From 95714d05d39d381b3ceaa4a7636d919d6edaacce Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Tue, 19 Dec 2023 19:49:35 -0800 Subject: [PATCH 001/486] Include optimizer and validator in publish script PiperOrigin-RevId: 592410792 --- publish/publish.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/publish/publish.sh b/publish/publish.sh index edb705f19..0814b16df 100755 --- a/publish/publish.sh +++ b/publish/publish.sh @@ -25,7 +25,7 @@ # 2. You will need to enter the key's password. The prompt appears in GUI, not in terminal. The publish operation will eventually timeout if the password is not entered. -ALL_TARGETS=("//publish:cel.publish" "//publish:cel_compiler.publish" "//publish:cel_runtime.publish" "//publish:cel_extensions.publish" "//publish:cel_v1alpha1.publish") +ALL_TARGETS=("//publish:cel.publish" "//publish:cel_compiler.publish" "//publish:cel_runtime.publish" "//publish:cel_extensions.publish" "//publish:cel_optimizers.publish" "//publish:cel_validators.publish" "//publish:cel_v1alpha1.publish") function publish_maven_remote() { maven_repo_url=$1 From 37799bc7836ffed9938c712d42c6593bbb0df1a5 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Thu, 21 Dec 2023 12:12:57 -0800 Subject: [PATCH 002/486] Fix constant folding to work with list provided as an identifier Fixes https://github.com/google/cel-java/issues/198 --- .gitignore | 4 ++-- .../cel/optimizer/optimizers/ConstantFoldingOptimizer.java | 7 ++++++- .../optimizer/optimizers/ConstantFoldingOptimizerTest.java | 6 ++++++ 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 633d0c6be..e8ebf31c4 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,7 @@ bazel-bin bazel-examples bazel-genfiles -bazel-grpc-java +bazel-cel-java bazel-out bazel-testlogs @@ -27,4 +27,4 @@ bin target # Temporary output dir for artifacts -mvn-artifacts \ No newline at end of file +mvn-artifacts diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java b/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java index 83114d144..460654bb6 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java @@ -299,7 +299,12 @@ private Optional maybePruneBranches( return Optional.of(replaceSubtree(ast, result, expr.id())); } else if (function.equals(Operator.IN.getFunction())) { - CelCreateList haystack = call.args().get(1).createList(); + CelExpr callArg = call.args().get(1); + if (!callArg.exprKind().getKind().equals(Kind.CREATE_LIST)) { + return Optional.empty(); + } + + CelCreateList haystack = callArg.createList(); if (haystack.elements().isEmpty()) { return Optional.of( replaceSubtree( diff --git a/optimizer/src/test/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizerTest.java b/optimizer/src/test/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizerTest.java index ed0415f39..f47481be1 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizerTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizerTest.java @@ -23,6 +23,8 @@ import dev.cel.bundle.CelFactory; import dev.cel.common.CelAbstractSyntaxTree; import dev.cel.common.CelOptions; +import dev.cel.common.types.ListType; +import dev.cel.common.types.MapType; import dev.cel.common.types.SimpleType; import dev.cel.extensions.CelOptionalLibrary; import dev.cel.optimizer.CelOptimizationException; @@ -41,6 +43,8 @@ public class ConstantFoldingOptimizerTest { CelFactory.standardCelBuilder() .addVar("x", SimpleType.DYN) .addVar("y", SimpleType.DYN) + .addVar("list_var", ListType.create(SimpleType.STRING)) + .addVar("map_var", MapType.create(SimpleType.STRING, SimpleType.STRING)) .addMessageTypes(TestAllTypes.getDescriptor()) .setContainer("dev.cel.testing.testdata.proto3") .addCompilerLibraries(CelOptionalLibrary.INSTANCE) @@ -152,6 +156,8 @@ public class ConstantFoldingOptimizerTest { @TestParameters("{source: 'x + dyn([1, 2] + [3, 4])', expected: 'x + [1, 2, 3, 4]'}") @TestParameters( "{source: '{\"a\": dyn([1, 2]), \"b\": x}', expected: '{\"a\": [1, 2], \"b\": x}'}") + @TestParameters("{source: 'map_var[?\"key\"]', expected: 'map_var[?\"key\"]'}") + @TestParameters("{source: '\"abc\" in list_var', expected: '\"abc\" in list_var'}") // TODO: Support folding lists with mixed types. This requires mutable lists. // @TestParameters("{source: 'dyn([1]) + [1.0]'}") public void constantFold_success(String source, String expected) throws Exception { From 7c4c5ee1a39a3c4c4e6542911ba535b8ca7c3a8e Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Thu, 4 Jan 2024 16:37:18 -0800 Subject: [PATCH 003/486] Allow MutableAst to insert a new bind macro PiperOrigin-RevId: 595833681 --- .../main/java/dev/cel/common/ast/BUILD.bazel | 1 + .../main/java/dev/cel/common/ast/CelExpr.java | 4 + .../dev/cel/common/ast/CelExprFactory.java | 23 +- .../dev/cel/common/ast/CelExprFormatter.java | 15 +- .../common/ast/CelExprIdGeneratorFactory.java | 47 ++- .../cel/common/ast/CelExprFactoryTest.java | 12 + .../cel/common/ast/CelExprFormatterTest.java | 7 + .../main/java/dev/cel/optimizer/BUILD.bazel | 1 + .../java/dev/cel/optimizer/MutableAst.java | 206 ++++++++++++-- .../test/java/dev/cel/optimizer/BUILD.bazel | 2 + .../dev/cel/optimizer/MutableAstTest.java | 268 +++++++++++++++++- 11 files changed, 547 insertions(+), 39 deletions(-) diff --git a/common/src/main/java/dev/cel/common/ast/BUILD.bazel b/common/src/main/java/dev/cel/common/ast/BUILD.bazel index c8663e6e3..ec79dbed2 100644 --- a/common/src/main/java/dev/cel/common/ast/BUILD.bazel +++ b/common/src/main/java/dev/cel/common/ast/BUILD.bazel @@ -88,6 +88,7 @@ java_library( ], deps = [ ":ast", + "//common/annotations", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", ], diff --git a/common/src/main/java/dev/cel/common/ast/CelExpr.java b/common/src/main/java/dev/cel/common/ast/CelExpr.java index b075de5f3..c106a1ff9 100644 --- a/common/src/main/java/dev/cel/common/ast/CelExpr.java +++ b/common/src/main/java/dev/cel/common/ast/CelExpr.java @@ -216,6 +216,7 @@ public CelComprehension comprehensionOrDefault() { /** Builder for CelExpr. */ @AutoValue.Builder public abstract static class Builder { + public abstract long id(); public abstract Builder setId(long value); @@ -787,6 +788,8 @@ public abstract static class Entry { @AutoValue.Builder public abstract static class Builder { + public abstract long id(); + public abstract CelExpr value(); public abstract Builder setId(long value); @@ -918,6 +921,7 @@ public abstract static class Entry { /** Builder for CelCreateMap.Entry. */ @AutoValue.Builder public abstract static class Builder { + public abstract long id(); public abstract CelExpr key(); diff --git a/common/src/main/java/dev/cel/common/ast/CelExprFactory.java b/common/src/main/java/dev/cel/common/ast/CelExprFactory.java index f73cb0564..385e72fee 100644 --- a/common/src/main/java/dev/cel/common/ast/CelExprFactory.java +++ b/common/src/main/java/dev/cel/common/ast/CelExprFactory.java @@ -19,16 +19,24 @@ import com.google.common.primitives.UnsignedLong; import com.google.protobuf.ByteString; +import dev.cel.common.annotations.Internal; import java.util.Arrays; /** Factory for generating expression nodes. */ +@Internal public class CelExprFactory { - private final CelExprIdGeneratorFactory.MonotonicIdGenerator idGenerator; + + private final CelExprIdGeneratorFactory.ExprIdGenerator idGenerator; public static CelExprFactory newInstance() { return new CelExprFactory(); } + public static CelExprFactory newInstance( + CelExprIdGeneratorFactory.ExprIdGenerator exprIdGenerator) { + return new CelExprFactory(exprIdGenerator); + } + /** Create a new constant expression. */ public final CelExpr newConstant(CelConstant constant) { return CelExpr.newBuilder().setId(nextExprId()).setConstant(constant).build(); @@ -543,10 +551,19 @@ public final CelExpr newSelect(CelExpr operand, String field, boolean testOnly) /** Returns the next unique expression ID. */ protected long nextExprId() { - return idGenerator.nextExprId(); + return idGenerator.generate( + /* exprId= */ -1); // Unconditionally generate next unique ID (i.e: no renumbering). } protected CelExprFactory() { - idGenerator = CelExprIdGeneratorFactory.newMonotonicIdGenerator(0); + this(CelExprIdGeneratorFactory.newMonotonicIdGenerator(0)); + } + + private CelExprFactory(CelExprIdGeneratorFactory.MonotonicIdGenerator idGenerator) { + this((unused) -> idGenerator.nextExprId()); + } + + private CelExprFactory(CelExprIdGeneratorFactory.ExprIdGenerator exprIdGenerator) { + idGenerator = exprIdGenerator; } } diff --git a/common/src/main/java/dev/cel/common/ast/CelExprFormatter.java b/common/src/main/java/dev/cel/common/ast/CelExprFormatter.java index 4c8add1fa..8ab71c094 100644 --- a/common/src/main/java/dev/cel/common/ast/CelExprFormatter.java +++ b/common/src/main/java/dev/cel/common/ast/CelExprFormatter.java @@ -14,11 +14,17 @@ package dev.cel.common.ast; +import com.google.common.collect.ImmutableSet; + /** Provides string formatting support for {@link CelExpr}. */ final class CelExprFormatter { private final StringBuilder indent = new StringBuilder(); private final StringBuilder exprBuilder = new StringBuilder(); + /** Denotes a set of expression kinds that will not have a new line inserted. */ + private static final ImmutableSet EXCLUDED_NEWLINE_KINDS = + ImmutableSet.of(CelExpr.ExprKind.Kind.CONSTANT, CelExpr.ExprKind.Kind.NOT_SET); + static String format(CelExpr celExpr) { CelExprFormatter formatter = new CelExprFormatter(); formatter.formatExpr(celExpr); @@ -28,7 +34,7 @@ static String format(CelExpr celExpr) { private void formatExpr(CelExpr celExpr) { append(String.format("%s [%d] {", celExpr.exprKind().getKind(), celExpr.id())); CelExpr.ExprKind.Kind exprKind = celExpr.exprKind().getKind(); - if (!exprKind.equals(CelExpr.ExprKind.Kind.CONSTANT)) { + if (!EXCLUDED_NEWLINE_KINDS.contains(exprKind)) { appendNewline(); } @@ -57,12 +63,17 @@ private void formatExpr(CelExpr celExpr) { case COMPREHENSION: appendComprehension(celExpr.comprehension()); break; + case NOT_SET: + break; default: + // This should be unreachable unless if we've added any other kinds. + indent(); append("Unknown kind: " + exprKind); + outdent(); break; } - if (!exprKind.equals(CelExpr.ExprKind.Kind.CONSTANT)) { + if (!EXCLUDED_NEWLINE_KINDS.contains(exprKind)) { appendNewline(); append("}"); } else { diff --git a/common/src/main/java/dev/cel/common/ast/CelExprIdGeneratorFactory.java b/common/src/main/java/dev/cel/common/ast/CelExprIdGeneratorFactory.java index c434150cd..10e259c07 100644 --- a/common/src/main/java/dev/cel/common/ast/CelExprIdGeneratorFactory.java +++ b/common/src/main/java/dev/cel/common/ast/CelExprIdGeneratorFactory.java @@ -59,8 +59,45 @@ public static class StableIdGenerator { private final HashMap idSet; private long exprId; + /** Checks if the given ID has been encountered before. */ + public boolean hasId(long id) { + return idSet.containsKey(id); + } + + /** + * Generate the next available ID while memoizing the existing ID. + * + *

The main purpose of this is to sanitize a new AST to replace an existing AST's node with. + * The incoming AST may not have its IDs consistently numbered (often, the expr IDs are just + * zeroes). In those cases, we just want to return an incremented expr ID. + * + *

The memoization becomes necessary if the incoming AST contains an expression with macro + * map populated, requiring a normalization pass. In this case, the method behaves largely the + * same as {@link #renumberId}. + * + * @param id Existing ID to memoize. Providing 0 or less will skip the memoization, in which + * case this behaves just like a {@link MonotonicIdGenerator}. + */ + public long nextExprId(long id) { + long nextExprId = ++exprId; + if (id > 0) { + idSet.put(id, nextExprId); + } + return nextExprId; + } + + /** Memoize a given expression ID with a newly generated ID. */ + public void memoize(long existingId, long newId) { + idSet.put(existingId, newId); + } + + /** + * Renumbers the existing expression ID to a newly generated unique ID. The existing ID is + * memoized, and calling this method again with the same ID will always return the same + * generated ID. + */ public long renumberId(long id) { - Preconditions.checkArgument(id >= 0); + Preconditions.checkArgument(id >= 0, "Expr ID must be positive. Got: %s", id); if (id == 0) { return 0; } @@ -81,5 +118,13 @@ private StableIdGenerator(long exprId) { } } + /** Functional interface for generating the next unique expression ID. */ + @FunctionalInterface + public interface ExprIdGenerator { + + /** Generates an expression ID with the provided expr ID as the context. */ + long generate(long exprId); + } + private CelExprIdGeneratorFactory() {} } diff --git a/common/src/test/java/dev/cel/common/ast/CelExprFactoryTest.java b/common/src/test/java/dev/cel/common/ast/CelExprFactoryTest.java index f3d77ea9e..30e8f5e41 100644 --- a/common/src/test/java/dev/cel/common/ast/CelExprFactoryTest.java +++ b/common/src/test/java/dev/cel/common/ast/CelExprFactoryTest.java @@ -16,6 +16,7 @@ import static com.google.common.truth.Truth.assertThat; +import dev.cel.common.ast.CelExprIdGeneratorFactory.StableIdGenerator; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -37,4 +38,15 @@ public void nextExprId_startingDefaultIsOne() { assertThat(exprFactory.nextExprId()).isEqualTo(1L); assertThat(exprFactory.nextExprId()).isEqualTo(2L); } + + @Test + public void nextExprId_usingStableIdGenerator() { + StableIdGenerator stableIdGenerator = CelExprIdGeneratorFactory.newStableIdGenerator(0); + CelExprFactory exprFactory = CelExprFactory.newInstance(stableIdGenerator::nextExprId); + + assertThat(exprFactory.nextExprId()).isEqualTo(1L); + assertThat(exprFactory.nextExprId()).isEqualTo(2L); + assertThat(stableIdGenerator.hasId(-1)).isFalse(); + assertThat(stableIdGenerator.hasId(0)).isFalse(); + } } diff --git a/common/src/test/java/dev/cel/common/ast/CelExprFormatterTest.java b/common/src/test/java/dev/cel/common/ast/CelExprFormatterTest.java index b80779bf7..2c863b1f4 100644 --- a/common/src/test/java/dev/cel/common/ast/CelExprFormatterTest.java +++ b/common/src/test/java/dev/cel/common/ast/CelExprFormatterTest.java @@ -61,6 +61,13 @@ public void constant(@TestParameter ConstantTestCase constantTestCase) throws Ex assertThat(formattedExpr).isEqualTo(constantTestCase.formatted); } + @Test + public void notSet() { + String formattedExpr = CelExprFormatter.format(CelExpr.ofNotSet(1)); + + assertThat(formattedExpr).isEqualTo("NOT_SET [1] {}"); + } + @Test public void select() throws Exception { CelCompiler celCompiler = diff --git a/optimizer/src/main/java/dev/cel/optimizer/BUILD.bazel b/optimizer/src/main/java/dev/cel/optimizer/BUILD.bazel index e145a2088..454ab828c 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/BUILD.bazel +++ b/optimizer/src/main/java/dev/cel/optimizer/BUILD.bazel @@ -81,6 +81,7 @@ java_library( tags = [ ], deps = [ + "//:auto_value", "//common", "//common/annotations", "//common/ast", diff --git a/optimizer/src/main/java/dev/cel/optimizer/MutableAst.java b/optimizer/src/main/java/dev/cel/optimizer/MutableAst.java index 64f5913d9..c8bf99c75 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/MutableAst.java +++ b/optimizer/src/main/java/dev/cel/optimizer/MutableAst.java @@ -16,7 +16,9 @@ import static com.google.common.collect.ImmutableList.toImmutableList; import static com.google.common.collect.ImmutableMap.toImmutableMap; +import static java.lang.Math.max; +import com.google.auto.value.AutoValue; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import dev.cel.common.CelAbstractSyntaxTree; @@ -29,8 +31,9 @@ import dev.cel.common.ast.CelExpr.CelCreateMap; import dev.cel.common.ast.CelExpr.CelCreateStruct; import dev.cel.common.ast.CelExpr.CelSelect; +import dev.cel.common.ast.CelExprFactory; import dev.cel.common.ast.CelExprIdGeneratorFactory; -import dev.cel.common.ast.CelExprIdGeneratorFactory.MonotonicIdGenerator; +import dev.cel.common.ast.CelExprIdGeneratorFactory.ExprIdGenerator; import dev.cel.common.ast.CelExprIdGeneratorFactory.StableIdGenerator; import dev.cel.common.navigation.CelNavigableExpr; import java.util.Map.Entry; @@ -51,34 +54,172 @@ private MutableAst(ExprIdGenerator celExprIdGenerator, CelExpr.Builder newExpr, this.exprIdToReplace = exprId; } + /** Replaces all the expression IDs in the expression tree with 0. */ + static CelExpr clearExprIds(CelExpr celExpr) { + return renumberExprIds((unused) -> 0, celExpr.toBuilder()).build(); + } + /** - * Replaces a subtree in the given CelExpr. + * Mutates the given AST by replacing a subtree at a given index. * - *

This method should remain package-private. + * @param ast Existing AST being mutated + * @param newExpr New subtree to perform the replacement with. + * @param exprIdToReplace The expr ID in the existing AST to replace the subtree at. */ static CelAbstractSyntaxTree replaceSubtree( CelAbstractSyntaxTree ast, CelExpr newExpr, long exprIdToReplace) { - // Update the IDs in the new expression tree first. This ensures that no ID collision - // occurs while attempting to replace the subtree, potentially leading to infinite loop - MonotonicIdGenerator monotonicIdGenerator = - CelExprIdGeneratorFactory.newMonotonicIdGenerator(getMaxId(ast.getExpr())); - CelExpr.Builder newExprBuilder = - renumberExprIds((unused) -> monotonicIdGenerator.nextExprId(), newExpr.toBuilder()); + return replaceSubtree( + ast, + CelAbstractSyntaxTree.newParsedAst(newExpr, CelSource.newBuilder().build()), + exprIdToReplace); + } + /** + * Mutates the given AST by replacing a subtree at a given index. + * + * @param ast Existing AST being mutated + * @param newAst New subtree to perform the replacement with. If the subtree has a macro map + * populated, its macro source is merged with the existing AST's after normalization. + * @param exprIdToReplace The expr ID in the existing AST to replace the subtree at. + */ + static CelAbstractSyntaxTree replaceSubtree( + CelAbstractSyntaxTree ast, CelAbstractSyntaxTree newAst, long exprIdToReplace) { + // Stabilize the incoming AST by renumbering all of its expression IDs. + long maxId = max(getMaxId(ast), getMaxId(newAst)); + newAst = stabilizeAst(newAst, maxId); + + // Mutate the AST root with the new subtree. All the existing expr IDs are renumbered in the + // process, but its original IDs are memoized so that we can normalize the expr IDs + // in the macro source map. StableIdGenerator stableIdGenerator = CelExprIdGeneratorFactory.newStableIdGenerator(0); CelExpr.Builder mutatedRoot = replaceSubtreeImpl( stableIdGenerator::renumberId, ast.getExpr().toBuilder(), - newExprBuilder, + newAst.getExpr().toBuilder(), exprIdToReplace); - // If the source info contained macro call information, their IDs must be normalized. - CelSource normalizedSource = + CelSource newAstSource = ast.getSource(); + if (!newAst.getSource().getMacroCalls().isEmpty()) { + // The root is mutated, but the expr IDs in the macro map needs to be normalized. + // In situations where an AST with a new macro map is being inserted (ex: new bind call), + // the new subtree's expr ID is not memoized in the stable ID generator because the ID never + // existed in the main AST. + // In this case, we forcibly memoize the new subtree ID with a newly generated ID so + // that the macro map IDs can be normalized properly. + stableIdGenerator.memoize( + newAst.getExpr().id(), stableIdGenerator.renumberId(exprIdToReplace)); + newAstSource = combine(newAstSource, newAst.getSource()); + } + + newAstSource = + normalizeMacroSource( + newAstSource, exprIdToReplace, mutatedRoot, stableIdGenerator::renumberId); + + return CelAbstractSyntaxTree.newParsedAst(mutatedRoot.build(), newAstSource); + } + + /** Replaces the subtree at the given ID with a newly created bind macro. */ + static CelAbstractSyntaxTree replaceSubtreeWithNewBindMacro( + CelAbstractSyntaxTree ast, + String varName, + CelExpr varInit, + CelExpr resultExpr, + long exprIdToReplace) { + long maxId = max(getMaxId(varInit), getMaxId(ast)); + StableIdGenerator stableIdGenerator = CelExprIdGeneratorFactory.newStableIdGenerator(maxId); + BindMacro bindMacro = newBindMacro(varName, varInit, resultExpr, stableIdGenerator); + // In situations where the existing AST already contains a macro call (ex: nested cel.binds), + // its macro source must be normalized to make it consistent with the newly generated bind + // macro. + CelSource celSource = normalizeMacroSource( - ast.getSource(), exprIdToReplace, mutatedRoot, stableIdGenerator::renumberId); + ast.getSource(), + -1, // Do not replace any of the subexpr in the macro map. + bindMacro.bindMacro().toBuilder(), + stableIdGenerator::renumberId); + celSource = + celSource.toBuilder() + .addMacroCalls(bindMacro.bindExpr().id(), bindMacro.bindMacro()) + .build(); + + return replaceSubtree( + ast, CelAbstractSyntaxTree.newParsedAst(bindMacro.bindExpr(), celSource), exprIdToReplace); + } + + private static BindMacro newBindMacro( + String varName, CelExpr varInit, CelExpr resultExpr, StableIdGenerator stableIdGenerator) { + // Clear incoming expression IDs in the initialization expression to avoid collision with the + // main AST. + varInit = clearExprIds(varInit); + CelExprFactory exprFactory = + CelExprFactory.newInstance((unused) -> stableIdGenerator.nextExprId(-1)); + CelExpr bindMacroExpr = + exprFactory.fold( + "#unused", + exprFactory.newList(), + varName, + varInit, + exprFactory.newBoolLiteral(false), + exprFactory.newIdentifier(varName), + resultExpr); - return CelAbstractSyntaxTree.newParsedAst(mutatedRoot.build(), normalizedSource); + // Update the IDs in the new expression tree first. This ensures that no ID collision + // occurs while attempting to replace the subtree later, potentially leading to an infinite loop + bindMacroExpr = + renumberExprIds(stableIdGenerator::nextExprId, bindMacroExpr.toBuilder()).build(); + + CelExpr bindMacroCallExpr = + exprFactory + .newReceiverCall( + "bind", + CelExpr.ofIdentExpr(stableIdGenerator.nextExprId(-1), "cel"), + CelExpr.ofIdentExpr(stableIdGenerator.nextExprId(-1), varName), + bindMacroExpr.comprehension().accuInit(), + bindMacroExpr.comprehension().result()) + .toBuilder() + .setId(0) + .build(); + + return BindMacro.of(bindMacroExpr, bindMacroCallExpr); + } + + private static CelSource combine(CelSource celSource1, CelSource celSource2) { + ImmutableMap.Builder macroMap = ImmutableMap.builder(); + macroMap.putAll(celSource1.getMacroCalls()); + macroMap.putAll(celSource2.getMacroCalls()); + + return CelSource.newBuilder().addAllMacroCalls(macroMap.buildOrThrow()).build(); + } + + /** + * Stabilizes the incoming AST by ensuring that all of expr IDs are consistently renumbered + * (monotonically increased) from the starting seed ID. If the AST contains any macro calls, its + * IDs are also normalized. + */ + private static CelAbstractSyntaxTree stabilizeAst(CelAbstractSyntaxTree ast, long seedExprId) { + StableIdGenerator stableIdGenerator = + CelExprIdGeneratorFactory.newStableIdGenerator(seedExprId); + CelExpr.Builder newExprBuilder = + renumberExprIds(stableIdGenerator::nextExprId, ast.getExpr().toBuilder()); + + if (ast.getSource().getMacroCalls().isEmpty()) { + return CelAbstractSyntaxTree.newParsedAst(newExprBuilder.build(), ast.getSource()); + } + + CelSource.Builder sourceBuilder = CelSource.newBuilder(); + // Update the macro call IDs and their call IDs + for (Entry macroCall : ast.getSource().getMacroCalls().entrySet()) { + long macroId = macroCall.getKey(); + long newCallId = stableIdGenerator.renumberId(macroId); + + CelExpr.Builder newCall = + renumberExprIds(stableIdGenerator::renumberId, macroCall.getValue().toBuilder()); + + sourceBuilder.addMacroCalls(newCallId, newCall.build()); + } + + return CelAbstractSyntaxTree.newParsedAst(newExprBuilder.build(), sourceBuilder.build()); } private static CelSource normalizeMacroSource( @@ -116,6 +257,10 @@ private static CelSource normalizeMacroSource( long macroId = macroCall.getKey(); long callId = idGenerator.generate(macroId); + if (!allExprs.containsKey(callId)) { + continue; + } + CelExpr.Builder newCall = renumberExprIds(idGenerator, macroCall.getValue().toBuilder()); CelNavigableExpr callNav = CelNavigableExpr.fromExpr(newCall.build()); ImmutableList callDescendants = @@ -152,6 +297,15 @@ private static CelExpr.Builder renumberExprIds( return mutableAst.visit(root); } + private static long getMaxId(CelAbstractSyntaxTree ast) { + long maxId = getMaxId(ast.getExpr()); + for (Entry macroCall : ast.getSource().getMacroCalls().entrySet()) { + maxId = max(maxId, getMaxId(macroCall.getValue())); + } + + return maxId; + } + private static long getMaxId(CelExpr newExpr) { return CelNavigableExpr.fromExpr(newExpr) .allNodes() @@ -216,6 +370,7 @@ private CelExpr.Builder visit(CelExpr.Builder expr, CelCreateStruct.Builder crea ImmutableList entries = createStruct.getEntriesBuilders(); for (int i = 0; i < entries.size(); i++) { CelCreateStruct.Entry.Builder entry = entries.get(i); + entry.setId(celExprIdGenerator.generate(entry.id())); entry.setValue(visit(entry.value().toBuilder()).build()); createStruct.setEntry(i, entry.build()); @@ -228,6 +383,7 @@ private CelExpr.Builder visit(CelExpr.Builder expr, CelCreateMap.Builder createM ImmutableList entriesBuilders = createMap.getEntriesBuilders(); for (int i = 0; i < entriesBuilders.size(); i++) { CelCreateMap.Entry.Builder entry = entriesBuilders.get(i); + entry.setId(celExprIdGenerator.generate(entry.id())); entry.setKey(visit(entry.key().toBuilder()).build()); entry.setValue(visit(entry.value().toBuilder()).build()); @@ -257,10 +413,24 @@ private CelExpr.Builder visit(CelExpr.Builder expr, CelComprehension.Builder com return expr.setComprehension(comprehension.build()); } - @FunctionalInterface - private interface ExprIdGenerator { + /** + * Intermediate value class to store the generated CelExpr for the bind macro and the macro call + * information. + */ + @AutoValue + abstract static class BindMacro { + + /** Comprehension expr for the generated cel.bind macro. */ + abstract CelExpr bindExpr(); - /** Generates an expression ID based on the provided ID. */ - long generate(long exprId); + /** + * Call expr representation that will be stored in the macro call map of the AST. This is + * typically used for the purposes of supporting unparse. + */ + abstract CelExpr bindMacro(); + + private static BindMacro of(CelExpr bindExpr, CelExpr bindMacro) { + return new AutoValue_MutableAst_BindMacro(bindExpr, bindMacro); + } } } diff --git a/optimizer/src/test/java/dev/cel/optimizer/BUILD.bazel b/optimizer/src/test/java/dev/cel/optimizer/BUILD.bazel index a769bc20d..f40903138 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/BUILD.bazel +++ b/optimizer/src/test/java/dev/cel/optimizer/BUILD.bazel @@ -17,6 +17,7 @@ java_library( "//common/resources/testdata/proto3:test_all_types_java_proto", "//common/types", "//compiler", + "//extensions", "//extensions:optional_library", "//optimizer", "//optimizer:mutable_ast", @@ -25,6 +26,7 @@ java_library( "//optimizer:optimizer_impl", "//parser", "//parser:macro", + "//parser:operator", "//parser:unparser", "//runtime", "@maven//:com_google_guava_guava", diff --git a/optimizer/src/test/java/dev/cel/optimizer/MutableAstTest.java b/optimizer/src/test/java/dev/cel/optimizer/MutableAstTest.java index 65d94b70e..b7f1d29d0 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/MutableAstTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/MutableAstTest.java @@ -19,6 +19,7 @@ import com.google.common.collect.ImmutableMap; import com.google.testing.junit.testparameterinjector.TestParameterInjector; +import com.google.testing.junit.testparameterinjector.TestParameters; import dev.cel.bundle.Cel; import dev.cel.bundle.CelFactory; import dev.cel.common.CelAbstractSyntaxTree; @@ -27,16 +28,20 @@ import dev.cel.common.CelOverloadDecl; import dev.cel.common.ast.CelConstant; import dev.cel.common.ast.CelExpr; +import dev.cel.common.ast.CelExpr.CelCall; import dev.cel.common.ast.CelExpr.CelIdent; import dev.cel.common.ast.CelExpr.CelSelect; +import dev.cel.common.ast.CelExpr.ExprKind.Kind; import dev.cel.common.navigation.CelNavigableAst; import dev.cel.common.navigation.CelNavigableExpr; import dev.cel.common.types.SimpleType; import dev.cel.common.types.StructTypeReference; +import dev.cel.extensions.CelExtensions; import dev.cel.extensions.CelOptionalLibrary; import dev.cel.parser.CelStandardMacro; import dev.cel.parser.CelUnparser; import dev.cel.parser.CelUnparserFactory; +import dev.cel.parser.Operator; import dev.cel.testing.testdata.proto3.TestAllTypesProto.TestAllTypes; import org.junit.Test; import org.junit.runner.RunWith; @@ -48,7 +53,7 @@ public class MutableAstTest { .setStandardMacros(CelStandardMacro.STANDARD_MACROS) .setOptions(CelOptions.current().populateMacroCalls(true).build()) .addMessageTypes(TestAllTypes.getDescriptor()) - .addCompilerLibraries(CelOptionalLibrary.INSTANCE) + .addCompilerLibraries(CelOptionalLibrary.INSTANCE, CelExtensions.bindings()) .addRuntimeLibraries(CelOptionalLibrary.INSTANCE) .setContainer("dev.cel.testing.testdata.proto3") .addVar("msg", StructTypeReference.create(TestAllTypes.getDescriptor().getFullName())) @@ -109,6 +114,248 @@ public void mutableAst_macro_sourceMacroCallsPopulated() throws Exception { assertThat(mutatedAst.getSource().getMacroCalls()).isNotEmpty(); } + @Test + @TestParameters("{source: '[1].exists(x, x > 0)', expectedMacroCallSize: 1}") + @TestParameters( + "{source: '[1].exists(x, x > 0) && [2].exists(x, x > 0)', expectedMacroCallSize: 2}") + @TestParameters( + "{source: '[1].exists(x, [2].exists(y, x > 0 && y > x))', expectedMacroCallSize: 2}") + public void replaceSubtree_rootReplacedWithMacro_macroCallPopulated( + String source, int expectedMacroCallSize) throws Exception { + CelAbstractSyntaxTree ast = CEL.compile("1").getAst(); + CelAbstractSyntaxTree ast2 = CEL.compile(source).getAst(); + + CelAbstractSyntaxTree mutatedAst = + MutableAst.replaceSubtree(ast, ast2, CelNavigableAst.fromAst(ast).getRoot().expr().id()); + + assertThat(mutatedAst.getSource().getMacroCalls()).hasSize(expectedMacroCallSize); + assertThat(CEL_UNPARSER.unparse(mutatedAst)).isEqualTo(source); + assertThat(CEL.createProgram(CEL.check(mutatedAst).getAst()).eval()).isEqualTo(true); + } + + @Test + public void replaceSubtree_branchReplacedWithMacro_macroCallPopulated() throws Exception { + CelAbstractSyntaxTree ast = CEL.compile("true && false").getAst(); + CelAbstractSyntaxTree ast2 = CEL.compile("[1].exists(x, x > 0)").getAst(); + + CelAbstractSyntaxTree mutatedAst = + MutableAst.replaceSubtree(ast, ast2, 3); // Replace false with the macro expr + CelAbstractSyntaxTree mutatedAst2 = + MutableAst.replaceSubtree(ast, ast2, 1); // Replace true with the macro expr + + assertThat(mutatedAst.getSource().getMacroCalls()).hasSize(1); + assertThat(CEL_UNPARSER.unparse(mutatedAst)).isEqualTo("true && [1].exists(x, x > 0)"); + assertThat(CEL.createProgram(CEL.check(mutatedAst).getAst()).eval()).isEqualTo(true); + assertThat(mutatedAst2.getSource().getMacroCalls()).hasSize(1); + assertThat(CEL_UNPARSER.unparse(mutatedAst2)).isEqualTo("[1].exists(x, x > 0) && false"); + assertThat(CEL.createProgram(CEL.check(mutatedAst2).getAst()).eval()).isEqualTo(false); + } + + @Test + public void replaceSubtree_macroInsertedIntoExistingMacro_macroCallPopulated() throws Exception { + CelAbstractSyntaxTree ast = CEL.compile("[1].exists(x, x > 0 && true)").getAst(); + CelAbstractSyntaxTree ast2 = CEL.compile("[2].exists(y, y > 0)").getAst(); + + CelAbstractSyntaxTree mutatedAst = + MutableAst.replaceSubtree(ast, ast2, 9); // Replace true with the ast2 maro expr + + assertThat(mutatedAst.getSource().getMacroCalls()).hasSize(2); + assertThat(CEL_UNPARSER.unparse(mutatedAst)) + .isEqualTo("[1].exists(x, x > 0 && [2].exists(y, y > 0))"); + assertThat(CEL.createProgram(CEL.check(mutatedAst).getAst()).eval()).isEqualTo(true); + } + + @Test + public void replaceSubtreeWithNewBindMacro_replaceRoot() throws Exception { + CelAbstractSyntaxTree ast = CEL.compile("1 + 1").getAst(); + String variableName = "@r0"; + CelExpr resultExpr = + CelExpr.newBuilder() + .setCall( + CelCall.newBuilder() + .setFunction(Operator.ADD.getFunction()) + .addArgs( + CelExpr.ofIdentExpr(0, variableName), CelExpr.ofIdentExpr(0, variableName)) + .build()) + .build(); + + CelAbstractSyntaxTree mutatedAst = + MutableAst.replaceSubtreeWithNewBindMacro( + ast, + variableName, + CelExpr.ofConstantExpr(0, CelConstant.ofValue(3L)), + resultExpr, + CelNavigableAst.fromAst(ast).getRoot().expr().id()); + + assertThat(mutatedAst.getSource().getMacroCalls()).hasSize(1); + assertThat(CEL_UNPARSER.unparse(mutatedAst)).isEqualTo("cel.bind(@r0, 3, @r0 + @r0)"); + assertThat(CEL.createProgram(CEL.check(mutatedAst).getAst()).eval()).isEqualTo(6); + assertConsistentMacroCalls(mutatedAst); + } + + @Test + public void replaceSubtreeWithNewBindMacro_nestedBindMacro_replaceComprehensionResult() + throws Exception { + // Arrange + CelAbstractSyntaxTree ast = CEL.compile("1 + 1").getAst(); + String variableName = "@r0"; + CelExpr resultExpr = + CelExpr.newBuilder() + .setCall( + CelCall.newBuilder() + .setFunction(Operator.ADD.getFunction()) + .addArgs( + CelExpr.ofIdentExpr(0, variableName), CelExpr.ofIdentExpr(0, variableName)) + .build()) + .build(); + + // Act + // Perform the initial replacement. (1 + 1) -> cel.bind(@r0, 3, @r0 + @r0) + CelAbstractSyntaxTree mutatedAst = + MutableAst.replaceSubtreeWithNewBindMacro( + ast, + variableName, + CelExpr.ofConstantExpr(0, CelConstant.ofValue(3L)), + resultExpr, + 2); // Replace + + String nestedVariableName = "@r1"; + // Construct a new result expression of the form @r0 + @r0 + @r1 + @r1 + resultExpr = + CelExpr.newBuilder() + .setCall( + CelCall.newBuilder() + .setFunction(Operator.ADD.getFunction()) + .addArgs( + CelExpr.newBuilder() + .setCall( + CelCall.newBuilder() + .setFunction(Operator.ADD.getFunction()) + .addArgs( + CelExpr.newBuilder() + .setCall( + CelCall.newBuilder() + .setFunction(Operator.ADD.getFunction()) + .addArgs( + CelExpr.ofIdentExpr(0, variableName), + CelExpr.ofIdentExpr(0, variableName)) + .build()) + .build(), + CelExpr.ofIdentExpr(0, nestedVariableName)) + .build()) + .build(), + CelExpr.ofIdentExpr(0, nestedVariableName)) + .build()) + .build(); + // Find the call node (_+_) in the comprehension's result + long exprIdToReplace = + CelNavigableAst.fromAst(mutatedAst) + .getRoot() + .children() + .filter( + node -> + node.getKind().equals(Kind.CALL) + && node.parent().get().getKind().equals(Kind.COMPREHENSION)) + .findAny() + .get() + .expr() + .id(); + // This should produce cel.bind(@r1, 1, cel.bind(@r0, 3, @r0 + @r0 + @r1 + @r1)) + mutatedAst = + MutableAst.replaceSubtreeWithNewBindMacro( + mutatedAst, + nestedVariableName, + CelExpr.ofConstantExpr(0, CelConstant.ofValue(1L)), + resultExpr, + exprIdToReplace); // Replace + + + assertThat(mutatedAst.getSource().getMacroCalls()).hasSize(2); + assertThat(CEL.createProgram(CEL.check(mutatedAst).getAst()).eval()).isEqualTo(8); + assertThat(CEL_UNPARSER.unparse(mutatedAst)) + .isEqualTo("cel.bind(@r0, 3, cel.bind(@r1, 1, @r0 + @r0 + @r1 + @r1))"); + assertConsistentMacroCalls(mutatedAst); + } + + @Test + public void replaceSubtreeWithNewBindMacro_replaceRootWithNestedBindMacro() throws Exception { + // Arrange + CelAbstractSyntaxTree ast = CEL.compile("1 + 1 + 3 + 3").getAst(); + String variableName = "@r0"; + CelExpr resultExpr = + CelExpr.newBuilder() + .setCall( + CelCall.newBuilder() + .setFunction(Operator.ADD.getFunction()) + .addArgs( + CelExpr.ofIdentExpr(0, variableName), CelExpr.ofIdentExpr(0, variableName)) + .build()) + .build(); + + // Act + // Perform the initial replacement. (1 + 1 + 3 + 3) -> cel.bind(@r0, 1, @r0 + @r0) + 3 + 3 + CelAbstractSyntaxTree mutatedAst = + MutableAst.replaceSubtreeWithNewBindMacro( + ast, + variableName, + CelExpr.ofConstantExpr(0, CelConstant.ofValue(1L)), + resultExpr, + 2); // Replace + + // Construct a new result expression of the form: + // cel.bind(@r1, 3, cel.bind(@r0, 1, @r0 + @r0) + @r1 + @r1) + String nestedVariableName = "@r1"; + CelExpr bindMacro = + CelNavigableAst.fromAst(mutatedAst) + .getRoot() + .descendants() + .filter(node -> node.getKind().equals(Kind.COMPREHENSION)) + .findAny() + .get() + .expr(); + resultExpr = + CelExpr.newBuilder() + .setCall( + CelCall.newBuilder() + .setFunction(Operator.ADD.getFunction()) + .addArgs( + CelExpr.newBuilder() + .setCall( + CelCall.newBuilder() + .setFunction(Operator.ADD.getFunction()) + .addArgs(bindMacro, CelExpr.ofIdentExpr(0, nestedVariableName)) + .build()) + .build(), + CelExpr.ofIdentExpr(0, nestedVariableName)) + .build()) + .build(); + // Replace the root with the new result and a bind macro inserted + mutatedAst = + MutableAst.replaceSubtreeWithNewBindMacro( + mutatedAst, + nestedVariableName, + CelExpr.ofConstantExpr(0, CelConstant.ofValue(3L)), + resultExpr, + 1); + + assertThat(mutatedAst.getSource().getMacroCalls()).hasSize(2); + assertThat(CEL.createProgram(CEL.check(mutatedAst).getAst()).eval()).isEqualTo(8); + assertThat(CEL_UNPARSER.unparse(mutatedAst)) + .isEqualTo("cel.bind(@r1, 3, cel.bind(@r0, 1, @r0 + @r0) + @r1 + @r1)"); + assertConsistentMacroCalls(mutatedAst); + } + + @Test + public void replaceSubtree_macroReplacedWithConstExpr_macroCallCleared() throws Exception { + CelAbstractSyntaxTree ast = + CEL.compile("[1].exists(x, x > 0) && [2].exists(x, x > 0)").getAst(); + CelAbstractSyntaxTree ast2 = CEL.compile("1").getAst(); + + CelAbstractSyntaxTree mutatedAst = + MutableAst.replaceSubtree(ast, ast2, CelNavigableAst.fromAst(ast).getRoot().expr().id()); + + assertThat(mutatedAst.getSource().getMacroCalls()).isEmpty(); + assertThat(CEL_UNPARSER.unparse(mutatedAst)).isEqualTo("1"); + assertThat(CEL.createProgram(CEL.check(mutatedAst).getAst()).eval()).isEqualTo(1); + } + @Test public void globalCallExpr_replaceRoot() throws Exception { // Tree shape (brackets are expr IDs): @@ -371,8 +618,8 @@ public void comprehension_replaceIterRange() throws Exception { ast, CelExpr.newBuilder().setConstant(CelConstant.ofValue(false)).build(), 2); assertThat(CEL_UNPARSER.unparse(replacedAst)).isEqualTo("[false].exists(i, i)"); - assertConsistentMacroCalls(ast); assertThat(CEL.createProgram(CEL.check(replacedAst).getAst()).eval()).isEqualTo(false); + assertConsistentMacroCalls(ast); } @Test @@ -384,8 +631,11 @@ public void comprehension_replaceAccuInit() throws Exception { ast, CelExpr.newBuilder().setConstant(CelConstant.ofValue(true)).build(), 6); assertThat(CEL_UNPARSER.unparse(replacedAst)).isEqualTo("[false].exists(i, i)"); - assertConsistentMacroCalls(ast); assertThat(CEL.createProgram(CEL.check(replacedAst).getAst()).eval()).isEqualTo(true); + // Check that the init value of accumulator has actually been replaced. + assertThat(ast.getExpr().comprehension().accuInit().constant().booleanValue()).isFalse(); + assertThat(replacedAst.getExpr().comprehension().accuInit().constant().booleanValue()).isTrue(); + assertConsistentMacroCalls(ast); } @Test @@ -402,18 +652,6 @@ public void comprehension_replaceLoopStep() throws Exception { assertConsistentMacroCalls(ast); } - @Test - public void comprehension_astContainsDuplicateNodes() throws Exception { - CelAbstractSyntaxTree ast = CEL.compile("[{\"a\": 1}].map(i, i)").getAst(); - - // AST contains two duplicate expr (ID: 9). Just ensure that it doesn't throw. - CelAbstractSyntaxTree replacedAst = - MutableAst.replaceSubtree(ast, CelExpr.newBuilder().build(), -1); - - assertThat(CEL_UNPARSER.unparse(replacedAst)).isEqualTo("[{\"a\": 1}].map(i, i)"); - assertConsistentMacroCalls(ast); - } - /** * Asserts that the expressions that appears in source_info's macro calls are consistent with the * actual expr nodes in the AST. From 870c59444540cb67d4b047b4695d80f59ac5caef Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Wed, 10 Jan 2024 14:00:23 -0800 Subject: [PATCH 004/486] Fix standard function 'type' to accept a parameter type of TypeParamType instead of Dyn PiperOrigin-RevId: 597349307 --- .../main/java/dev/cel/checker/Standard.java | 2 +- .../java/dev/cel/checker/ExprCheckerTest.java | 2 ++ .../abstractTypeParameterLess.baseline | 3 +- .../abstractTypeParameterized.baseline | 3 +- .../test/resources/standardEnvDump.baseline | 2 +- checker/src/test/resources/types.baseline | 31 +++++++++++++++++-- 6 files changed, 35 insertions(+), 8 deletions(-) diff --git a/checker/src/main/java/dev/cel/checker/Standard.java b/checker/src/main/java/dev/cel/checker/Standard.java index 02bfefdf8..4dcbcb1da 100644 --- a/checker/src/main/java/dev/cel/checker/Standard.java +++ b/checker/src/main/java/dev/cel/checker/Standard.java @@ -320,7 +320,7 @@ private static ImmutableList coreFunctionDeclarations() { CelFunctionDecl.newFunctionDeclaration( "type", CelOverloadDecl.newGlobalOverload( - "type", "returns type of value", TypeType.create(SimpleType.DYN), typeParamA))); + "type", "returns type of value", TypeType.create(typeParamA), typeParamA))); // Conversions to int celFunctionDeclBuilder.add( diff --git a/checker/src/test/java/dev/cel/checker/ExprCheckerTest.java b/checker/src/test/java/dev/cel/checker/ExprCheckerTest.java index 461eb3574..9217942c1 100644 --- a/checker/src/test/java/dev/cel/checker/ExprCheckerTest.java +++ b/checker/src/test/java/dev/cel/checker/ExprCheckerTest.java @@ -652,6 +652,8 @@ public void unexpectedAggregateMapError() throws Exception { public void types() throws Exception { source = "list == type([1]) && map == type({1:2u})"; runTest(); + source = "{}.map(c,[c,type(c)])"; + runTest(); } // Enum Values diff --git a/checker/src/test/resources/abstractTypeParameterLess.baseline b/checker/src/test/resources/abstractTypeParameterLess.baseline index 8f1e0ea0a..10cfae312 100644 --- a/checker/src/test/resources/abstractTypeParameterLess.baseline +++ b/checker/src/test/resources/abstractTypeParameterLess.baseline @@ -13,9 +13,8 @@ _&&_( _==_( type( make_abs()~abs^make_abs - )~type(dyn)^type, + )~type(abs)^type, abs~type(abs)^abs )~bool^equals, make_abs()~abs^make_abs.as_bool()~bool^as_bool )~bool^logical_and - diff --git a/checker/src/test/resources/abstractTypeParameterized.baseline b/checker/src/test/resources/abstractTypeParameterized.baseline index c1e65941b..948f61ec9 100644 --- a/checker/src/test/resources/abstractTypeParameterized.baseline +++ b/checker/src/test/resources/abstractTypeParameterized.baseline @@ -15,7 +15,7 @@ _&&_( 1~int ]~list(int) )~vector(int)^vector - )~type(dyn)^type, + )~type(vector(int))^type, vector( dyn~type(dyn)^dyn )~type(vector(dyn))^vector @@ -31,4 +31,3 @@ _&&_( 1~int )~bool^equals )~bool^logical_and - diff --git a/checker/src/test/resources/standardEnvDump.baseline b/checker/src/test/resources/standardEnvDump.baseline index 028a9188c..4ef2fa9cf 100644 --- a/checker/src/test/resources/standardEnvDump.baseline +++ b/checker/src/test/resources/standardEnvDump.baseline @@ -261,7 +261,7 @@ declare timestamp { } declare type { value type(dyn) - function type (A) -> type(dyn) + function type (A) -> type(A) } declare uint { value type(uint) diff --git a/checker/src/test/resources/types.baseline b/checker/src/test/resources/types.baseline index b58cd143c..61f3f4423 100644 --- a/checker/src/test/resources/types.baseline +++ b/checker/src/test/resources/types.baseline @@ -7,7 +7,7 @@ _&&_( [ 1~int ]~list(int) - )~type(dyn)^type + )~type(list(int))^type )~bool^equals, _==_( map~type(map(dyn, dyn))^map, @@ -15,7 +15,34 @@ _&&_( { 1~int:2u~uint }~map(int, uint) - )~type(dyn)^type + )~type(map(int, uint))^type )~bool^equals )~bool^logical_and +Source: {}.map(c,[c,type(c)]) +=====> +__comprehension__( + // Variable + c, + // Target + {}~map(dyn, dyn), + // Accumulator + __result__, + // Init + []~list(list(dyn)), + // LoopCondition + true~bool, + // LoopStep + _+_( + __result__~list(list(dyn))^__result__, + [ + [ + c~dyn^c, + type( + c~dyn^c + )~type(dyn)^type + ]~list(dyn) + ]~list(list(dyn)) + )~list(list(dyn))^add_list, + // Result + __result__~list(list(dyn))^__result__)~list(list(dyn)) From 8ff0918a36ca738772054f5059ea6f09ca0eea6a Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Wed, 10 Jan 2024 15:03:43 -0800 Subject: [PATCH 005/486] Add an enum for Standard functions that are non-operators PiperOrigin-RevId: 597366073 --- .../main/java/dev/cel/checker/Standard.java | 92 ++++++++++++++----- 1 file changed, 67 insertions(+), 25 deletions(-) diff --git a/checker/src/main/java/dev/cel/checker/Standard.java b/checker/src/main/java/dev/cel/checker/Standard.java index 4dcbcb1da..f595dde9a 100644 --- a/checker/src/main/java/dev/cel/checker/Standard.java +++ b/checker/src/main/java/dev/cel/checker/Standard.java @@ -42,6 +42,48 @@ public final class Standard { private static final ImmutableList CORE_IDENT_DECLARATIONS = coreIdentDeclarations(); + /** Enumeration of Standard Functions that are not present in {@link Operator}). */ + public enum Function { + BOOL("bool"), + BYTES("bytes"), + CONTAINS("contains"), + DOUBLE("double"), + DURATION("duration"), + DYN("dyn"), + ENDS_WITH("endsWith"), + GET_DATE("getDate"), + GET_DAY_OF_MONTH("getDayOfMonth"), + GET_DAY_OF_WEEK("getDayOfWeek"), + GET_DAY_OF_YEAR("getDayOfYear"), + GET_FULL_YEAR("getFullYear"), + GET_HOURS("getHours"), + GET_MILLISECONDS("getMilliseconds"), + GET_MINUTES("getMinutes"), + GET_MONTH("getMonth"), + GET_SECONDS("getSeconds"), + INT("int"), + LIST("list"), + MAP("map"), + MATCHES("matches"), + NULL_TYPE("null_type"), + SIZE("size"), + STARTS_WITH("startsWith"), + STRING("string"), + TIMESTAMP("timestamp"), + TYPE("type"), + UINT("uint"); + + private final String functionName; + + public String getFunction() { + return functionName; + } + + Function(String functionName) { + this.functionName = functionName; + } + } + /** * Adds the standard declarations of CEL to the environment. * @@ -318,14 +360,14 @@ private static ImmutableList coreFunctionDeclarations() { // Conversions to type celFunctionDeclBuilder.add( CelFunctionDecl.newFunctionDeclaration( - "type", + Function.TYPE.getFunction(), CelOverloadDecl.newGlobalOverload( "type", "returns type of value", TypeType.create(typeParamA), typeParamA))); // Conversions to int celFunctionDeclBuilder.add( CelFunctionDecl.newFunctionDeclaration( - "int", + Function.INT.getFunction(), CelOverloadDecl.newGlobalOverload( "uint64_to_int64", "type conversion", SimpleType.INT, SimpleType.UINT), CelOverloadDecl.newGlobalOverload( @@ -341,7 +383,7 @@ private static ImmutableList coreFunctionDeclarations() { // Conversions to uint celFunctionDeclBuilder.add( CelFunctionDecl.newFunctionDeclaration( - "uint", + Function.UINT.getFunction(), CelOverloadDecl.newGlobalOverload( "int64_to_uint64", "type conversion", SimpleType.UINT, SimpleType.INT), CelOverloadDecl.newGlobalOverload( @@ -352,7 +394,7 @@ private static ImmutableList coreFunctionDeclarations() { // Conversions to double celFunctionDeclBuilder.add( CelFunctionDecl.newFunctionDeclaration( - "double", + Function.DOUBLE.getFunction(), CelOverloadDecl.newGlobalOverload( "int64_to_double", "type conversion", SimpleType.DOUBLE, SimpleType.INT), CelOverloadDecl.newGlobalOverload( @@ -363,7 +405,7 @@ private static ImmutableList coreFunctionDeclarations() { // Conversions to string celFunctionDeclBuilder.add( CelFunctionDecl.newFunctionDeclaration( - "string", + Function.STRING.getFunction(), CelOverloadDecl.newGlobalOverload( "int64_to_string", "type conversion", SimpleType.STRING, SimpleType.INT), CelOverloadDecl.newGlobalOverload( @@ -380,14 +422,14 @@ private static ImmutableList coreFunctionDeclarations() { // Conversions to list celFunctionDeclBuilder.add( CelFunctionDecl.newFunctionDeclaration( - "list", + Function.LIST.getFunction(), CelOverloadDecl.newGlobalOverload( "to_list", "type conversion", listOfA, TypeType.create(typeParamA), listOfA))); // Conversions to map celFunctionDeclBuilder.add( CelFunctionDecl.newFunctionDeclaration( - "map", + Function.MAP.getFunction(), CelOverloadDecl.newGlobalOverload( "to_map", "type conversion", @@ -399,21 +441,21 @@ private static ImmutableList coreFunctionDeclarations() { // Conversions to bytes celFunctionDeclBuilder.add( CelFunctionDecl.newFunctionDeclaration( - "bytes", + Function.BYTES.getFunction(), CelOverloadDecl.newGlobalOverload( "string_to_bytes", "type conversion", SimpleType.BYTES, SimpleType.STRING))); // Conversions to dyn celFunctionDeclBuilder.add( CelFunctionDecl.newFunctionDeclaration( - "dyn", + Function.DYN.getFunction(), CelOverloadDecl.newGlobalOverload( "to_dyn", "type conversion", SimpleType.DYN, typeParamA))); // Conversions to Duration celFunctionDeclBuilder.add( CelFunctionDecl.newFunctionDeclaration( - "duration", + Function.DURATION.getFunction(), CelOverloadDecl.newGlobalOverload( "string_to_duration", "type conversion, duration should be end with \"s\", which stands for seconds", @@ -423,7 +465,7 @@ private static ImmutableList coreFunctionDeclarations() { // String functions celFunctionDeclBuilder.add( CelFunctionDecl.newFunctionDeclaration( - "matches", + Function.MATCHES.getFunction(), CelOverloadDecl.newGlobalOverload( "matches", "matches first argument against regular expression in second argument", @@ -432,7 +474,7 @@ private static ImmutableList coreFunctionDeclarations() { SimpleType.STRING))); celFunctionDeclBuilder.add( CelFunctionDecl.newFunctionDeclaration( - "matches", + Function.MATCHES.getFunction(), CelOverloadDecl.newMemberOverload( "matches_string", "matches the self argument against regular expression in first argument", @@ -442,7 +484,7 @@ private static ImmutableList coreFunctionDeclarations() { celFunctionDeclBuilder.add( CelFunctionDecl.newFunctionDeclaration( - "contains", + Function.CONTAINS.getFunction(), CelOverloadDecl.newMemberOverload( "contains_string", "tests whether the string operand contains the substring", @@ -451,7 +493,7 @@ private static ImmutableList coreFunctionDeclarations() { SimpleType.STRING))); celFunctionDeclBuilder.add( CelFunctionDecl.newFunctionDeclaration( - "endsWith", + Function.ENDS_WITH.getFunction(), CelOverloadDecl.newMemberOverload( "ends_with_string", "tests whether the string operand ends with the suffix argument", @@ -460,7 +502,7 @@ private static ImmutableList coreFunctionDeclarations() { SimpleType.STRING))); celFunctionDeclBuilder.add( CelFunctionDecl.newFunctionDeclaration( - "startsWith", + Function.STARTS_WITH.getFunction(), CelOverloadDecl.newMemberOverload( "starts_with_string", "tests whether the string operand starts with the prefix argument", @@ -471,7 +513,7 @@ private static ImmutableList coreFunctionDeclarations() { // Date/time functions celFunctionDeclBuilder.add( CelFunctionDecl.newFunctionDeclaration( - "getFullYear", + Function.GET_FULL_YEAR.getFunction(), CelOverloadDecl.newMemberOverload( "timestamp_to_year", "get year from the date in UTC", @@ -486,7 +528,7 @@ private static ImmutableList coreFunctionDeclarations() { celFunctionDeclBuilder.add( CelFunctionDecl.newFunctionDeclaration( - "getMonth", + Function.GET_MONTH.getFunction(), CelOverloadDecl.newMemberOverload( "timestamp_to_month", "get month from the date in UTC, 0-11", @@ -501,7 +543,7 @@ private static ImmutableList coreFunctionDeclarations() { celFunctionDeclBuilder.add( CelFunctionDecl.newFunctionDeclaration( - "getDayOfYear", + Function.GET_DAY_OF_YEAR.getFunction(), CelOverloadDecl.newMemberOverload( "timestamp_to_day_of_year", "get day of year from the date in UTC, zero-based indexing", @@ -516,7 +558,7 @@ private static ImmutableList coreFunctionDeclarations() { celFunctionDeclBuilder.add( CelFunctionDecl.newFunctionDeclaration( - "getDayOfMonth", + Function.GET_DAY_OF_MONTH.getFunction(), CelOverloadDecl.newMemberOverload( "timestamp_to_day_of_month", "get day of month from the date in UTC, zero-based indexing", @@ -530,7 +572,7 @@ private static ImmutableList coreFunctionDeclarations() { SimpleType.STRING))); celFunctionDeclBuilder.add( CelFunctionDecl.newFunctionDeclaration( - "getDate", + Function.GET_DATE.getFunction(), CelOverloadDecl.newMemberOverload( "timestamp_to_day_of_month_1_based", "get day of month from the date in UTC, one-based indexing", @@ -545,7 +587,7 @@ private static ImmutableList coreFunctionDeclarations() { celFunctionDeclBuilder.add( CelFunctionDecl.newFunctionDeclaration( - "getDayOfWeek", + Function.GET_DAY_OF_WEEK.getFunction(), CelOverloadDecl.newMemberOverload( "timestamp_to_day_of_week", "get day of week from the date in UTC, zero-based, zero for Sunday", @@ -560,7 +602,7 @@ private static ImmutableList coreFunctionDeclarations() { celFunctionDeclBuilder.add( CelFunctionDecl.newFunctionDeclaration( - "getHours", + Function.GET_HOURS.getFunction(), CelOverloadDecl.newMemberOverload( "timestamp_to_hours", "get hours from the date in UTC, 0-23", @@ -580,7 +622,7 @@ private static ImmutableList coreFunctionDeclarations() { celFunctionDeclBuilder.add( CelFunctionDecl.newFunctionDeclaration( - "getMinutes", + Function.GET_MINUTES.getFunction(), CelOverloadDecl.newMemberOverload( "timestamp_to_minutes", "get minutes from the date in UTC, 0-59", @@ -600,7 +642,7 @@ private static ImmutableList coreFunctionDeclarations() { celFunctionDeclBuilder.add( CelFunctionDecl.newFunctionDeclaration( - "getSeconds", + Function.GET_SECONDS.getFunction(), CelOverloadDecl.newMemberOverload( "timestamp_to_seconds", "get seconds from the date in UTC, 0-59", @@ -620,7 +662,7 @@ private static ImmutableList coreFunctionDeclarations() { celFunctionDeclBuilder.add( CelFunctionDecl.newFunctionDeclaration( - "getMilliseconds", + Function.GET_MILLISECONDS.getFunction(), CelOverloadDecl.newMemberOverload( "timestamp_to_milliseconds", "get milliseconds from the date in UTC, 0-999", From 562ec94c4faf6d2b82d3ecb8c5896993713390f1 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Tue, 16 Jan 2024 11:27:15 -0800 Subject: [PATCH 006/486] Move standard macro definitions from CelMacro to CelStandardMacro PiperOrigin-RevId: 598901986 --- .../extensions/CelBindingsExtensionsTest.java | 4 +- .../main/java/dev/cel/parser/CelMacro.java | 239 ------------------ .../java/dev/cel/parser/CelStandardMacro.java | 213 +++++++++++++++- .../java/dev/cel/parser/CelMacroTest.java | 98 ------- .../dev/cel/parser/CelParserImplTest.java | 62 +++-- .../dev/cel/parser/CelStandardMacroTest.java | 106 ++++++++ .../dev/cel/parser/CelUnparserImplTest.java | 6 +- 7 files changed, 352 insertions(+), 376 deletions(-) diff --git a/extensions/src/test/java/dev/cel/extensions/CelBindingsExtensionsTest.java b/extensions/src/test/java/dev/cel/extensions/CelBindingsExtensionsTest.java index 43e64bb8b..2b836dcc5 100644 --- a/extensions/src/test/java/dev/cel/extensions/CelBindingsExtensionsTest.java +++ b/extensions/src/test/java/dev/cel/extensions/CelBindingsExtensionsTest.java @@ -26,7 +26,7 @@ import dev.cel.common.types.SimpleType; import dev.cel.compiler.CelCompiler; import dev.cel.compiler.CelCompilerFactory; -import dev.cel.parser.CelMacro; +import dev.cel.parser.CelStandardMacro; import dev.cel.runtime.CelRuntime; import dev.cel.runtime.CelRuntime.CelFunctionBinding; import dev.cel.runtime.CelRuntimeFactory; @@ -39,7 +39,7 @@ public final class CelBindingsExtensionsTest { private static final CelCompiler COMPILER = CelCompilerFactory.standardCelCompilerBuilder() - .addMacros(CelMacro.STANDARD_MACROS) + .setStandardMacros(CelStandardMacro.STANDARD_MACROS) .addLibraries(CelExtensions.bindings()) .build(); diff --git a/parser/src/main/java/dev/cel/parser/CelMacro.java b/parser/src/main/java/dev/cel/parser/CelMacro.java index 06e48d8be..cf75714a0 100644 --- a/parser/src/main/java/dev/cel/parser/CelMacro.java +++ b/parser/src/main/java/dev/cel/parser/CelMacro.java @@ -19,70 +19,13 @@ import static com.google.common.base.Strings.isNullOrEmpty; import com.google.auto.value.AutoValue; -import com.google.common.collect.ImmutableList; import com.google.errorprone.annotations.CheckReturnValue; import com.google.errorprone.annotations.Immutable; -import dev.cel.common.CelIssue; -import dev.cel.common.ast.CelExpr; -import java.util.Optional; /** Describes a function signature to match and the {@link CelMacroExpander} to apply. */ @AutoValue @Immutable public abstract class CelMacro implements Comparable { - - private static final String ACCUMULATOR_VAR = "__result__"; - - /** Field presence test macro */ - public static final CelMacro HAS = - newGlobalMacro(Operator.HAS.getFunction(), 1, CelMacro::expandHasMacro); - - /** - * Boolean comprehension which asserts that a predicate holds true for all elements in the input - * range. - */ - public static final CelMacro ALL = - newReceiverMacro(Operator.ALL.getFunction(), 2, CelMacro::expandAllMacro); - - /** - * Boolean comprehension which asserts that a predicate holds true for at least one element in the - * input range. - */ - public static final CelMacro EXISTS = - newReceiverMacro(Operator.EXISTS.getFunction(), 2, CelMacro::expandExistsMacro); - - /** - * Boolean comprehension which asserts that a predicate holds true for exactly one element in the - * input range. - */ - public static final CelMacro EXISTS_ONE = - newReceiverMacro(Operator.EXISTS_ONE.getFunction(), 2, CelMacro::expandExistsOneMacro); - - /** - * Comprehension which applies a transform to each element in the input range and produces a list - * of equivalent size as output. - */ - public static final CelMacro MAP = - newReceiverMacro(Operator.MAP.getFunction(), 2, CelMacro::expandMapMacro); - - /** - * Comprehension which conditionally applies a transform to elements in the list which satisfy the - * filter predicate. - */ - public static final CelMacro MAP_FILTER = - newReceiverMacro(Operator.MAP.getFunction(), 3, CelMacro::expandMapMacro); - - /** - * Comprehension which produces a list containing elements in the input range which match the - * filter. - */ - public static final CelMacro FILTER = - newReceiverMacro(Operator.FILTER.getFunction(), 2, CelMacro::expandFilterMacro); - - /** Set of all standard macros supported by the CEL spec. */ - public static final ImmutableList STANDARD_MACROS = - ImmutableList.of(HAS, ALL, EXISTS, EXISTS_ONE, MAP, MAP_FILTER, FILTER); - // Package-private default constructor to prevent extensions outside of the codebase. CelMacro() {} @@ -241,186 +184,4 @@ abstract static class Builder { @CheckReturnValue abstract CelMacro build(); } - - // CelMacroExpander implementation for CEL's has() macro. - private static Optional expandHasMacro( - CelMacroExprFactory exprFactory, CelExpr target, ImmutableList arguments) { - checkNotNull(exprFactory); - checkNotNull(target); - checkArgument(arguments.size() == 1); - CelExpr arg = checkNotNull(arguments.get(0)); - if (arg.exprKind().getKind() != CelExpr.ExprKind.Kind.SELECT) { - return Optional.of(exprFactory.reportError("invalid argument to has() macro")); - } - return Optional.of(exprFactory.newSelect(arg.select().operand(), arg.select().field(), true)); - } - - // CelMacroExpander implementation for CEL's all() macro. - private static Optional expandAllMacro( - CelMacroExprFactory exprFactory, CelExpr target, ImmutableList arguments) { - checkNotNull(exprFactory); - checkNotNull(target); - checkArgument(arguments.size() == 2); - CelExpr arg0 = checkNotNull(arguments.get(0)); - if (arg0.exprKind().getKind() != CelExpr.ExprKind.Kind.IDENT) { - return Optional.of(reportArgumentError(exprFactory, arg0)); - } - CelExpr arg1 = checkNotNull(arguments.get(1)); - CelExpr accuInit = exprFactory.newBoolLiteral(true); - CelExpr condition = - exprFactory.newGlobalCall( - Operator.NOT_STRICTLY_FALSE.getFunction(), exprFactory.newIdentifier(ACCUMULATOR_VAR)); - CelExpr step = - exprFactory.newGlobalCall( - Operator.LOGICAL_AND.getFunction(), exprFactory.newIdentifier(ACCUMULATOR_VAR), arg1); - CelExpr result = exprFactory.newIdentifier(ACCUMULATOR_VAR); - return Optional.of( - exprFactory.fold( - arg0.ident().name(), target, ACCUMULATOR_VAR, accuInit, condition, step, result)); - } - - // CelMacroExpander implementation for CEL's exists() macro. - private static Optional expandExistsMacro( - CelMacroExprFactory exprFactory, CelExpr target, ImmutableList arguments) { - checkNotNull(exprFactory); - checkNotNull(target); - checkArgument(arguments.size() == 2); - CelExpr arg0 = checkNotNull(arguments.get(0)); - if (arg0.exprKind().getKind() != CelExpr.ExprKind.Kind.IDENT) { - return Optional.of(reportArgumentError(exprFactory, arg0)); - } - CelExpr arg1 = checkNotNull(arguments.get(1)); - CelExpr accuInit = exprFactory.newBoolLiteral(false); - CelExpr condition = - exprFactory.newGlobalCall( - Operator.NOT_STRICTLY_FALSE.getFunction(), - exprFactory.newGlobalCall( - Operator.LOGICAL_NOT.getFunction(), exprFactory.newIdentifier(ACCUMULATOR_VAR))); - CelExpr step = - exprFactory.newGlobalCall( - Operator.LOGICAL_OR.getFunction(), exprFactory.newIdentifier(ACCUMULATOR_VAR), arg1); - CelExpr result = exprFactory.newIdentifier(ACCUMULATOR_VAR); - return Optional.of( - exprFactory.fold( - arg0.ident().name(), target, ACCUMULATOR_VAR, accuInit, condition, step, result)); - } - - // CelMacroExpander implementation for CEL's exists_one() macro. - private static Optional expandExistsOneMacro( - CelMacroExprFactory exprFactory, CelExpr target, ImmutableList arguments) { - checkNotNull(exprFactory); - checkNotNull(target); - checkArgument(arguments.size() == 2); - CelExpr arg0 = checkNotNull(arguments.get(0)); - if (arg0.exprKind().getKind() != CelExpr.ExprKind.Kind.IDENT) { - return Optional.of(reportArgumentError(exprFactory, arg0)); - } - CelExpr arg1 = checkNotNull(arguments.get(1)); - CelExpr zeroExpr = exprFactory.newIntLiteral(0); - CelExpr oneExpr = exprFactory.newIntLiteral(1); - CelExpr accuInit = zeroExpr; - CelExpr condition = exprFactory.newBoolLiteral(true); - CelExpr step = - exprFactory.newGlobalCall( - Operator.CONDITIONAL.getFunction(), - arg1, - exprFactory.newGlobalCall( - Operator.ADD.getFunction(), exprFactory.newIdentifier(ACCUMULATOR_VAR), oneExpr), - exprFactory.newIdentifier(ACCUMULATOR_VAR)); - CelExpr result = - exprFactory.newGlobalCall( - Operator.EQUALS.getFunction(), exprFactory.newIdentifier(ACCUMULATOR_VAR), oneExpr); - return Optional.of( - exprFactory.fold( - arg0.ident().name(), target, ACCUMULATOR_VAR, accuInit, condition, step, result)); - } - - // CelMacroExpander implementation for CEL's map() macro. - private static Optional expandMapMacro( - CelMacroExprFactory exprFactory, CelExpr target, ImmutableList arguments) { - checkNotNull(exprFactory); - checkNotNull(target); - checkArgument(arguments.size() == 2 || arguments.size() == 3); - CelExpr arg0 = checkNotNull(arguments.get(0)); - if (arg0.exprKind().getKind() != CelExpr.ExprKind.Kind.IDENT) { - return Optional.of( - exprFactory.reportError( - CelIssue.formatError( - exprFactory.getSourceLocation(arg0), "argument is not an identifier"))); - } - CelExpr arg1; - CelExpr arg2; - if (arguments.size() == 3) { - arg2 = checkNotNull(arguments.get(1)); - arg1 = checkNotNull(arguments.get(2)); - } else { - arg1 = checkNotNull(arguments.get(1)); - arg2 = null; - } - CelExpr accuInit = exprFactory.newList(); - CelExpr condition = exprFactory.newBoolLiteral(true); - CelExpr step = - exprFactory.newGlobalCall( - Operator.ADD.getFunction(), - exprFactory.newIdentifier(ACCUMULATOR_VAR), - exprFactory.newList(arg1)); - if (arg2 != null) { - step = - exprFactory.newGlobalCall( - Operator.CONDITIONAL.getFunction(), - arg2, - step, - exprFactory.newIdentifier(ACCUMULATOR_VAR)); - } - return Optional.of( - exprFactory.fold( - arg0.ident().name(), - target, - ACCUMULATOR_VAR, - accuInit, - condition, - step, - exprFactory.newIdentifier(ACCUMULATOR_VAR))); - } - - // CelMacroExpander implementation for CEL's filter() macro. - private static Optional expandFilterMacro( - CelMacroExprFactory exprFactory, CelExpr target, ImmutableList arguments) { - checkNotNull(exprFactory); - checkNotNull(target); - checkArgument(arguments.size() == 2); - CelExpr arg0 = checkNotNull(arguments.get(0)); - if (arg0.exprKind().getKind() != CelExpr.ExprKind.Kind.IDENT) { - return Optional.of(reportArgumentError(exprFactory, arg0)); - } - CelExpr arg1 = checkNotNull(arguments.get(1)); - CelExpr accuInit = exprFactory.newList(); - CelExpr condition = exprFactory.newBoolLiteral(true); - CelExpr step = - exprFactory.newGlobalCall( - Operator.ADD.getFunction(), - exprFactory.newIdentifier(ACCUMULATOR_VAR), - exprFactory.newList(arg0)); - step = - exprFactory.newGlobalCall( - Operator.CONDITIONAL.getFunction(), - arg1, - step, - exprFactory.newIdentifier(ACCUMULATOR_VAR)); - return Optional.of( - exprFactory.fold( - arg0.ident().name(), - target, - ACCUMULATOR_VAR, - accuInit, - condition, - step, - exprFactory.newIdentifier(ACCUMULATOR_VAR))); - } - - private static CelExpr reportArgumentError(CelMacroExprFactory exprFactory, CelExpr argument) { - return exprFactory.reportError( - CelIssue.formatError( - exprFactory.getSourceLocation(argument), "The argument must be a simple name")); - } } diff --git a/parser/src/main/java/dev/cel/parser/CelStandardMacro.java b/parser/src/main/java/dev/cel/parser/CelStandardMacro.java index a4aa50fff..3d93e8531 100644 --- a/parser/src/main/java/dev/cel/parser/CelStandardMacro.java +++ b/parser/src/main/java/dev/cel/parser/CelStandardMacro.java @@ -14,55 +14,72 @@ package dev.cel.parser; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; +import dev.cel.common.CelIssue; +import dev.cel.common.ast.CelExpr; +import java.util.Optional; /** * CelStandardMacro enum represents all of the macros defined as part of the CEL standard library. */ public enum CelStandardMacro { + /** Field presence test macro */ - HAS(CelMacro.HAS), + HAS(CelMacro.newGlobalMacro(Operator.HAS.getFunction(), 1, CelStandardMacro::expandHasMacro)), /** * Boolean comprehension which asserts that a predicate holds true for all elements in the input * range. */ - ALL(CelMacro.ALL), + ALL(CelMacro.newReceiverMacro(Operator.ALL.getFunction(), 2, CelStandardMacro::expandAllMacro)), /** * Boolean comprehension which asserts that a predicate holds true for at least one element in the * input range. */ - EXISTS(CelMacro.EXISTS), + EXISTS( + CelMacro.newReceiverMacro( + Operator.EXISTS.getFunction(), 2, CelStandardMacro::expandExistsMacro)), /** * Boolean comprehension which asserts that a predicate holds true for exactly one element in the * input range. */ - EXISTS_ONE(CelMacro.EXISTS_ONE), + EXISTS_ONE( + CelMacro.newReceiverMacro( + Operator.EXISTS_ONE.getFunction(), 2, CelStandardMacro::expandExistsOneMacro)), /** * Comprehension which applies a transform to each element in the input range and produces a list * of equivalent size as output. */ - MAP(CelMacro.MAP), + MAP(CelMacro.newReceiverMacro(Operator.MAP.getFunction(), 2, CelStandardMacro::expandMapMacro)), /** * Comprehension which conditionally applies a transform to elements in the list which satisfy the * filter predicate. */ - MAP_FILTER(CelMacro.MAP_FILTER), + MAP_FILTER( + CelMacro.newReceiverMacro(Operator.MAP.getFunction(), 3, CelStandardMacro::expandMapMacro)), /** * Comprehension which produces a list containing elements in the input range which match the * filter. */ - FILTER(CelMacro.FILTER); + FILTER( + CelMacro.newReceiverMacro( + Operator.FILTER.getFunction(), 2, CelStandardMacro::expandFilterMacro)); /** Set of all standard macros supported by the CEL spec. */ public static final ImmutableSet STANDARD_MACROS = ImmutableSet.of(HAS, ALL, EXISTS, EXISTS_ONE, MAP, MAP_FILTER, FILTER); + private static final String ACCUMULATOR_VAR = "__result__"; + private final CelMacro macro; CelStandardMacro(CelMacro macro) { @@ -78,4 +95,186 @@ public String getFunction() { public CelMacro getDefinition() { return macro; } + + // CelMacroExpander implementation for CEL's has() macro. + private static Optional expandHasMacro( + CelMacroExprFactory exprFactory, CelExpr target, ImmutableList arguments) { + checkNotNull(exprFactory); + checkNotNull(target); + checkArgument(arguments.size() == 1); + CelExpr arg = checkNotNull(arguments.get(0)); + if (arg.exprKind().getKind() != CelExpr.ExprKind.Kind.SELECT) { + return Optional.of(exprFactory.reportError("invalid argument to has() macro")); + } + return Optional.of(exprFactory.newSelect(arg.select().operand(), arg.select().field(), true)); + } + + // CelMacroExpander implementation for CEL's all() macro. + private static Optional expandAllMacro( + CelMacroExprFactory exprFactory, CelExpr target, ImmutableList arguments) { + checkNotNull(exprFactory); + checkNotNull(target); + checkArgument(arguments.size() == 2); + CelExpr arg0 = checkNotNull(arguments.get(0)); + if (arg0.exprKind().getKind() != CelExpr.ExprKind.Kind.IDENT) { + return Optional.of(reportArgumentError(exprFactory, arg0)); + } + CelExpr arg1 = checkNotNull(arguments.get(1)); + CelExpr accuInit = exprFactory.newBoolLiteral(true); + CelExpr condition = + exprFactory.newGlobalCall( + Operator.NOT_STRICTLY_FALSE.getFunction(), exprFactory.newIdentifier(ACCUMULATOR_VAR)); + CelExpr step = + exprFactory.newGlobalCall( + Operator.LOGICAL_AND.getFunction(), exprFactory.newIdentifier(ACCUMULATOR_VAR), arg1); + CelExpr result = exprFactory.newIdentifier(ACCUMULATOR_VAR); + return Optional.of( + exprFactory.fold( + arg0.ident().name(), target, ACCUMULATOR_VAR, accuInit, condition, step, result)); + } + + // CelMacroExpander implementation for CEL's exists() macro. + private static Optional expandExistsMacro( + CelMacroExprFactory exprFactory, CelExpr target, ImmutableList arguments) { + checkNotNull(exprFactory); + checkNotNull(target); + checkArgument(arguments.size() == 2); + CelExpr arg0 = checkNotNull(arguments.get(0)); + if (arg0.exprKind().getKind() != CelExpr.ExprKind.Kind.IDENT) { + return Optional.of(reportArgumentError(exprFactory, arg0)); + } + CelExpr arg1 = checkNotNull(arguments.get(1)); + CelExpr accuInit = exprFactory.newBoolLiteral(false); + CelExpr condition = + exprFactory.newGlobalCall( + Operator.NOT_STRICTLY_FALSE.getFunction(), + exprFactory.newGlobalCall( + Operator.LOGICAL_NOT.getFunction(), exprFactory.newIdentifier(ACCUMULATOR_VAR))); + CelExpr step = + exprFactory.newGlobalCall( + Operator.LOGICAL_OR.getFunction(), exprFactory.newIdentifier(ACCUMULATOR_VAR), arg1); + CelExpr result = exprFactory.newIdentifier(ACCUMULATOR_VAR); + return Optional.of( + exprFactory.fold( + arg0.ident().name(), target, ACCUMULATOR_VAR, accuInit, condition, step, result)); + } + + // CelMacroExpander implementation for CEL's exists_one() macro. + private static Optional expandExistsOneMacro( + CelMacroExprFactory exprFactory, CelExpr target, ImmutableList arguments) { + checkNotNull(exprFactory); + checkNotNull(target); + checkArgument(arguments.size() == 2); + CelExpr arg0 = checkNotNull(arguments.get(0)); + if (arg0.exprKind().getKind() != CelExpr.ExprKind.Kind.IDENT) { + return Optional.of(reportArgumentError(exprFactory, arg0)); + } + CelExpr arg1 = checkNotNull(arguments.get(1)); + CelExpr zeroExpr = exprFactory.newIntLiteral(0); + CelExpr oneExpr = exprFactory.newIntLiteral(1); + CelExpr accuInit = zeroExpr; + CelExpr condition = exprFactory.newBoolLiteral(true); + CelExpr step = + exprFactory.newGlobalCall( + Operator.CONDITIONAL.getFunction(), + arg1, + exprFactory.newGlobalCall( + Operator.ADD.getFunction(), exprFactory.newIdentifier(ACCUMULATOR_VAR), oneExpr), + exprFactory.newIdentifier(ACCUMULATOR_VAR)); + CelExpr result = + exprFactory.newGlobalCall( + Operator.EQUALS.getFunction(), exprFactory.newIdentifier(ACCUMULATOR_VAR), oneExpr); + return Optional.of( + exprFactory.fold( + arg0.ident().name(), target, ACCUMULATOR_VAR, accuInit, condition, step, result)); + } + + // CelMacroExpander implementation for CEL's map() macro. + private static Optional expandMapMacro( + CelMacroExprFactory exprFactory, CelExpr target, ImmutableList arguments) { + checkNotNull(exprFactory); + checkNotNull(target); + checkArgument(arguments.size() == 2 || arguments.size() == 3); + CelExpr arg0 = checkNotNull(arguments.get(0)); + if (arg0.exprKind().getKind() != CelExpr.ExprKind.Kind.IDENT) { + return Optional.of( + exprFactory.reportError( + CelIssue.formatError( + exprFactory.getSourceLocation(arg0), "argument is not an identifier"))); + } + CelExpr arg1; + CelExpr arg2; + if (arguments.size() == 3) { + arg2 = checkNotNull(arguments.get(1)); + arg1 = checkNotNull(arguments.get(2)); + } else { + arg1 = checkNotNull(arguments.get(1)); + arg2 = null; + } + CelExpr accuInit = exprFactory.newList(); + CelExpr condition = exprFactory.newBoolLiteral(true); + CelExpr step = + exprFactory.newGlobalCall( + Operator.ADD.getFunction(), + exprFactory.newIdentifier(ACCUMULATOR_VAR), + exprFactory.newList(arg1)); + if (arg2 != null) { + step = + exprFactory.newGlobalCall( + Operator.CONDITIONAL.getFunction(), + arg2, + step, + exprFactory.newIdentifier(ACCUMULATOR_VAR)); + } + return Optional.of( + exprFactory.fold( + arg0.ident().name(), + target, + ACCUMULATOR_VAR, + accuInit, + condition, + step, + exprFactory.newIdentifier(ACCUMULATOR_VAR))); + } + + // CelMacroExpander implementation for CEL's filter() macro. + private static Optional expandFilterMacro( + CelMacroExprFactory exprFactory, CelExpr target, ImmutableList arguments) { + checkNotNull(exprFactory); + checkNotNull(target); + checkArgument(arguments.size() == 2); + CelExpr arg0 = checkNotNull(arguments.get(0)); + if (arg0.exprKind().getKind() != CelExpr.ExprKind.Kind.IDENT) { + return Optional.of(reportArgumentError(exprFactory, arg0)); + } + CelExpr arg1 = checkNotNull(arguments.get(1)); + CelExpr accuInit = exprFactory.newList(); + CelExpr condition = exprFactory.newBoolLiteral(true); + CelExpr step = + exprFactory.newGlobalCall( + Operator.ADD.getFunction(), + exprFactory.newIdentifier(ACCUMULATOR_VAR), + exprFactory.newList(arg0)); + step = + exprFactory.newGlobalCall( + Operator.CONDITIONAL.getFunction(), + arg1, + step, + exprFactory.newIdentifier(ACCUMULATOR_VAR)); + return Optional.of( + exprFactory.fold( + arg0.ident().name(), + target, + ACCUMULATOR_VAR, + accuInit, + condition, + step, + exprFactory.newIdentifier(ACCUMULATOR_VAR))); + } + + private static CelExpr reportArgumentError(CelMacroExprFactory exprFactory, CelExpr argument) { + return exprFactory.reportError( + CelIssue.formatError( + exprFactory.getSourceLocation(argument), "The argument must be a simple name")); + } } diff --git a/parser/src/test/java/dev/cel/parser/CelMacroTest.java b/parser/src/test/java/dev/cel/parser/CelMacroTest.java index 301d26449..585b01578 100644 --- a/parser/src/test/java/dev/cel/parser/CelMacroTest.java +++ b/parser/src/test/java/dev/cel/parser/CelMacroTest.java @@ -16,7 +16,6 @@ import static com.google.common.truth.Truth.assertThat; -import com.google.common.testing.EqualsTester; import dev.cel.common.ast.CelExpr; import java.util.Optional; import org.junit.Test; @@ -26,103 +25,6 @@ @RunWith(JUnit4.class) public final class CelMacroTest { - @Test - public void testHas() { - assertThat(CelMacro.HAS.getFunction()).isEqualTo(Operator.HAS.getFunction()); - assertThat(CelMacro.HAS.getArgumentCount()).isEqualTo(1); - assertThat(CelMacro.HAS.isReceiverStyle()).isFalse(); - assertThat(CelMacro.HAS.getKey()).isEqualTo("has:1:false"); - assertThat(CelMacro.HAS.isVariadic()).isFalse(); - assertThat(CelMacro.HAS.toString()).isEqualTo(CelMacro.HAS.getKey()); - assertThat(CelMacro.HAS.hashCode()).isEqualTo(CelMacro.HAS.getKey().hashCode()); - assertThat(CelMacro.HAS).isEquivalentAccordingToCompareTo(CelMacro.HAS); - } - - @Test - public void testAll() { - assertThat(CelMacro.ALL.getFunction()).isEqualTo(Operator.ALL.getFunction()); - assertThat(CelMacro.ALL.getArgumentCount()).isEqualTo(2); - assertThat(CelMacro.ALL.isReceiverStyle()).isTrue(); - assertThat(CelMacro.ALL.getKey()).isEqualTo("all:2:true"); - assertThat(CelMacro.ALL.isVariadic()).isFalse(); - assertThat(CelMacro.ALL.toString()).isEqualTo(CelMacro.ALL.getKey()); - assertThat(CelMacro.ALL.hashCode()).isEqualTo(CelMacro.ALL.getKey().hashCode()); - assertThat(CelMacro.ALL).isEquivalentAccordingToCompareTo(CelMacro.ALL); - } - - @Test - public void testExists() { - assertThat(CelMacro.EXISTS.getFunction()).isEqualTo(Operator.EXISTS.getFunction()); - assertThat(CelMacro.EXISTS.getArgumentCount()).isEqualTo(2); - assertThat(CelMacro.EXISTS.isReceiverStyle()).isTrue(); - assertThat(CelMacro.EXISTS.getKey()).isEqualTo("exists:2:true"); - assertThat(CelMacro.EXISTS.isVariadic()).isFalse(); - assertThat(CelMacro.EXISTS.toString()).isEqualTo(CelMacro.EXISTS.getKey()); - assertThat(CelMacro.EXISTS.hashCode()).isEqualTo(CelMacro.EXISTS.getKey().hashCode()); - assertThat(CelMacro.EXISTS).isEquivalentAccordingToCompareTo(CelMacro.EXISTS); - } - - @Test - public void testExistsOne() { - assertThat(CelMacro.EXISTS_ONE.getFunction()).isEqualTo(Operator.EXISTS_ONE.getFunction()); - assertThat(CelMacro.EXISTS_ONE.getArgumentCount()).isEqualTo(2); - assertThat(CelMacro.EXISTS_ONE.isReceiverStyle()).isTrue(); - assertThat(CelMacro.EXISTS_ONE.getKey()).isEqualTo("exists_one:2:true"); - assertThat(CelMacro.EXISTS_ONE.isVariadic()).isFalse(); - assertThat(CelMacro.EXISTS_ONE.toString()).isEqualTo(CelMacro.EXISTS_ONE.getKey()); - assertThat(CelMacro.EXISTS_ONE.hashCode()).isEqualTo(CelMacro.EXISTS_ONE.getKey().hashCode()); - assertThat(CelMacro.EXISTS_ONE).isEquivalentAccordingToCompareTo(CelMacro.EXISTS_ONE); - } - - @Test - public void testMap2() { - assertThat(CelMacro.MAP.getFunction()).isEqualTo(Operator.MAP.getFunction()); - assertThat(CelMacro.MAP.getArgumentCount()).isEqualTo(2); - assertThat(CelMacro.MAP.isReceiverStyle()).isTrue(); - assertThat(CelMacro.MAP.getKey()).isEqualTo("map:2:true"); - assertThat(CelMacro.MAP.isVariadic()).isFalse(); - assertThat(CelMacro.MAP.toString()).isEqualTo(CelMacro.MAP.getKey()); - assertThat(CelMacro.MAP.hashCode()).isEqualTo(CelMacro.MAP.getKey().hashCode()); - assertThat(CelMacro.MAP).isEquivalentAccordingToCompareTo(CelMacro.MAP); - } - - @Test - public void testMap3() { - assertThat(CelMacro.MAP_FILTER.getFunction()).isEqualTo(Operator.MAP.getFunction()); - assertThat(CelMacro.MAP_FILTER.getArgumentCount()).isEqualTo(3); - assertThat(CelMacro.MAP_FILTER.isReceiverStyle()).isTrue(); - assertThat(CelMacro.MAP_FILTER.getKey()).isEqualTo("map:3:true"); - assertThat(CelMacro.MAP_FILTER.isVariadic()).isFalse(); - assertThat(CelMacro.MAP_FILTER.toString()).isEqualTo(CelMacro.MAP_FILTER.getKey()); - assertThat(CelMacro.MAP_FILTER.hashCode()).isEqualTo(CelMacro.MAP_FILTER.getKey().hashCode()); - assertThat(CelMacro.MAP_FILTER).isEquivalentAccordingToCompareTo(CelMacro.MAP_FILTER); - } - - @Test - public void testFilter() { - assertThat(CelMacro.FILTER.getFunction()).isEqualTo(Operator.FILTER.getFunction()); - assertThat(CelMacro.FILTER.getArgumentCount()).isEqualTo(2); - assertThat(CelMacro.FILTER.isReceiverStyle()).isTrue(); - assertThat(CelMacro.FILTER.getKey()).isEqualTo("filter:2:true"); - assertThat(CelMacro.FILTER.isVariadic()).isFalse(); - assertThat(CelMacro.FILTER.toString()).isEqualTo(CelMacro.FILTER.getKey()); - assertThat(CelMacro.FILTER.hashCode()).isEqualTo(CelMacro.FILTER.getKey().hashCode()); - assertThat(CelMacro.FILTER).isEquivalentAccordingToCompareTo(CelMacro.FILTER); - } - - @Test - public void testEquals() { - new EqualsTester() - .addEqualityGroup(CelMacro.HAS) - .addEqualityGroup(CelMacro.ALL) - .addEqualityGroup(CelMacro.EXISTS) - .addEqualityGroup(CelMacro.EXISTS_ONE) - .addEqualityGroup(CelMacro.MAP) - .addEqualityGroup(CelMacro.MAP_FILTER) - .addEqualityGroup(CelMacro.FILTER) - .testEquals(); - } - @Test public void testGlobalVarArgMacro() { CelMacro macro = diff --git a/parser/src/test/java/dev/cel/parser/CelParserImplTest.java b/parser/src/test/java/dev/cel/parser/CelParserImplTest.java index 8a9f1439e..97bb8573b 100644 --- a/parser/src/test/java/dev/cel/parser/CelParserImplTest.java +++ b/parser/src/test/java/dev/cel/parser/CelParserImplTest.java @@ -40,14 +40,17 @@ public final class CelParserImplTest { @Test public void build_withMacros_containsAllMacros() { CelParserImpl parser = - (CelParserImpl) CelParserImpl.newBuilder().addMacros(CelMacro.STANDARD_MACROS).build(); - assertThat(parser.findMacro("has:1:false")).hasValue(CelMacro.HAS); - assertThat(parser.findMacro("all:2:true")).hasValue(CelMacro.ALL); - assertThat(parser.findMacro("exists:2:true")).hasValue(CelMacro.EXISTS); - assertThat(parser.findMacro("exists_one:2:true")).hasValue(CelMacro.EXISTS_ONE); - assertThat(parser.findMacro("map:2:true")).hasValue(CelMacro.MAP); - assertThat(parser.findMacro("map:3:true")).hasValue(CelMacro.MAP_FILTER); - assertThat(parser.findMacro("filter:2:true")).hasValue(CelMacro.FILTER); + (CelParserImpl) + CelParserImpl.newBuilder().setStandardMacros(CelStandardMacro.STANDARD_MACROS).build(); + assertThat(parser.findMacro("has:1:false")).hasValue(CelStandardMacro.HAS.getDefinition()); + assertThat(parser.findMacro("all:2:true")).hasValue(CelStandardMacro.ALL.getDefinition()); + assertThat(parser.findMacro("exists:2:true")).hasValue(CelStandardMacro.EXISTS.getDefinition()); + assertThat(parser.findMacro("exists_one:2:true")) + .hasValue(CelStandardMacro.EXISTS_ONE.getDefinition()); + assertThat(parser.findMacro("map:2:true")).hasValue(CelStandardMacro.MAP.getDefinition()); + assertThat(parser.findMacro("map:3:true")) + .hasValue(CelStandardMacro.MAP_FILTER.getDefinition()); + assertThat(parser.findMacro("filter:2:true")).hasValue(CelStandardMacro.FILTER.getDefinition()); } @Test @@ -55,13 +58,15 @@ public void build_withStandardMacros_containsAllMacros() { CelParserImpl parser = (CelParserImpl) CelParserImpl.newBuilder().setStandardMacros(CelStandardMacro.STANDARD_MACROS).build(); - assertThat(parser.findMacro("has:1:false")).hasValue(CelMacro.HAS); - assertThat(parser.findMacro("all:2:true")).hasValue(CelMacro.ALL); - assertThat(parser.findMacro("exists:2:true")).hasValue(CelMacro.EXISTS); - assertThat(parser.findMacro("exists_one:2:true")).hasValue(CelMacro.EXISTS_ONE); - assertThat(parser.findMacro("map:2:true")).hasValue(CelMacro.MAP); - assertThat(parser.findMacro("map:3:true")).hasValue(CelMacro.MAP_FILTER); - assertThat(parser.findMacro("filter:2:true")).hasValue(CelMacro.FILTER); + assertThat(parser.findMacro("has:1:false")).hasValue(CelStandardMacro.HAS.getDefinition()); + assertThat(parser.findMacro("all:2:true")).hasValue(CelStandardMacro.ALL.getDefinition()); + assertThat(parser.findMacro("exists:2:true")).hasValue(CelStandardMacro.EXISTS.getDefinition()); + assertThat(parser.findMacro("exists_one:2:true")) + .hasValue(CelStandardMacro.EXISTS_ONE.getDefinition()); + assertThat(parser.findMacro("map:2:true")).hasValue(CelStandardMacro.MAP.getDefinition()); + assertThat(parser.findMacro("map:3:true")) + .hasValue(CelStandardMacro.MAP_FILTER.getDefinition()); + assertThat(parser.findMacro("filter:2:true")).hasValue(CelStandardMacro.FILTER.getDefinition()); } @Test @@ -76,28 +81,30 @@ public void build_withStandardMacrosAndCustomMacros_containsAllMacros() { .addMacros(customMacro) .build(); - assertThat(parser.findMacro("has:1:false")).hasValue(CelMacro.HAS); - assertThat(parser.findMacro("all:2:true")).hasValue(CelMacro.ALL); - assertThat(parser.findMacro("exists:2:true")).hasValue(CelMacro.EXISTS); - assertThat(parser.findMacro("exists_one:2:true")).hasValue(CelMacro.EXISTS_ONE); - assertThat(parser.findMacro("map:2:true")).hasValue(CelMacro.MAP); - assertThat(parser.findMacro("map:3:true")).hasValue(CelMacro.MAP_FILTER); - assertThat(parser.findMacro("filter:2:true")).hasValue(CelMacro.FILTER); + assertThat(parser.findMacro("has:1:false")).hasValue(CelStandardMacro.HAS.getDefinition()); + assertThat(parser.findMacro("all:2:true")).hasValue(CelStandardMacro.ALL.getDefinition()); + assertThat(parser.findMacro("exists:2:true")).hasValue(CelStandardMacro.EXISTS.getDefinition()); + assertThat(parser.findMacro("exists_one:2:true")) + .hasValue(CelStandardMacro.EXISTS_ONE.getDefinition()); + assertThat(parser.findMacro("map:2:true")).hasValue(CelStandardMacro.MAP.getDefinition()); + assertThat(parser.findMacro("map:3:true")) + .hasValue(CelStandardMacro.MAP_FILTER.getDefinition()); + assertThat(parser.findMacro("filter:2:true")).hasValue(CelStandardMacro.FILTER.getDefinition()); assertThat(parser.findMacro("customMacro:1:true")).hasValue(customMacro); } @Test public void build_withMacro_containsMacro() { CelParserImpl parser = - (CelParserImpl) CelParserImpl.newBuilder().addMacros(CelMacro.HAS).build(); - assertThat(parser.findMacro("has:1:false")).hasValue(CelMacro.HAS); + (CelParserImpl) CelParserImpl.newBuilder().setStandardMacros(CelStandardMacro.HAS).build(); + assertThat(parser.findMacro("has:1:false")).hasValue(CelStandardMacro.HAS.getDefinition()); } @Test public void build_withStandardMacro_containsMacro() { CelParserImpl parser = (CelParserImpl) CelParserImpl.newBuilder().setStandardMacros(CelStandardMacro.HAS).build(); - assertThat(parser.findMacro("has:1:false")).hasValue(CelMacro.HAS); + assertThat(parser.findMacro("has:1:false")).hasValue(CelStandardMacro.HAS.getDefinition()); } @Test @@ -109,7 +116,7 @@ public void build_withStandardMacro_secondCallReplaces() { .setStandardMacros(CelStandardMacro.HAS) .build(); - assertThat(parser.findMacro("has:1:false")).hasValue(CelMacro.HAS); + assertThat(parser.findMacro("has:1:false")).hasValue(CelStandardMacro.HAS.getDefinition()); assertThat(parser.findMacro("all:2:true")).isEmpty(); } @@ -256,7 +263,8 @@ public void parse_exprUnderMaxRecursionLimit_doesNotThrow( @TestParameters("{expression: 'A.exists_one(a?b, c)'}") @TestParameters("{expression: 'A.filter(a?b, c)'}") public void parse_macroArgumentContainsSyntaxError_throws(String expression) { - CelParser parser = CelParserImpl.newBuilder().addMacros(CelMacro.STANDARD_MACROS).build(); + CelParser parser = + CelParserImpl.newBuilder().setStandardMacros(CelStandardMacro.STANDARD_MACROS).build(); CelValidationResult parseResult = parser.parse(expression); diff --git a/parser/src/test/java/dev/cel/parser/CelStandardMacroTest.java b/parser/src/test/java/dev/cel/parser/CelStandardMacroTest.java index 498c14f0e..c06be2688 100644 --- a/parser/src/test/java/dev/cel/parser/CelStandardMacroTest.java +++ b/parser/src/test/java/dev/cel/parser/CelStandardMacroTest.java @@ -16,6 +16,7 @@ import static com.google.common.truth.Truth.assertThat; +import com.google.common.testing.EqualsTester; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -34,4 +35,109 @@ public void getFunction() { assertThat(CelStandardMacro.MAP.getFunction()).isEqualTo(Operator.MAP.getFunction()); assertThat(CelStandardMacro.MAP_FILTER.getFunction()).isEqualTo(Operator.MAP.getFunction()); } + + @Test + public void testHas() { + assertThat(CelStandardMacro.HAS.getFunction()).isEqualTo(Operator.HAS.getFunction()); + assertThat(CelStandardMacro.HAS.getDefinition().getArgumentCount()).isEqualTo(1); + assertThat(CelStandardMacro.HAS.getDefinition().isReceiverStyle()).isFalse(); + assertThat(CelStandardMacro.HAS.getDefinition().getKey()).isEqualTo("has:1:false"); + assertThat(CelStandardMacro.HAS.getDefinition().isVariadic()).isFalse(); + assertThat(CelStandardMacro.HAS.getDefinition().toString()) + .isEqualTo(CelStandardMacro.HAS.getDefinition().getKey()); + assertThat(CelStandardMacro.HAS.getDefinition().hashCode()) + .isEqualTo(CelStandardMacro.HAS.getDefinition().getKey().hashCode()); + } + + @Test + public void testAll() { + assertThat(CelStandardMacro.ALL.getFunction()).isEqualTo(Operator.ALL.getFunction()); + assertThat(CelStandardMacro.ALL.getDefinition().getArgumentCount()).isEqualTo(2); + assertThat(CelStandardMacro.ALL.getDefinition().isReceiverStyle()).isTrue(); + assertThat(CelStandardMacro.ALL.getDefinition().getKey()).isEqualTo("all:2:true"); + assertThat(CelStandardMacro.ALL.getDefinition().isVariadic()).isFalse(); + assertThat(CelStandardMacro.ALL.getDefinition().toString()) + .isEqualTo(CelStandardMacro.ALL.getDefinition().getKey()); + assertThat(CelStandardMacro.ALL.getDefinition().hashCode()) + .isEqualTo(CelStandardMacro.ALL.getDefinition().getKey().hashCode()); + } + + @Test + public void testExists() { + assertThat(CelStandardMacro.EXISTS.getFunction()).isEqualTo(Operator.EXISTS.getFunction()); + assertThat(CelStandardMacro.EXISTS.getDefinition().getArgumentCount()).isEqualTo(2); + assertThat(CelStandardMacro.EXISTS.getDefinition().isReceiverStyle()).isTrue(); + assertThat(CelStandardMacro.EXISTS.getDefinition().getKey()).isEqualTo("exists:2:true"); + assertThat(CelStandardMacro.EXISTS.getDefinition().isVariadic()).isFalse(); + assertThat(CelStandardMacro.EXISTS.getDefinition().toString()) + .isEqualTo(CelStandardMacro.EXISTS.getDefinition().getKey()); + assertThat(CelStandardMacro.EXISTS.getDefinition().hashCode()) + .isEqualTo(CelStandardMacro.EXISTS.getDefinition().getKey().hashCode()); + } + + @Test + public void testExistsOne() { + assertThat(CelStandardMacro.EXISTS_ONE.getFunction()) + .isEqualTo(Operator.EXISTS_ONE.getFunction()); + assertThat(CelStandardMacro.EXISTS_ONE.getDefinition().getArgumentCount()).isEqualTo(2); + assertThat(CelStandardMacro.EXISTS_ONE.getDefinition().isReceiverStyle()).isTrue(); + assertThat(CelStandardMacro.EXISTS_ONE.getDefinition().getKey()).isEqualTo("exists_one:2:true"); + assertThat(CelStandardMacro.EXISTS_ONE.getDefinition().isVariadic()).isFalse(); + assertThat(CelStandardMacro.EXISTS_ONE.getDefinition().toString()) + .isEqualTo(CelStandardMacro.EXISTS_ONE.getDefinition().getKey()); + assertThat(CelStandardMacro.EXISTS_ONE.getDefinition().hashCode()) + .isEqualTo(CelStandardMacro.EXISTS_ONE.getDefinition().getKey().hashCode()); + } + + @Test + public void testMap2() { + assertThat(CelStandardMacro.MAP.getFunction()).isEqualTo(Operator.MAP.getFunction()); + assertThat(CelStandardMacro.MAP.getDefinition().getArgumentCount()).isEqualTo(2); + assertThat(CelStandardMacro.MAP.getDefinition().isReceiverStyle()).isTrue(); + assertThat(CelStandardMacro.MAP.getDefinition().getKey()).isEqualTo("map:2:true"); + assertThat(CelStandardMacro.MAP.getDefinition().isVariadic()).isFalse(); + assertThat(CelStandardMacro.MAP.getDefinition().toString()) + .isEqualTo(CelStandardMacro.MAP.getDefinition().getKey()); + assertThat(CelStandardMacro.MAP.getDefinition().hashCode()) + .isEqualTo(CelStandardMacro.MAP.getDefinition().getKey().hashCode()); + } + + @Test + public void testMap3() { + assertThat(CelStandardMacro.MAP_FILTER.getFunction()).isEqualTo(Operator.MAP.getFunction()); + assertThat(CelStandardMacro.MAP_FILTER.getDefinition().getArgumentCount()).isEqualTo(3); + assertThat(CelStandardMacro.MAP_FILTER.getDefinition().isReceiverStyle()).isTrue(); + assertThat(CelStandardMacro.MAP_FILTER.getDefinition().getKey()).isEqualTo("map:3:true"); + assertThat(CelStandardMacro.MAP_FILTER.getDefinition().isVariadic()).isFalse(); + assertThat(CelStandardMacro.MAP_FILTER.getDefinition().toString()) + .isEqualTo(CelStandardMacro.MAP_FILTER.getDefinition().getKey()); + assertThat(CelStandardMacro.MAP_FILTER.getDefinition().hashCode()) + .isEqualTo(CelStandardMacro.MAP_FILTER.getDefinition().getKey().hashCode()); + } + + @Test + public void testFilter() { + assertThat(CelStandardMacro.FILTER.getFunction()).isEqualTo(Operator.FILTER.getFunction()); + assertThat(CelStandardMacro.FILTER.getDefinition().getArgumentCount()).isEqualTo(2); + assertThat(CelStandardMacro.FILTER.getDefinition().isReceiverStyle()).isTrue(); + assertThat(CelStandardMacro.FILTER.getDefinition().getKey()).isEqualTo("filter:2:true"); + assertThat(CelStandardMacro.FILTER.getDefinition().isVariadic()).isFalse(); + assertThat(CelStandardMacro.FILTER.getDefinition().toString()) + .isEqualTo(CelStandardMacro.FILTER.getDefinition().getKey()); + assertThat(CelStandardMacro.FILTER.getDefinition().hashCode()) + .isEqualTo(CelStandardMacro.FILTER.getDefinition().getKey().hashCode()); + } + + @Test + public void testEquals() { + new EqualsTester() + .addEqualityGroup(CelStandardMacro.HAS) + .addEqualityGroup(CelStandardMacro.ALL) + .addEqualityGroup(CelStandardMacro.EXISTS) + .addEqualityGroup(CelStandardMacro.EXISTS_ONE) + .addEqualityGroup(CelStandardMacro.MAP) + .addEqualityGroup(CelStandardMacro.MAP_FILTER) + .addEqualityGroup(CelStandardMacro.FILTER) + .testEquals(); + } } diff --git a/parser/src/test/java/dev/cel/parser/CelUnparserImplTest.java b/parser/src/test/java/dev/cel/parser/CelUnparserImplTest.java index d17cdf9a0..8eb312560 100644 --- a/parser/src/test/java/dev/cel/parser/CelUnparserImplTest.java +++ b/parser/src/test/java/dev/cel/parser/CelUnparserImplTest.java @@ -41,7 +41,7 @@ public final class CelUnparserImplTest { CelParserImpl.newBuilder() .setOptions(CelOptions.newBuilder().populateMacroCalls(true).build()) .addLibraries(CelOptionalLibrary.INSTANCE) - .addMacros(CelMacro.STANDARD_MACROS) + .setStandardMacros(CelStandardMacro.STANDARD_MACROS) .build(); private final CelUnparserImpl unparser = new CelUnparserImpl(); @@ -249,7 +249,7 @@ public void unparse_comprehensionWithoutMacroCallTracking_presenceTestSucceeds() CelParser parser = CelParserImpl.newBuilder() .setOptions(CelOptions.newBuilder().populateMacroCalls(false).build()) - .addMacros(CelMacro.STANDARD_MACROS) + .setStandardMacros(CelStandardMacro.STANDARD_MACROS) .build(); CelAbstractSyntaxTree ast = parser.parse("has(hello.world)").getAst(); @@ -261,7 +261,7 @@ public void unparse_comprehensionWithoutMacroCallTracking_throwsException() thro CelParser parser = CelParserImpl.newBuilder() .setOptions(CelOptions.newBuilder().populateMacroCalls(false).build()) - .addMacros(CelMacro.STANDARD_MACROS) + .setStandardMacros(CelStandardMacro.STANDARD_MACROS) .build(); CelAbstractSyntaxTree ast = parser.parse("[1, 2, 3].all(x, x > 0)").getAst(); From 8dffc6c797ba1184e67650a41aa2e1a36ed865f1 Mon Sep 17 00:00:00 2001 From: CEL Dev Team Date: Thu, 18 Jan 2024 10:56:41 -0800 Subject: [PATCH 007/486] Internal test change. PiperOrigin-RevId: 599559120 --- runtime/src/test/resources/contextPropagation.baseline | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 runtime/src/test/resources/contextPropagation.baseline diff --git a/runtime/src/test/resources/contextPropagation.baseline b/runtime/src/test/resources/contextPropagation.baseline new file mode 100644 index 000000000..a70382604 --- /dev/null +++ b/runtime/src/test/resources/contextPropagation.baseline @@ -0,0 +1,7 @@ +Source: f() +declare f { + function f () -> string +} +=====> +bindings: {} +result: testpeer \ No newline at end of file From 790e8cfc657e6f94371c4f77af42a013faeabdb2 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Thu, 18 Jan 2024 19:45:24 -0800 Subject: [PATCH 008/486] Implement Optimizer for Common Subexpression Elimination PiperOrigin-RevId: 599696579 --- .gitignore | 2 + .../common/ast/CelExprIdGeneratorFactory.java | 5 + .../common/navigation/CelNavigableExpr.java | 4 + optimizer/optimizers/BUILD.bazel | 6 + .../dev/cel/optimizer/CelAstOptimizer.java | 32 + .../java/dev/cel/optimizer/MutableAst.java | 59 +- .../dev/cel/optimizer/optimizers/BUILD.bazel | 21 + .../optimizers/ConstantFoldingOptimizer.java | 5 +- .../optimizers/SubexpressionOptimizer.java | 321 ++++++++++ .../dev/cel/optimizer/MutableAstTest.java | 19 +- .../dev/cel/optimizer/optimizers/BUILD.bazel | 6 + .../ConstantFoldingOptimizerTest.java | 92 +++ .../SubexpressionOptimizerTest.java | 564 ++++++++++++++++++ 13 files changed, 1111 insertions(+), 25 deletions(-) create mode 100644 optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java create mode 100644 optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java diff --git a/.gitignore b/.gitignore index e8ebf31c4..753e69672 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,8 @@ bazel-cel-java bazel-out bazel-testlogs +MODULE.bazel* + # IntelliJ IDEA .idea *.iml diff --git a/common/src/main/java/dev/cel/common/ast/CelExprIdGeneratorFactory.java b/common/src/main/java/dev/cel/common/ast/CelExprIdGeneratorFactory.java index 10e259c07..9b7bc60fc 100644 --- a/common/src/main/java/dev/cel/common/ast/CelExprIdGeneratorFactory.java +++ b/common/src/main/java/dev/cel/common/ast/CelExprIdGeneratorFactory.java @@ -64,6 +64,11 @@ public boolean hasId(long id) { return idSet.containsKey(id); } + /** Generates the next available ID. */ + public long nextExprId() { + return ++exprId; + } + /** * Generate the next available ID while memoizing the existing ID. * diff --git a/common/src/main/java/dev/cel/common/navigation/CelNavigableExpr.java b/common/src/main/java/dev/cel/common/navigation/CelNavigableExpr.java index 76fa5bfb0..326f8b78f 100644 --- a/common/src/main/java/dev/cel/common/navigation/CelNavigableExpr.java +++ b/common/src/main/java/dev/cel/common/navigation/CelNavigableExpr.java @@ -50,6 +50,10 @@ public enum TraversalOrder { public abstract CelExpr expr(); + public long id() { + return expr().id(); + } + public abstract Optional parent(); /** Represents the count of transitive parents. Depth of an AST's root is 0. */ diff --git a/optimizer/optimizers/BUILD.bazel b/optimizer/optimizers/BUILD.bazel index c6cdf913a..e39612db2 100644 --- a/optimizer/optimizers/BUILD.bazel +++ b/optimizer/optimizers/BUILD.bazel @@ -7,3 +7,9 @@ java_library( name = "constant_folding", exports = ["//optimizer/src/main/java/dev/cel/optimizer/optimizers:constant_folding"], ) + +java_library( + name = "common_subexpression_elimination", + visibility = ["//visibility:public"], # TODO: Expose when ready + exports = ["//optimizer/src/main/java/dev/cel/optimizer/optimizers:common_subexpression_elimination"], +) diff --git a/optimizer/src/main/java/dev/cel/optimizer/CelAstOptimizer.java b/optimizer/src/main/java/dev/cel/optimizer/CelAstOptimizer.java index 652dca0e2..9a9f22c94 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/CelAstOptimizer.java +++ b/optimizer/src/main/java/dev/cel/optimizer/CelAstOptimizer.java @@ -47,4 +47,36 @@ default CelAbstractSyntaxTree replaceSubtree( CelAbstractSyntaxTree ast, CelExpr newExpr, long exprIdToReplace) { return MutableAst.replaceSubtree(ast, newExpr, exprIdToReplace); } + + /** + * Generates a new bind macro using the provided initialization and result expression, then + * replaces the subtree using the new bind expr at the designated expr ID. + * + *

The bind call takes the format of: {@code cel.bind(varInit, varName, resultExpr)} + * + * @param ast Original ast to mutate. + * @param varName New variable name for the bind macro call. + * @param varInit Initialization expression to bind to the local variable. + * @param resultExpr Result expression + * @param exprIdToReplace Expression ID of the subtree that is getting replaced. + */ + default CelAbstractSyntaxTree replaceSubtreeWithNewBindMacro( + CelAbstractSyntaxTree ast, + String varName, + CelExpr varInit, + CelExpr resultExpr, + long exprIdToReplace) { + return MutableAst.replaceSubtreeWithNewBindMacro( + ast, varName, varInit, resultExpr, exprIdToReplace); + } + + /** Sets all expr IDs in the expression tree to 0. */ + default CelExpr clearExprIds(CelExpr celExpr) { + return MutableAst.clearExprIds(celExpr); + } + + /** Renumbers all the expr IDs in the given AST in a consecutive manner starting from 1. */ + default CelAbstractSyntaxTree renumberIdsConsecutively(CelAbstractSyntaxTree ast) { + return MutableAst.renumberIdsConsecutively(ast); + } } diff --git a/optimizer/src/main/java/dev/cel/optimizer/MutableAst.java b/optimizer/src/main/java/dev/cel/optimizer/MutableAst.java index c8bf99c75..f1f579252 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/MutableAst.java +++ b/optimizer/src/main/java/dev/cel/optimizer/MutableAst.java @@ -31,6 +31,7 @@ import dev.cel.common.ast.CelExpr.CelCreateMap; import dev.cel.common.ast.CelExpr.CelCreateStruct; import dev.cel.common.ast.CelExpr.CelSelect; +import dev.cel.common.ast.CelExpr.ExprKind.Kind; import dev.cel.common.ast.CelExprFactory; import dev.cel.common.ast.CelExprIdGeneratorFactory; import dev.cel.common.ast.CelExprIdGeneratorFactory.ExprIdGenerator; @@ -42,7 +43,7 @@ /** MutableAst contains logic for mutating a {@link CelExpr}. */ @Internal final class MutableAst { - private static final int MAX_ITERATION_COUNT = 500; + private static final int MAX_ITERATION_COUNT = 1000; private final CelExpr.Builder newExpr; private final ExprIdGenerator celExprIdGenerator; private int iterationCount; @@ -91,7 +92,8 @@ static CelAbstractSyntaxTree replaceSubtree( // Mutate the AST root with the new subtree. All the existing expr IDs are renumbered in the // process, but its original IDs are memoized so that we can normalize the expr IDs // in the macro source map. - StableIdGenerator stableIdGenerator = CelExprIdGeneratorFactory.newStableIdGenerator(0); + StableIdGenerator stableIdGenerator = + CelExprIdGeneratorFactory.newStableIdGenerator(getMaxId(newAst)); CelExpr.Builder mutatedRoot = replaceSubtreeImpl( stableIdGenerator::renumberId, @@ -147,13 +149,26 @@ static CelAbstractSyntaxTree replaceSubtreeWithNewBindMacro( ast, CelAbstractSyntaxTree.newParsedAst(bindMacro.bindExpr(), celSource), exprIdToReplace); } + static CelAbstractSyntaxTree renumberIdsConsecutively(CelAbstractSyntaxTree ast) { + StableIdGenerator stableIdGenerator = CelExprIdGeneratorFactory.newStableIdGenerator(0); + CelExpr.Builder root = + renumberExprIds(stableIdGenerator::renumberId, ast.getExpr().toBuilder()); + CelSource newSource = + normalizeMacroSource( + ast.getSource(), Integer.MIN_VALUE, root, stableIdGenerator::renumberId); + + return CelAbstractSyntaxTree.newParsedAst(root.build(), newSource); + } + private static BindMacro newBindMacro( String varName, CelExpr varInit, CelExpr resultExpr, StableIdGenerator stableIdGenerator) { - // Clear incoming expression IDs in the initialization expression to avoid collision with the - // main AST. - varInit = clearExprIds(varInit); + // Renumber incoming expression IDs in the init and result expression to avoid collision with + // the main AST. Existing IDs are memoized for a macro source sanitization pass at the end + // (e.g: inserting a bind macro to an existing macro expr) + varInit = renumberExprIds(stableIdGenerator::nextExprId, varInit.toBuilder()).build(); + resultExpr = renumberExprIds(stableIdGenerator::nextExprId, resultExpr.toBuilder()).build(); CelExprFactory exprFactory = - CelExprFactory.newInstance((unused) -> stableIdGenerator.nextExprId(-1)); + CelExprFactory.newInstance((unused) -> stableIdGenerator.nextExprId()); CelExpr bindMacroExpr = exprFactory.fold( "#unused", @@ -164,17 +179,12 @@ private static BindMacro newBindMacro( exprFactory.newIdentifier(varName), resultExpr); - // Update the IDs in the new expression tree first. This ensures that no ID collision - // occurs while attempting to replace the subtree later, potentially leading to an infinite loop - bindMacroExpr = - renumberExprIds(stableIdGenerator::nextExprId, bindMacroExpr.toBuilder()).build(); - CelExpr bindMacroCallExpr = exprFactory .newReceiverCall( "bind", - CelExpr.ofIdentExpr(stableIdGenerator.nextExprId(-1), "cel"), - CelExpr.ofIdentExpr(stableIdGenerator.nextExprId(-1), varName), + CelExpr.ofIdentExpr(stableIdGenerator.nextExprId(), "cel"), + CelExpr.ofIdentExpr(stableIdGenerator.nextExprId(), varName), bindMacroExpr.comprehension().accuInit(), bindMacroExpr.comprehension().result()) .toBuilder() @@ -270,6 +280,7 @@ private static CelSource normalizeMacroSource( if (!allExprs.containsKey(callChild.id())) { continue; } + CelExpr mutatedExpr = allExprs.get(callChild.id()); if (!callChild.equals(mutatedExpr)) { newCall = @@ -279,6 +290,25 @@ private static CelSource normalizeMacroSource( sourceBuilder.addMacroCalls(callId, newCall.build()); } + // Replace comprehension nodes with a NOT_SET reference to reduce AST size. + for (Entry macroCall : sourceBuilder.getMacroCalls().entrySet()) { + CelExpr macroCallExpr = macroCall.getValue(); + CelNavigableExpr.fromExpr(macroCallExpr) + .allNodes() + .filter(node -> node.getKind().equals(Kind.COMPREHENSION)) + .map(CelNavigableExpr::expr) + .forEach( + node -> { + CelExpr.Builder mutatedNode = + replaceSubtreeImpl( + (id) -> id, + macroCallExpr.toBuilder(), + CelExpr.ofNotSet(node.id()).toBuilder(), + node.id()); + macroCall.setValue(mutatedNode.build()); + }); + } + return sourceBuilder.build(); } @@ -309,7 +339,7 @@ private static long getMaxId(CelAbstractSyntaxTree ast) { private static long getMaxId(CelExpr newExpr) { return CelNavigableExpr.fromExpr(newExpr) .allNodes() - .mapToLong(node -> node.expr().id()) + .mapToLong(CelNavigableExpr::id) .max() .orElseThrow(NoSuchElementException::new); } @@ -419,7 +449,6 @@ private CelExpr.Builder visit(CelExpr.Builder expr, CelComprehension.Builder com */ @AutoValue abstract static class BindMacro { - /** Comprehension expr for the generated cel.bind macro. */ abstract CelExpr bindExpr(); diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel b/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel index 730f0c0d2..f2519c83c 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel @@ -27,3 +27,24 @@ java_library( "@maven//:com_google_guava_guava", ], ) + +java_library( + name = "common_subexpression_elimination", + srcs = [ + "SubexpressionOptimizer.java", + ], + tags = [ + ], + deps = [ + "//:auto_value", + "//bundle:cel", + "//checker:checker_legacy_environment", + "//common", + "//common/ast", + "//common/navigation", + "//optimizer:ast_optimizer", + "//parser:operator", + "@maven//:com_google_guava_guava", + "@maven//:org_jspecify_jspecify", + ], +) diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java b/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java index 460654bb6..272cd54f8 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java @@ -98,9 +98,8 @@ public CelAbstractSyntaxTree optimize(CelNavigableAst navigableAst, Cel cel) // If the output is a list, map, or struct which contains optional entries, then prune it // to make sure that the optionals, if resolved, do not surface in the output literal. - navigableAst = CelNavigableAst.fromAst(pruneOptionalElements(navigableAst)); - - return navigableAst.getAst(); + CelAbstractSyntaxTree newAst = pruneOptionalElements(navigableAst); + return renumberIdsConsecutively(newAst); } private static boolean canFold(CelNavigableExpr navigableExpr) { diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java new file mode 100644 index 000000000..88ae694e6 --- /dev/null +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java @@ -0,0 +1,321 @@ +// Copyright 2024 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.optimizers; + +import static com.google.common.collect.ImmutableList.toImmutableList; +import static com.google.common.collect.ImmutableSet.toImmutableSet; +import static java.util.Arrays.stream; + +import com.google.auto.value.AutoValue; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Streams; +import dev.cel.bundle.Cel; +import dev.cel.checker.Standard; +import dev.cel.common.CelAbstractSyntaxTree; +import dev.cel.common.CelSource; +import dev.cel.common.ast.CelExpr; +import dev.cel.common.ast.CelExpr.CelIdent; +import dev.cel.common.ast.CelExpr.ExprKind.Kind; +import dev.cel.common.navigation.CelNavigableAst; +import dev.cel.common.navigation.CelNavigableExpr; +import dev.cel.common.navigation.CelNavigableExpr.TraversalOrder; +import dev.cel.optimizer.CelAstOptimizer; +import dev.cel.parser.Operator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.NoSuchElementException; +import java.util.Optional; +import java.util.stream.Stream; + +/** + * Performs Common Subexpression Elimination. + * + *

+ * Subexpressions are extracted into `cel.bind` calls. For example, the expression below:
+ *
+ * {@code
+ *    message.child.text_map[x].startsWith("hello") && message.child.text_map[x].endsWith("world")
+ * }
+ *
+ * will be optimized into the following form:
+ *
+ * {@code
+ *    cel.bind(@r0, message.child.text_map[x],
+ *        @r0.startsWith("hello") && @r0.endsWith("world"))
+ * }
+ * 
+ */ +public class SubexpressionOptimizer implements CelAstOptimizer { + + private static final SubexpressionOptimizer INSTANCE = + new SubexpressionOptimizer(SubexpressionOptimizerOptions.newBuilder().build()); + private static final String BIND_IDENTIFIER_PREFIX = "@r"; + private static final ImmutableSet CSE_ALLOWED_FUNCTIONS = + Streams.concat( + stream(Operator.values()).map(Operator::getFunction), + stream(Standard.Function.values()).map(Standard.Function::getFunction)) + .collect(toImmutableSet()); + private final SubexpressionOptimizerOptions cseOptions; + + /** + * Returns a default instance of common subexpression elimination optimizer with preconfigured + * defaults. + */ + public static SubexpressionOptimizer getInstance() { + return INSTANCE; + } + + /** + * Returns a new instance of common subexpression elimination optimizer configured with the + * provided {@link SubexpressionOptimizerOptions}. + */ + public static SubexpressionOptimizer newInstance(SubexpressionOptimizerOptions cseOptions) { + return new SubexpressionOptimizer(cseOptions); + } + + @Override + public CelAbstractSyntaxTree optimize(CelNavigableAst navigableAst, Cel cel) { + CelAbstractSyntaxTree astToModify = navigableAst.getAst(); + CelSource sourceToModify = astToModify.getSource(); + int bindIdentifierIndex = 0; + int iterCount; + for (iterCount = 0; iterCount < cseOptions.maxIterationLimit(); iterCount++) { + CelNavigableExpr cseCandidate = findCseCandidate(astToModify).orElse(null); + if (cseCandidate == null) { + break; + } + + String bindIdentifier = BIND_IDENTIFIER_PREFIX + bindIdentifierIndex; + bindIdentifierIndex++; + + // Using the CSE candidate, fetch all semantically equivalent subexpressions ahead of time. + ImmutableList allCseCandidates = + getAllCseCandidatesStream(astToModify, cseCandidate.expr()).collect(toImmutableList()); + + // Replace all CSE candidates with new bind identifier + for (CelExpr semanticallyEqualNode : allCseCandidates) { + iterCount++; + // Refetch the candidate expr as mutating the AST could have renumbered its IDs. + CelExpr exprToReplace = + getAllCseCandidatesStream(astToModify, semanticallyEqualNode) + .findAny() + .orElseThrow( + () -> + new NoSuchElementException( + "No value present for expr ID: " + semanticallyEqualNode.id())); + + astToModify = + replaceSubtree( + astToModify, + CelExpr.newBuilder() + .setIdent(CelIdent.newBuilder().setName(bindIdentifier).build()) + .build(), + exprToReplace.id()); + } + + // Find LCA to insert the new cel.bind macro into. + CelNavigableExpr lca = getLca(astToModify, bindIdentifier); + + sourceToModify = + sourceToModify.toBuilder() + .addAllMacroCalls(astToModify.getSource().getMacroCalls()) + .build(); + astToModify = CelAbstractSyntaxTree.newParsedAst(astToModify.getExpr(), sourceToModify); + + // Insert the new bind call + astToModify = + replaceSubtreeWithNewBindMacro( + astToModify, bindIdentifier, cseCandidate.expr(), lca.expr(), lca.id()); + + // Retain the existing macro calls in case if the bind identifiers are replacing a subtree + // that contains a comprehension. + sourceToModify = astToModify.getSource(); + } + + if (iterCount >= cseOptions.maxIterationLimit()) { + throw new IllegalStateException("Max iteration count reached."); + } + + if (iterCount == 0) { + // No modification has been made. + return astToModify; + } + + if (!cseOptions.populateMacroCalls()) { + astToModify = + CelAbstractSyntaxTree.newParsedAst(astToModify.getExpr(), CelSource.newBuilder().build()); + } + + return renumberIdsConsecutively(astToModify); + } + + private Stream getAllCseCandidatesStream( + CelAbstractSyntaxTree ast, CelExpr cseCandidate) { + return CelNavigableAst.fromAst(ast) + .getRoot() + .allNodes() + .filter(SubexpressionOptimizer::canEliminate) + .map(CelNavigableExpr::expr) + .filter(expr -> areSemanticallyEqual(cseCandidate, expr)); + } + + private static CelNavigableExpr getLca(CelAbstractSyntaxTree ast, String boundIdentifier) { + CelNavigableExpr root = CelNavigableAst.fromAst(ast).getRoot(); + ImmutableList allNodesWithIdentifier = + root.allNodes() + .filter(node -> node.expr().identOrDefault().name().equals(boundIdentifier)) + .collect(toImmutableList()); + + if (allNodesWithIdentifier.size() < 2) { + throw new IllegalStateException("Expected at least 2 bound identifiers to be present."); + } + + CelNavigableExpr lca = root; + long lcaAncestorCount = 0; + HashMap ancestors = new HashMap<>(); + for (CelNavigableExpr navigableExpr : allNodesWithIdentifier) { + Optional maybeParent = Optional.of(navigableExpr); + while (maybeParent.isPresent()) { + CelNavigableExpr parent = maybeParent.get(); + if (!ancestors.containsKey(parent.id())) { + ancestors.put(parent.id(), 1L); + continue; + } + + long ancestorCount = ancestors.get(parent.id()); + if (lcaAncestorCount < ancestorCount + || (lcaAncestorCount == ancestorCount && lca.depth() < parent.depth())) { + lca = parent; + lcaAncestorCount = ancestorCount; + } + + ancestors.put(parent.id(), ancestorCount + 1); + maybeParent = parent.parent(); + } + } + + return lca; + } + + private Optional findCseCandidate(CelAbstractSyntaxTree ast) { + HashSet encounteredNodes = new HashSet<>(); + ImmutableList allNodes = + CelNavigableAst.fromAst(ast) + .getRoot() + .allNodes(TraversalOrder.PRE_ORDER) + .filter(SubexpressionOptimizer::canEliminate) + .collect(toImmutableList()); + + for (CelNavigableExpr node : allNodes) { + // Strip out all IDs to test equivalence + CelExpr celExpr = clearExprIds(node.expr()); + if (encounteredNodes.contains(celExpr)) { + return Optional.of(node); + } + + encounteredNodes.add(celExpr); + } + + return Optional.empty(); + } + + private static boolean canEliminate(CelNavigableExpr navigableExpr) { + return !navigableExpr.getKind().equals(Kind.CONSTANT) + && !navigableExpr.getKind().equals(Kind.IDENT) + && !navigableExpr.expr().identOrDefault().name().startsWith(BIND_IDENTIFIER_PREFIX) + && isAllowedFunction(navigableExpr) + && isWithinInlineableComprehension(navigableExpr); + } + + private static boolean isWithinInlineableComprehension(CelNavigableExpr expr) { + Optional maybeParent = expr.parent(); + while (maybeParent.isPresent()) { + CelNavigableExpr parent = maybeParent.get(); + if (parent.getKind().equals(Kind.COMPREHENSION)) { + return Streams.concat( + // If the expression is within a comprehension, it is eligible for CSE iff is in + // result or iterRange. While result is not human authored, it needs to be included + // to extract subexpressions that are already in cel.bind macro. + CelNavigableExpr.fromExpr(parent.expr().comprehension().result()).descendants(), + CelNavigableExpr.fromExpr(parent.expr().comprehension().iterRange()).allNodes()) + .filter( + node -> + // Exclude empty lists (cel.bind sets this for iterRange). + !node.getKind().equals(Kind.CREATE_LIST) + || !node.expr().createList().elements().isEmpty()) + .map(CelNavigableExpr::expr) + .anyMatch(node -> node.equals(expr.expr())); + } + maybeParent = parent.parent(); + } + + return true; + } + + private boolean areSemanticallyEqual(CelExpr expr1, CelExpr expr2) { + return clearExprIds(expr1).equals(clearExprIds(expr2)); + } + + private static boolean isAllowedFunction(CelNavigableExpr navigableExpr) { + if (navigableExpr.getKind().equals(Kind.CALL)) { + return CSE_ALLOWED_FUNCTIONS.contains(navigableExpr.expr().call().function()); + } + + return true; + } + + /** Options to configure how Common Subexpression Elimination behave. */ + @AutoValue + public abstract static class SubexpressionOptimizerOptions { + public abstract int maxIterationLimit(); + + public abstract boolean populateMacroCalls(); + + /** Builder for configuring the {@link SubexpressionOptimizerOptions}. */ + @AutoValue.Builder + public abstract static class Builder { + + /** + * Limit the number of iteration while performing CSE. An exception is thrown if the iteration + * count exceeds the set value. + */ + public abstract Builder maxIterationLimit(int value); + + /** + * Populate the macro_calls map in source_info with macro calls on the resulting optimized + * AST. + */ + public abstract Builder populateMacroCalls(boolean value); + + public abstract SubexpressionOptimizerOptions build(); + + Builder() {} + } + + /** Returns a new options builder with recommended defaults pre-configured. */ + public static Builder newBuilder() { + return new AutoValue_SubexpressionOptimizer_SubexpressionOptimizerOptions.Builder() + .maxIterationLimit(500) + .populateMacroCalls(false); + } + + SubexpressionOptimizerOptions() {} + } + + private SubexpressionOptimizer(SubexpressionOptimizerOptions cseOptions) { + this.cseOptions = cseOptions; + } +} diff --git a/optimizer/src/test/java/dev/cel/optimizer/MutableAstTest.java b/optimizer/src/test/java/dev/cel/optimizer/MutableAstTest.java index b7f1d29d0..587c3c71d 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/MutableAstTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/MutableAstTest.java @@ -71,7 +71,7 @@ public void constExpr() throws Exception { ast, CelExpr.newBuilder().setConstant(CelConstant.ofValue(true)).build(), 1); assertThat(mutatedAst.getExpr()) - .isEqualTo(CelExpr.ofConstantExpr(1, CelConstant.ofValue(true))); + .isEqualTo(CelExpr.ofConstantExpr(3, CelConstant.ofValue(true))); } @Test @@ -126,7 +126,7 @@ public void replaceSubtree_rootReplacedWithMacro_macroCallPopulated( CelAbstractSyntaxTree ast2 = CEL.compile(source).getAst(); CelAbstractSyntaxTree mutatedAst = - MutableAst.replaceSubtree(ast, ast2, CelNavigableAst.fromAst(ast).getRoot().expr().id()); + MutableAst.replaceSubtree(ast, ast2, CelNavigableAst.fromAst(ast).getRoot().id()); assertThat(mutatedAst.getSource().getMacroCalls()).hasSize(expectedMacroCallSize); assertThat(CEL_UNPARSER.unparse(mutatedAst)).isEqualTo(source); @@ -185,7 +185,7 @@ public void replaceSubtreeWithNewBindMacro_replaceRoot() throws Exception { variableName, CelExpr.ofConstantExpr(0, CelConstant.ofValue(3L)), resultExpr, - CelNavigableAst.fromAst(ast).getRoot().expr().id()); + CelNavigableAst.fromAst(ast).getRoot().id()); assertThat(mutatedAst.getSource().getMacroCalls()).hasSize(1); assertThat(CEL_UNPARSER.unparse(mutatedAst)).isEqualTo("cel.bind(@r0, 3, @r0 + @r0)"); @@ -333,7 +333,7 @@ public void replaceSubtreeWithNewBindMacro_replaceRootWithNestedBindMacro() thro nestedVariableName, CelExpr.ofConstantExpr(0, CelConstant.ofValue(3L)), resultExpr, - 1); + CelNavigableAst.fromAst(mutatedAst).getRoot().id()); assertThat(mutatedAst.getSource().getMacroCalls()).hasSize(2); assertThat(CEL.createProgram(CEL.check(mutatedAst).getAst()).eval()).isEqualTo(8); @@ -349,7 +349,7 @@ public void replaceSubtree_macroReplacedWithConstExpr_macroCallCleared() throws CelAbstractSyntaxTree ast2 = CEL.compile("1").getAst(); CelAbstractSyntaxTree mutatedAst = - MutableAst.replaceSubtree(ast, ast2, CelNavigableAst.fromAst(ast).getRoot().expr().id()); + MutableAst.replaceSubtree(ast, ast2, CelNavigableAst.fromAst(ast).getRoot().id()); assertThat(mutatedAst.getSource().getMacroCalls()).isEmpty(); assertThat(CEL_UNPARSER.unparse(mutatedAst)).isEqualTo("1"); @@ -368,7 +368,7 @@ public void globalCallExpr_replaceRoot() throws Exception { MutableAst.replaceSubtree( ast, CelExpr.newBuilder().setConstant(CelConstant.ofValue(10)).build(), 4); - assertThat(replacedAst.getExpr()).isEqualTo(CelExpr.ofConstantExpr(1, CelConstant.ofValue(10))); + assertThat(replacedAst.getExpr()).isEqualTo(CelExpr.ofConstantExpr(7, CelConstant.ofValue(10))); } @Test @@ -673,7 +673,12 @@ private void assertConsistentMacroCalls(CelAbstractSyntaxTree ast) { node -> { CelExpr e = allExprs.get(node.id()); if (e != null) { - assertThat(node).isEqualTo(e); + assertThat(node.id()).isEqualTo(e.id()); + if (e.exprKind().getKind().equals(Kind.COMPREHENSION)) { + assertThat(node.exprKind().getKind()).isEqualTo(Kind.NOT_SET); + } else { + assertThat(node.exprKind().getKind()).isEqualTo(e.exprKind().getKind()); + } } }); } diff --git a/optimizer/src/test/java/dev/cel/optimizer/optimizers/BUILD.bazel b/optimizer/src/test/java/dev/cel/optimizer/optimizers/BUILD.bazel index 3e1119847..a4f8143f8 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/optimizers/BUILD.bazel +++ b/optimizer/src/test/java/dev/cel/optimizer/optimizers/BUILD.bazel @@ -10,16 +10,22 @@ java_library( "//:java_truth", "//bundle:cel", "//common", + "//common:compiler_common", "//common:options", + "//common/ast", "//common/resources/testdata/proto3:test_all_types_java_proto", "//common/types", + "//extensions", "//extensions:optional_library", "//optimizer", "//optimizer:optimization_exception", "//optimizer:optimizer_builder", + "//optimizer/optimizers:common_subexpression_elimination", "//optimizer/optimizers:constant_folding", "//parser:macro", + "//parser:operator", "//parser:unparser", + "@maven//:com_google_guava_guava", "@maven//:com_google_testparameterinjector_test_parameter_injector", "@maven//:junit_junit", ], diff --git a/optimizer/src/test/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizerTest.java b/optimizer/src/test/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizerTest.java index f47481be1..eaa8c6ced 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizerTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizerTest.java @@ -288,6 +288,98 @@ public void constantFold_noOp(String source) throws Exception { assertThat(CEL_UNPARSER.unparse(optimizedAst)).isEqualTo(source); } + @Test + public void constantFold_withMacroCallPopulated_comprehensionsAreReplacedWithNotSet() + throws Exception { + Cel cel = + CelFactory.standardCelBuilder() + .addVar("x", SimpleType.DYN) + .setStandardMacros(CelStandardMacro.STANDARD_MACROS) + .setOptions(CelOptions.current().populateMacroCalls(true).build()) + .build(); + CelOptimizer celOptimizer = + CelOptimizerFactory.standardCelOptimizerBuilder(cel) + .addAstOptimizers(ConstantFoldingOptimizer.INSTANCE) + .build(); + CelAbstractSyntaxTree ast = + cel.compile("[1, 1 + 1, 1 + 1+ 1].map(i, i).filter(j, j % 2 == x)").getAst(); + + CelAbstractSyntaxTree optimizedAst = celOptimizer.optimize(ast); + + assertThat(CEL_UNPARSER.unparse(optimizedAst)) + .isEqualTo("[1, 2, 3].map(i, i).filter(j, j % 2 == x)"); + assertThat(optimizedAst.getSource().getMacroCalls()).hasSize(2); + assertThat(optimizedAst.getSource().getMacroCalls().get(1L).toString()) + .isEqualTo( + "CALL [0] {\n" + + " function: filter\n" + + " target: {\n" + + " NOT_SET [2] {}\n" + + " }\n" + + " args: {\n" + + " IDENT [25] {\n" + + " name: j\n" + + " }\n" + + " CALL [17] {\n" + + " function: _==_\n" + + " args: {\n" + + " CALL [18] {\n" + + " function: _%_\n" + + " args: {\n" + + " IDENT [19] {\n" + + " name: j\n" + + " }\n" + + " CONSTANT [20] { value: 2 }\n" + + " }\n" + + " }\n" + + " IDENT [21] {\n" + + " name: x\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + "}"); + assertThat(optimizedAst.getSource().getMacroCalls().get(2L).toString()) + .isEqualTo( + "CALL [0] {\n" + + " function: map\n" + + " target: {\n" + + " CREATE_LIST [3] {\n" + + " elements: {\n" + + " CONSTANT [4] { value: 1 }\n" + + " CONSTANT [5] { value: 2 }\n" + + " CONSTANT [6] { value: 3 }\n" + + " }\n" + + " }\n" + + " }\n" + + " args: {\n" + + " IDENT [28] {\n" + + " name: i\n" + + " }\n" + + " IDENT [12] {\n" + + " name: i\n" + + " }\n" + + " }\n" + + "}"); + } + + @Test + public void constantFold_astProducesConsistentlyNumberedIds() throws Exception { + CelAbstractSyntaxTree ast = CEL.compile("[1] + [2] + [3]").getAst(); + + CelAbstractSyntaxTree optimizedAst = CEL_OPTIMIZER.optimize(ast); + + assertThat(optimizedAst.getExpr().toString()) + .isEqualTo( + "CREATE_LIST [1] {\n" + + " elements: {\n" + + " CONSTANT [2] { value: 1 }\n" + + " CONSTANT [3] { value: 2 }\n" + + " CONSTANT [4] { value: 3 }\n" + + " }\n" + + "}"); + } + @Test public void maxIterationCountReached_throws() throws Exception { StringBuilder sb = new StringBuilder(); diff --git a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java new file mode 100644 index 000000000..157417504 --- /dev/null +++ b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java @@ -0,0 +1,564 @@ +// Copyright 2024 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.optimizers; + +import static com.google.common.truth.Truth.assertThat; +import static dev.cel.common.CelOverloadDecl.newGlobalOverload; +import static org.junit.Assert.assertThrows; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.testing.junit.testparameterinjector.TestParameter; +import com.google.testing.junit.testparameterinjector.TestParameterInjector; +import com.google.testing.junit.testparameterinjector.TestParameters; +import dev.cel.bundle.Cel; +import dev.cel.bundle.CelBuilder; +import dev.cel.bundle.CelFactory; +import dev.cel.common.CelAbstractSyntaxTree; +import dev.cel.common.CelFunctionDecl; +import dev.cel.common.CelOptions; +import dev.cel.common.ast.CelConstant; +import dev.cel.common.ast.CelExpr; +import dev.cel.common.types.SimpleType; +import dev.cel.common.types.StructTypeReference; +import dev.cel.extensions.CelExtensions; +import dev.cel.extensions.CelOptionalLibrary; +import dev.cel.optimizer.CelOptimizationException; +import dev.cel.optimizer.CelOptimizer; +import dev.cel.optimizer.CelOptimizerFactory; +import dev.cel.optimizer.optimizers.SubexpressionOptimizer.SubexpressionOptimizerOptions; +import dev.cel.parser.CelStandardMacro; +import dev.cel.parser.CelUnparser; +import dev.cel.parser.CelUnparserFactory; +import dev.cel.parser.Operator; +import dev.cel.testing.testdata.proto3.TestAllTypesProto.NestedTestAllTypes; +import dev.cel.testing.testdata.proto3.TestAllTypesProto.TestAllTypes; +import java.util.Optional; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(TestParameterInjector.class) +public class SubexpressionOptimizerTest { + + private static final Cel CEL = newCelBuilder().build(); + + private static final CelOptimizer CEL_OPTIMIZER = + CelOptimizerFactory.standardCelOptimizerBuilder(CEL) + .addAstOptimizers( + SubexpressionOptimizer.newInstance( + SubexpressionOptimizerOptions.newBuilder().populateMacroCalls(true).build())) + .build(); + + private static final CelUnparser CEL_UNPARSER = CelUnparserFactory.newUnparser(); + + private static final TestAllTypes TEST_ALL_TYPES_INPUT = + TestAllTypes.newBuilder() + .setSingleInt64(3L) + .setSingleInt32(5) + .setOneofType( + NestedTestAllTypes.newBuilder() + .setPayload( + TestAllTypes.newBuilder() + .setSingleInt32(8) + .setSingleInt64(10L) + .putMapInt32Int64(0, 1) + .putMapInt32Int64(1, 5) + .putMapInt32Int64(2, 2))) + .build(); + + private static CelBuilder newCelBuilder() { + return CelFactory.standardCelBuilder() + .addMessageTypes(TestAllTypes.getDescriptor()) + .setContainer("dev.cel.testing.testdata.proto3") + .setStandardMacros(CelStandardMacro.STANDARD_MACROS) + .setOptions( + CelOptions.current().enableTimestampEpoch(true).populateMacroCalls(true).build()) + .addCompilerLibraries(CelOptionalLibrary.INSTANCE, CelExtensions.bindings()) + .addRuntimeLibraries(CelOptionalLibrary.INSTANCE) + .addFunctionDeclarations( + CelFunctionDecl.newFunctionDeclaration( + "custom_func", + newGlobalOverload("custom_func_overload", SimpleType.INT, SimpleType.INT))) + .addVar("x", SimpleType.DYN) + .addVar("msg", StructTypeReference.create(TestAllTypes.getDescriptor().getFullName())); + } + + @Test + public void cse_producesOptimizedAst() throws Exception { + CelAbstractSyntaxTree ast = + CEL.compile("size([0]) + size([0]) + size([1,2]) + size([1,2])").getAst(); + + CelAbstractSyntaxTree optimizedAst = CEL_OPTIMIZER.optimize(ast); + + assertThat(CEL.createProgram(optimizedAst).eval()).isEqualTo(6); + assertThat(optimizedAst.getExpr().toString()) + .isEqualTo( + "COMPREHENSION [1] {\n" + + " iter_var: #unused\n" + + " iter_range: {\n" + + " CREATE_LIST [2] {\n" + + " elements: {\n" + + " }\n" + + " }\n" + + " }\n" + + " accu_var: @r1\n" + + " accu_init: {\n" + + " CALL [3] {\n" + + " function: size\n" + + " args: {\n" + + " CREATE_LIST [4] {\n" + + " elements: {\n" + + " CONSTANT [5] { value: 1 }\n" + + " CONSTANT [6] { value: 2 }\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + " loop_condition: {\n" + + " CONSTANT [7] { value: false }\n" + + " }\n" + + " loop_step: {\n" + + " IDENT [8] {\n" + + " name: @r1\n" + + " }\n" + + " }\n" + + " result: {\n" + + " CALL [9] {\n" + + " function: _+_\n" + + " args: {\n" + + " CALL [10] {\n" + + " function: _+_\n" + + " args: {\n" + + " COMPREHENSION [11] {\n" + + " iter_var: #unused\n" + + " iter_range: {\n" + + " CREATE_LIST [12] {\n" + + " elements: {\n" + + " }\n" + + " }\n" + + " }\n" + + " accu_var: @r0\n" + + " accu_init: {\n" + + " CALL [13] {\n" + + " function: size\n" + + " args: {\n" + + " CREATE_LIST [14] {\n" + + " elements: {\n" + + " CONSTANT [15] { value: 0 }\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + " loop_condition: {\n" + + " CONSTANT [16] { value: false }\n" + + " }\n" + + " loop_step: {\n" + + " IDENT [17] {\n" + + " name: @r0\n" + + " }\n" + + " }\n" + + " result: {\n" + + " CALL [18] {\n" + + " function: _+_\n" + + " args: {\n" + + " IDENT [19] {\n" + + " name: @r0\n" + + " }\n" + + " IDENT [20] {\n" + + " name: @r0\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + " IDENT [21] {\n" + + " name: @r1\n" + + " }\n" + + " }\n" + + " }\n" + + " IDENT [22] {\n" + + " name: @r1\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + "}"); + } + + private enum CseTestCase { + SIZE_1("size([1,2]) + size([1,2]) + 1 == 5", "cel.bind(@r0, size([1, 2]), @r0 + @r0) + 1 == 5"), + SIZE_2( + "2 + size([1,2]) + size([1,2]) + 1 == 7", + "cel.bind(@r0, size([1, 2]), 2 + @r0 + @r0) + 1 == 7"), + SIZE_3( + "size([0]) + size([0]) + size([1,2]) + size([1,2]) == 6", + "cel.bind(@r1, size([1, 2]), cel.bind(@r0, size([0]), @r0 + @r0) + @r1 + @r1) == 6"), + SIZE_4( + "5 + size([0]) + size([0]) + size([1,2]) + size([1,2]) + " + + "size([1,2,3]) + size([1,2,3]) == 17", + "cel.bind(@r2, size([1, 2, 3]), cel.bind(@r1, size([1, 2]), cel.bind(@r0, size([0]), 5 +" + + " @r0 + @r0) + @r1 + @r1) + @r2 + @r2) == 17"), + /** + * Unparsed form is: + * + *
+     * {@code
+     * cel.bind(@r0, timestamp(int(timestamp(1000000000))).getFullYear(),
+     *    cel.bind(@r3, timestamp(int(timestamp(75))),
+     *      cel.bind(@r2, timestamp(int(timestamp(200))).getFullYear(),
+     *        cel.bind(@r1, timestamp(int(timestamp(50))),
+     *          @r0 + @r3.getFullYear() + @r1.getFullYear() + @r0 + @r1.getSeconds()
+     *        ) + @r2 + @r2
+     *      ) + @r3.getMinutes()
+     *    ) + @r0
+     *) == 13934
+     * }
+     * 
+ */ + TIMESTAMP( + "timestamp(int(timestamp(1000000000))).getFullYear() +" + + " timestamp(int(timestamp(75))).getFullYear() + " + + " timestamp(int(timestamp(50))).getFullYear() + " + + " timestamp(int(timestamp(1000000000))).getFullYear() + " + + " timestamp(int(timestamp(50))).getSeconds() + " + + " timestamp(int(timestamp(200))).getFullYear() + " + + " timestamp(int(timestamp(200))).getFullYear() + " + + " timestamp(int(timestamp(75))).getMinutes() + " + + " timestamp(int(timestamp(1000000000))).getFullYear() == 13934", + "cel.bind(@r0, timestamp(int(timestamp(1000000000))).getFullYear(), " + + "cel.bind(@r3, timestamp(int(timestamp(75))), " + + "cel.bind(@r2, timestamp(int(timestamp(200))).getFullYear(), " + + "cel.bind(@r1, timestamp(int(timestamp(50))), " + + "@r0 + @r3.getFullYear() + @r1.getFullYear() + " + + "@r0 + @r1.getSeconds()) + @r2 + @r2) + @r3.getMinutes()) + @r0) == 13934"), + MAP_INDEX( + "{\"a\": 2}[\"a\"] + {\"a\": 2}[\"a\"] * {\"a\": 2}[\"a\"] == 6", + "cel.bind(@r0, {\"a\": 2}[\"a\"], @r0 + @r0 * @r0) == 6"), + /** + * Input map is: + * + *
{@code
+     * {
+     *    "a": { "b": 1 },
+     *    "c": { "b": 1 },
+     *    "d": {
+     *       "e": { "b": 1 }
+     *    },
+     *    "e":{
+     *       "e": { "b": 1 }
+     *    }
+     * }
+     * }
+ */ + NESTED_MAP_CONSTRUCTION( + "size({'a': {'b': 1}, 'c': {'b': 1}, 'd': {'e': {'b': 1}}, 'e': {'e': {'b': 1}}}) == 4", + "size(cel.bind(@r0, {\"b\": 1}, cel.bind(@r1, {\"e\": @r0}, {\"a\": @r0, \"c\": @r0, \"d\":" + + " @r1, \"e\": @r1}))) == 4"), + NESTED_LIST_CONSTRUCTION( + "size([1, [1,2,3,4], 2, [1,2,3,4], 5, [1,2,3,4], 7, [[1,2], [1,2,3,4]], [1,2]]) == 9", + "size(cel.bind(@r0, [1, 2, 3, 4], " + + "cel.bind(@r1, [1, 2], [1, @r0, 2, @r0, 5, @r0, 7, [@r1, @r0], @r1]))) == 9"), + SELECT( + "msg.single_int64 + msg.single_int64 == 6", + "cel.bind(@r0, msg.single_int64, @r0 + @r0) == 6"), + SELECT_NESTED( + "msg.oneof_type.payload.single_int64 + msg.oneof_type.payload.single_int32 + " + + "msg.oneof_type.payload.single_int64 + " + + "msg.single_int64 + msg.oneof_type.payload.oneof_type.payload.single_int64 == 31", + "cel.bind(@r0, msg.oneof_type.payload, " + + "cel.bind(@r1, @r0.single_int64, @r1 + @r0.single_int32 + @r1) + " + + "msg.single_int64 + @r0.oneof_type.payload.single_int64) == 31"), + SELECT_NESTED_MESSAGE_MAP_INDEX_1( + "msg.oneof_type.payload.map_int32_int64[1] + " + + "msg.oneof_type.payload.map_int32_int64[1] + " + + "msg.oneof_type.payload.map_int32_int64[1] == 15", + "cel.bind(@r0, msg.oneof_type.payload.map_int32_int64[1], @r0 + @r0 + @r0) == 15"), + SELECT_NESTED_MESSAGE_MAP_INDEX_2( + "msg.oneof_type.payload.map_int32_int64[0] + " + + "msg.oneof_type.payload.map_int32_int64[1] + " + + "msg.oneof_type.payload.map_int32_int64[2] == 8", + "cel.bind(@r0, msg.oneof_type.payload.map_int32_int64, @r0[0] + @r0[1] + @r0[2]) == 8"), + TERNARY( + "(msg.single_int64 > 0 ? msg.single_int64 : 0) == 3", + "cel.bind(@r0, msg.single_int64, (@r0 > 0) ? @r0 : 0) == 3"), + TERNARY_BIND_RHS_ONLY( + "false ? false : (msg.single_int64) + ((msg.single_int64 + 1) * 2) == 11", + "false ? false : (cel.bind(@r0, msg.single_int64, @r0 + (@r0 + 1) * 2) == 11)"), + NESTED_TERNARY( + "(msg.single_int64 > 0 ? (msg.single_int32 > 0 ? " + + "msg.single_int64 + msg.single_int32 : 0) : 0) == 8", + "cel.bind(@r0, msg.single_int64, (@r0 > 0) ? " + + "cel.bind(@r1, msg.single_int32, (@r1 > 0) ? (@r0 + @r1) : 0) : 0) == 8"), + MULTIPLE_MACROS( + "size([[1].exists(x, x > 0)]) + size([[1].exists(x, x > 0)]) + " + + "size([[2].exists(x, x > 1)]) + size([[2].exists(x, x > 1)]) == 4", + "cel.bind(@r1, size([[2].exists(x, x > 1)]), " + + "cel.bind(@r0, size([[1].exists(x, x > 0)]), @r0 + @r0) + @r1 + @r1) == 4"), + NESTED_MACROS( + "[1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [[2, 3, 4], [2, 3, 4], [2, 3, 4]]", + "cel.bind(@r0, [1, 2, 3], @r0.map(i, @r0.map(i, i + 1))) == cel.bind(@r1, [2, 3, 4], [@r1," + + " @r1, @r1])"), + MACRO_SHADOWED_VARIABLE( + // Macro variable `x` in .exists is shadowed. + // This is left intact due to the fact that loop condition is not optimized at the moment. + "[x - 1 > 3 ? x - 1 : 5].exists(x, x - 1 > 3) || x - 1 > 3", + "cel.bind(@r0, x - 1, cel.bind(@r1, @r0 > 3, [@r1 ? @r0 : 5].exists(x, x - 1 > 3) ||" + + " @r1))"); + + private final String source; + private final String unparsed; + + CseTestCase(String source, String unparsed) { + this.source = source; + this.unparsed = unparsed; + } + } + + @Test + public void cse_withMacroMapPopulated_success(@TestParameter CseTestCase testCase) + throws Exception { + CelAbstractSyntaxTree ast = CEL.compile(testCase.source).getAst(); + + CelAbstractSyntaxTree optimizedAst = CEL_OPTIMIZER.optimize(ast); + + assertThat( + CEL.createProgram(optimizedAst) + .eval(ImmutableMap.of("msg", TEST_ALL_TYPES_INPUT, "x", 5L))) + .isEqualTo(true); + assertThat(CEL_UNPARSER.unparse(optimizedAst)).isEqualTo(testCase.unparsed); + } + + @Test + public void cse_withoutMacroMap_success(@TestParameter CseTestCase testCase) throws Exception { + Cel celWithoutMacroMap = + newCelBuilder() + .setOptions( + CelOptions.current().populateMacroCalls(false).enableTimestampEpoch(true).build()) + .build(); + CelAbstractSyntaxTree ast = celWithoutMacroMap.compile(testCase.source).getAst(); + + CelAbstractSyntaxTree optimizedAst = + CelOptimizerFactory.standardCelOptimizerBuilder(celWithoutMacroMap) + .addAstOptimizers(SubexpressionOptimizer.getInstance()) + .build() + .optimize(ast); + + assertThat(optimizedAst.getSource().getMacroCalls()).isEmpty(); + assertThat( + celWithoutMacroMap + .createProgram(optimizedAst) + .eval(ImmutableMap.of("msg", TEST_ALL_TYPES_INPUT, "x", 5L))) + .isEqualTo(true); + } + + @Test + // Nothing to optimize + @TestParameters("{source: 'size(\"hello\")'}") + // Constants and identifiers + @TestParameters("{source: '2 + 2 + 2 + 2'}") + @TestParameters("{source: 'x + x + x + x'}") + @TestParameters("{source: 'true == true && false == false'}") + // Constants and identifiers within a function + @TestParameters("{source: 'size(\"hello\" + \"hello\" + \"hello\")'}") + @TestParameters("{source: 'string(x + x + x)'}") + // Non-standard functions are considered non-pure for time being + @TestParameters("{source: 'custom_func(1) + custom_func(1)'}") + // Duplicated but nested calls. + @TestParameters("{source: 'int(timestamp(int(timestamp(1000000000))))'}") + // Loop condition is not optimized at the moment. This requires mangling. + @TestParameters("{source: '[\"foo\", \"bar\"].map(x, [x + x, x + x]).map(x, [x + x, x + x])'}") + // Ternary with presence test is not supported yet. + @TestParameters("{source: 'has(msg.single_any) ? msg.single_any : 10'}") + public void cse_noop(String source) throws Exception { + CelAbstractSyntaxTree ast = CEL.compile(source).getAst(); + + CelAbstractSyntaxTree optimizedAst = CEL_OPTIMIZER.optimize(ast); + + assertThat(ast.getExpr()).isEqualTo(optimizedAst.getExpr()); + assertThat(CEL_UNPARSER.unparse(optimizedAst)).isEqualTo(source); + } + + @Test + public void cse_largeCalcExpr() throws Exception { + StringBuilder sb = new StringBuilder(); + int limit = 40; + for (int i = 0; i < limit; i++) { + sb.append("size([1]) + "); + sb.append("size([1,2]) + "); + sb.append("size([1,2,3]) +"); + sb.append("size([1,2,3,4])"); + if (i < limit - 1) { + sb.append("+"); + } + } + CelAbstractSyntaxTree ast = CEL.compile(sb.toString()).getAst(); + + CelAbstractSyntaxTree optimizedAst = CEL_OPTIMIZER.optimize(ast); + + assertThat(CEL_UNPARSER.unparse(optimizedAst)) + .isEqualTo( + "cel.bind(@r3, size([1, 2, 3, 4]), cel.bind(@r2, size([1, 2, 3]), cel.bind(@r1," + + " size([1, 2]), cel.bind(@r0, size([1]), @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2" + + " + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 +" + + " @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 +" + + " @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 +" + + " @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 +" + + " @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 +" + + " @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 +" + + " @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 +" + + " @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 +" + + " @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 +" + + " @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 +" + + " @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 +" + + " @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0) + @r1) + @r2) + @r3)"); + assertThat(CEL.createProgram(optimizedAst).eval()).isEqualTo(400L); + } + + @Test + public void cse_largeNestedBinds() throws Exception { + StringBuilder sb = new StringBuilder(); + int limit = 50; + for (int i = 0; i < limit; i++) { + sb.append(String.format("size([%d, %d]) + ", i, i + 1)); + sb.append(String.format("size([%d, %d]) ", i, i + 1)); + if (i < limit - 1) { + sb.append("+"); + } + } + CelAbstractSyntaxTree ast = CEL.compile(sb.toString()).getAst(); + + CelAbstractSyntaxTree optimizedAst = CEL_OPTIMIZER.optimize(ast); + + assertThat(CEL_UNPARSER.unparse(optimizedAst)) + .isEqualTo( + "cel.bind(@r49, size([49, 50]), cel.bind(@r48, size([48, 49]), cel.bind(@r47, size([47," + + " 48]), cel.bind(@r46, size([46, 47]), cel.bind(@r45, size([45, 46])," + + " cel.bind(@r44, size([44, 45]), cel.bind(@r43, size([43, 44]), cel.bind(@r42," + + " size([42, 43]), cel.bind(@r41, size([41, 42]), cel.bind(@r40, size([40, 41])," + + " cel.bind(@r39, size([39, 40]), cel.bind(@r38, size([38, 39]), cel.bind(@r37," + + " size([37, 38]), cel.bind(@r36, size([36, 37]), cel.bind(@r35, size([35, 36])," + + " cel.bind(@r34, size([34, 35]), cel.bind(@r33, size([33, 34]), cel.bind(@r32," + + " size([32, 33]), cel.bind(@r31, size([31, 32]), cel.bind(@r30, size([30, 31])," + + " cel.bind(@r29, size([29, 30]), cel.bind(@r28, size([28, 29]), cel.bind(@r27," + + " size([27, 28]), cel.bind(@r26, size([26, 27]), cel.bind(@r25, size([25, 26])," + + " cel.bind(@r24, size([24, 25]), cel.bind(@r23, size([23, 24]), cel.bind(@r22," + + " size([22, 23]), cel.bind(@r21, size([21, 22]), cel.bind(@r20, size([20, 21])," + + " cel.bind(@r19, size([19, 20]), cel.bind(@r18, size([18, 19]), cel.bind(@r17," + + " size([17, 18]), cel.bind(@r16, size([16, 17]), cel.bind(@r15, size([15, 16])," + + " cel.bind(@r14, size([14, 15]), cel.bind(@r13, size([13, 14]), cel.bind(@r12," + + " size([12, 13]), cel.bind(@r11, size([11, 12]), cel.bind(@r10, size([10, 11])," + + " cel.bind(@r9, size([9, 10]), cel.bind(@r8, size([8, 9]), cel.bind(@r7, size([7," + + " 8]), cel.bind(@r6, size([6, 7]), cel.bind(@r5, size([5, 6]), cel.bind(@r4," + + " size([4, 5]), cel.bind(@r3, size([3, 4]), cel.bind(@r2, size([2, 3])," + + " cel.bind(@r1, size([1, 2]), cel.bind(@r0, size([0, 1]), @r0 + @r0) + @r1 + @r1)" + + " + @r2 + @r2) + @r3 + @r3) + @r4 + @r4) + @r5 + @r5) + @r6 + @r6) + @r7 + @r7) +" + + " @r8 + @r8) + @r9 + @r9) + @r10 + @r10) + @r11 + @r11) + @r12 + @r12) + @r13 +" + + " @r13) + @r14 + @r14) + @r15 + @r15) + @r16 + @r16) + @r17 + @r17) + @r18 +" + + " @r18) + @r19 + @r19) + @r20 + @r20) + @r21 + @r21) + @r22 + @r22) + @r23 +" + + " @r23) + @r24 + @r24) + @r25 + @r25) + @r26 + @r26) + @r27 + @r27) + @r28 +" + + " @r28) + @r29 + @r29) + @r30 + @r30) + @r31 + @r31) + @r32 + @r32) + @r33 +" + + " @r33) + @r34 + @r34) + @r35 + @r35) + @r36 + @r36) + @r37 + @r37) + @r38 +" + + " @r38) + @r39 + @r39) + @r40 + @r40) + @r41 + @r41) + @r42 + @r42) + @r43 +" + + " @r43) + @r44 + @r44) + @r45 + @r45) + @r46 + @r46) + @r47 + @r47) + @r48 +" + + " @r48) + @r49 + @r49)"); + assertThat(CEL.createProgram(optimizedAst).eval()).isEqualTo(200L); + } + + @Test + public void cse_largeNestedMacro() throws Exception { + StringBuilder sb = new StringBuilder(); + sb.append("size([1,2,3]"); + int limit = 8; + for (int i = 0; i < limit; i++) { + sb.append(".map(i, [1, 2, 3]"); + } + for (int i = 0; i < limit; i++) { + sb.append(")"); + } + sb.append(")"); + String nestedMapCallExpr = sb.toString(); // size([1,2,3].map(i, [1,2,3].map(i, [1,2,3].map(... + // Add this large macro call 8 times + for (int i = 0; i < limit; i++) { + sb.append("+"); + sb.append(nestedMapCallExpr); + } + CelAbstractSyntaxTree ast = CEL.compile(sb.toString()).getAst(); + + CelAbstractSyntaxTree optimizedAst = CEL_OPTIMIZER.optimize(ast); + + assertThat(CEL_UNPARSER.unparse(optimizedAst)) + .isEqualTo( + "cel.bind(@r0, [1, 2, 3], cel.bind(@r1, size(@r0.map(i, @r0.map(i, @r0.map(i," + + " @r0.map(i, @r0.map(i, @r0.map(i, @r0.map(i, @r0.map(i, [1, 2, 3]))))))))), @r1" + + " + @r1 + @r1 + @r1 + @r1 + @r1 + @r1 + @r1 + @r1))"); + assertThat(CEL.createProgram(optimizedAst).eval()).isEqualTo(27); + } + + @Test + public void cse_applyConstFoldingAfter() throws Exception { + CelAbstractSyntaxTree ast = + CEL.compile("size([1+1+1]) + size([1+1+1]) + size([1,1+1+1]) + size([1,1+1+1]) + x") + .getAst(); + CelOptimizer optimizer = + CelOptimizerFactory.standardCelOptimizerBuilder(CEL) + .addAstOptimizers( + SubexpressionOptimizer.newInstance( + SubexpressionOptimizerOptions.newBuilder().populateMacroCalls(true).build()), + ConstantFoldingOptimizer.INSTANCE) + .build(); + + CelAbstractSyntaxTree optimizedAst = optimizer.optimize(ast); + + assertThat(optimizedAst.getExpr()) + .isEqualTo( + CelExpr.ofCallExpr( + 1L, + Optional.empty(), + Operator.ADD.getFunction(), + ImmutableList.of( + CelExpr.ofConstantExpr(2L, CelConstant.ofValue(6L)), + CelExpr.ofIdentExpr(3L, "x")))); + assertThat(CEL_UNPARSER.unparse(optimizedAst)).isEqualTo("6 + x"); + } + + @Test + public void maxIterationLimitReached_throws() throws Exception { + StringBuilder largeExprBuilder = new StringBuilder(); + int maxIterationLimit = 100; + for (int i = 0; i < maxIterationLimit; i++) { + largeExprBuilder.append("[1,2]"); + if (i < maxIterationLimit - 1) { + largeExprBuilder.append("+"); + } + } + CelAbstractSyntaxTree ast = CEL.compile(largeExprBuilder.toString()).getAst(); + + CelOptimizationException e = + assertThrows( + CelOptimizationException.class, + () -> + CelOptimizerFactory.standardCelOptimizerBuilder(CEL) + .addAstOptimizers( + SubexpressionOptimizer.newInstance( + SubexpressionOptimizerOptions.newBuilder() + .maxIterationLimit(maxIterationLimit) + .build())) + .build() + .optimize(ast)); + assertThat(e).hasMessageThat().isEqualTo("Optimization failure: Max iteration count reached."); + } +} From 5a7cbab74dee635cf5bc0df6dcb4b0088e391932 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Fri, 19 Jan 2024 10:44:39 -0800 Subject: [PATCH 009/486] Perform CSE on comprehension loop step by mangling identifier names PiperOrigin-RevId: 599877299 --- .../dev/cel/optimizer/CelAstOptimizer.java | 30 +++ .../java/dev/cel/optimizer/MutableAst.java | 145 +++++++++++++ .../optimizers/SubexpressionOptimizer.java | 11 +- .../dev/cel/optimizer/MutableAstTest.java | 191 ++++++++++++++++++ .../SubexpressionOptimizerTest.java | 33 +-- 5 files changed, 392 insertions(+), 18 deletions(-) diff --git a/optimizer/src/main/java/dev/cel/optimizer/CelAstOptimizer.java b/optimizer/src/main/java/dev/cel/optimizer/CelAstOptimizer.java index 9a9f22c94..c7f166460 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/CelAstOptimizer.java +++ b/optimizer/src/main/java/dev/cel/optimizer/CelAstOptimizer.java @@ -70,6 +70,36 @@ default CelAbstractSyntaxTree replaceSubtreeWithNewBindMacro( ast, varName, varInit, resultExpr, exprIdToReplace); } + /** + * Replaces all comprehension identifier names with a unique name based on the given prefix. + * + *

The purpose of this is to avoid errors that can be caused by shadowed variables while + * augmenting an AST. As an example: {@code [2, 3].exists(x, x - 1 > 3) || x - 1 > 3}. Note that + * the scoping of `x - 1` is different between th two LOGICAL_OR branches. Iteration variable `x` + * in `exists` will be mangled to {@code [2, 3].exists(@c0, @c0 - 1 > 3) || x - 1 > 3} to avoid + * erroneously extracting x - 1 as common subexpression. + * + *

The expression IDs are not modified when the identifier names are changed. + * + *

Iteration variables in comprehensions are numbered based on their comprehension nesting + * levels. Examples: + * + *

    + *
  • {@code [true].exists(i, i) && [true].exists(j, j)} -> {@code [true].exists(@c0, @c0) && + * [true].exists(@c0, @c0)} // Note that i,j gets replaced to the same @c0 in this example + *
  • {@code [true].exists(i, i && [true].exists(j, j))} -> {@code [true].exists(@c0, @c0 && + * [true].exists(@c1, @c1))} + *
+ * + * @param ast AST to mutate + * @param newIdentPrefix Prefix to use for new identifier names. For example, providing @c will + * produce @c0, @c1, @c2... as new names. + */ + default CelAbstractSyntaxTree mangleComprehensionIdentifierNames( + CelAbstractSyntaxTree ast, String newIdentPrefix) { + return MutableAst.mangleComprehensionIdentifierNames(ast, newIdentPrefix); + } + /** Sets all expr IDs in the expression tree to 0. */ default CelExpr clearExprIds(CelExpr celExpr) { return MutableAst.clearExprIds(celExpr); diff --git a/optimizer/src/main/java/dev/cel/optimizer/MutableAst.java b/optimizer/src/main/java/dev/cel/optimizer/MutableAst.java index f1f579252..45cbb0ff6 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/MutableAst.java +++ b/optimizer/src/main/java/dev/cel/optimizer/MutableAst.java @@ -30,20 +30,26 @@ import dev.cel.common.ast.CelExpr.CelCreateList; import dev.cel.common.ast.CelExpr.CelCreateMap; import dev.cel.common.ast.CelExpr.CelCreateStruct; +import dev.cel.common.ast.CelExpr.CelIdent; import dev.cel.common.ast.CelExpr.CelSelect; import dev.cel.common.ast.CelExpr.ExprKind.Kind; import dev.cel.common.ast.CelExprFactory; import dev.cel.common.ast.CelExprIdGeneratorFactory; import dev.cel.common.ast.CelExprIdGeneratorFactory.ExprIdGenerator; import dev.cel.common.ast.CelExprIdGeneratorFactory.StableIdGenerator; +import dev.cel.common.navigation.CelNavigableAst; import dev.cel.common.navigation.CelNavigableExpr; +import dev.cel.common.navigation.CelNavigableExpr.TraversalOrder; import java.util.Map.Entry; import java.util.NoSuchElementException; +import java.util.Optional; /** MutableAst contains logic for mutating a {@link CelExpr}. */ @Internal final class MutableAst { private static final int MAX_ITERATION_COUNT = 1000; + private static final ExprIdGenerator NO_OP_ID_GENERATOR = id -> id; + private final CelExpr.Builder newExpr; private final ExprIdGenerator celExprIdGenerator; private int iterationCount; @@ -160,6 +166,132 @@ static CelAbstractSyntaxTree renumberIdsConsecutively(CelAbstractSyntaxTree ast) return CelAbstractSyntaxTree.newParsedAst(root.build(), newSource); } + static CelAbstractSyntaxTree mangleComprehensionIdentifierNames( + CelAbstractSyntaxTree ast, String newIdentPrefix) { + int iterCount; + CelNavigableAst newNavigableAst = CelNavigableAst.fromAst(ast); + for (iterCount = 0; iterCount < MAX_ITERATION_COUNT; iterCount++) { + Optional maybeComprehensionExpr = + newNavigableAst + .getRoot() + // This is important - mangling needs to happen bottom-up to avoid stepping over + // shadowed variables that are not part of the comprehension being mangled. + .allNodes(TraversalOrder.POST_ORDER) + .filter(node -> node.getKind().equals(Kind.COMPREHENSION)) + .filter(node -> !node.expr().comprehension().iterVar().startsWith(newIdentPrefix)) + .findAny(); + if (!maybeComprehensionExpr.isPresent()) { + break; + } + + CelExpr.Builder comprehensionExpr = maybeComprehensionExpr.get().expr().toBuilder(); + String iterVar = comprehensionExpr.comprehension().iterVar(); + int comprehensionNestingLevel = countComprehensionNestingLevel(maybeComprehensionExpr.get()); + String mangledVarName = newIdentPrefix + comprehensionNestingLevel; + + CelExpr.Builder mutatedComprehensionExpr = + mangleIdentsInComprehensionExpr( + newNavigableAst.getAst().getExpr().toBuilder(), + comprehensionExpr, + iterVar, + mangledVarName); + // Repeat the mangling process for the macro source. + CelSource newSource = + mangleIdentsInMacroSource( + newNavigableAst.getAst(), + mutatedComprehensionExpr, + iterVar, + mangledVarName, + comprehensionExpr.id()); + + newNavigableAst = + CelNavigableAst.fromAst( + CelAbstractSyntaxTree.newParsedAst(mutatedComprehensionExpr.build(), newSource)); + } + + if (iterCount >= MAX_ITERATION_COUNT) { + throw new IllegalStateException("Max iteration count reached."); + } + + return newNavigableAst.getAst(); + } + + private static CelExpr.Builder mangleIdentsInComprehensionExpr( + CelExpr.Builder root, + CelExpr.Builder comprehensionExpr, + String originalIterVar, + String mangledVarName) { + int iterCount; + for (iterCount = 0; iterCount < MAX_ITERATION_COUNT; iterCount++) { + Optional identToMangle = + CelNavigableExpr.fromExpr(comprehensionExpr.comprehension().loopStep()) + .descendants() + .map(CelNavigableExpr::expr) + .filter(node -> node.identOrDefault().name().equals(originalIterVar)) + .findAny(); + if (!identToMangle.isPresent()) { + break; + } + + comprehensionExpr = + replaceSubtreeImpl( + NO_OP_ID_GENERATOR, + comprehensionExpr, + CelExpr.newBuilder().setIdent(CelIdent.newBuilder().setName(mangledVarName).build()), + identToMangle.get().id()); + } + + if (iterCount >= MAX_ITERATION_COUNT) { + throw new IllegalStateException("Max iteration count reached."); + } + + return replaceSubtreeImpl( + NO_OP_ID_GENERATOR, + root, + comprehensionExpr.setComprehension( + comprehensionExpr.comprehension().toBuilder().setIterVar(mangledVarName).build()), + comprehensionExpr.id()); + } + + private static CelSource mangleIdentsInMacroSource( + CelAbstractSyntaxTree ast, + CelExpr.Builder mutatedComprehensionExpr, + String originalIterVar, + String mangledVarName, + long originalComprehensionId) { + if (!ast.getSource().getMacroCalls().containsKey(originalComprehensionId)) { + return ast.getSource(); + } + + // First, normalize the macro source. + // ex: [x].exists(x, [x].exists(x, x == 1)) -> [x].exists(x, [@c1].exists(x, @c0 == 1)). + CelSource.Builder newSource = + normalizeMacroSource(ast.getSource(), -1, mutatedComprehensionExpr, (id) -> id).toBuilder(); + + // Note that in the above example, the iteration variable is not replaced after normalization. + // This is because populating a macro call map upon parse generates a new unique identifier + // that does not exist in the main AST. Thus, we need to manually replace the identifier. + CelExpr.Builder macroExpr = newSource.getMacroCalls().get(originalComprehensionId).toBuilder(); + // By convention, the iteration variable is always the first argument of the + // macro call expression. + CelExpr identToMangle = macroExpr.call().args().get(0); + if (!identToMangle.identOrDefault().name().equals(originalIterVar)) { + throw new IllegalStateException( + String.format( + "Expected %s for iteration variable but got %s instead.", + identToMangle.identOrDefault().name(), originalIterVar)); + } + macroExpr = + replaceSubtreeImpl( + NO_OP_ID_GENERATOR, + macroExpr, + CelExpr.newBuilder().setIdent(CelIdent.newBuilder().setName(mangledVarName).build()), + identToMangle.id()); + + newSource.addMacroCalls(originalComprehensionId, macroExpr.build()); + return newSource.build(); + } + private static BindMacro newBindMacro( String varName, CelExpr varInit, CelExpr resultExpr, StableIdGenerator stableIdGenerator) { // Renumber incoming expression IDs in the init and result expression to avoid collision with @@ -344,6 +476,19 @@ private static long getMaxId(CelExpr newExpr) { .orElseThrow(NoSuchElementException::new); } + private static int countComprehensionNestingLevel(CelNavigableExpr comprehensionExpr) { + int nestedLevel = 0; + Optional maybeParent = comprehensionExpr.parent(); + while (maybeParent.isPresent()) { + if (maybeParent.get().getKind().equals(Kind.COMPREHENSION)) { + nestedLevel++; + } + + maybeParent = maybeParent.get().parent(); + } + return nestedLevel; + } + private CelExpr.Builder visit(CelExpr.Builder expr) { if (++iterationCount > MAX_ITERATION_COUNT) { throw new IllegalStateException("Max iteration count reached."); diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java index 88ae694e6..d2f1ae7e6 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java @@ -63,6 +63,7 @@ public class SubexpressionOptimizer implements CelAstOptimizer { private static final SubexpressionOptimizer INSTANCE = new SubexpressionOptimizer(SubexpressionOptimizerOptions.newBuilder().build()); private static final String BIND_IDENTIFIER_PREFIX = "@r"; + private static final String MANGLED_COMPREHENSION_IDENTIFIER_PREFIX = "@c"; private static final ImmutableSet CSE_ALLOWED_FUNCTIONS = Streams.concat( stream(Operator.values()).map(Operator::getFunction), @@ -88,8 +89,11 @@ public static SubexpressionOptimizer newInstance(SubexpressionOptimizerOptions c @Override public CelAbstractSyntaxTree optimize(CelNavigableAst navigableAst, Cel cel) { - CelAbstractSyntaxTree astToModify = navigableAst.getAst(); + CelAbstractSyntaxTree astToModify = + mangleComprehensionIdentifierNames( + navigableAst.getAst(), MANGLED_COMPREHENSION_IDENTIFIER_PREFIX); CelSource sourceToModify = astToModify.getSource(); + int bindIdentifierIndex = 0; int iterCount; for (iterCount = 0; iterCount < cseOptions.maxIterationLimit(); iterCount++) { @@ -247,9 +251,10 @@ private static boolean isWithinInlineableComprehension(CelNavigableExpr expr) { if (parent.getKind().equals(Kind.COMPREHENSION)) { return Streams.concat( // If the expression is within a comprehension, it is eligible for CSE iff is in - // result or iterRange. While result is not human authored, it needs to be included - // to extract subexpressions that are already in cel.bind macro. + // result, loopStep or iterRange. While result is not human authored, it needs to be + // included to extract subexpressions that are already in cel.bind macro. CelNavigableExpr.fromExpr(parent.expr().comprehension().result()).descendants(), + CelNavigableExpr.fromExpr(parent.expr().comprehension().loopStep()).descendants(), CelNavigableExpr.fromExpr(parent.expr().comprehension().iterRange()).allNodes()) .filter( node -> diff --git a/optimizer/src/test/java/dev/cel/optimizer/MutableAstTest.java b/optimizer/src/test/java/dev/cel/optimizer/MutableAstTest.java index 587c3c71d..8f79838c3 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/MutableAstTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/MutableAstTest.java @@ -652,6 +652,197 @@ public void comprehension_replaceLoopStep() throws Exception { assertConsistentMacroCalls(ast); } + @Test + public void mangleComprehensionVariable_singleMacro() throws Exception { + CelAbstractSyntaxTree ast = CEL.compile("[false].exists(i, i)").getAst(); + + CelAbstractSyntaxTree mangledAst = MutableAst.mangleComprehensionIdentifierNames(ast, "@c"); + + assertThat(mangledAst.getExpr().toString()) + .isEqualTo( + "COMPREHENSION [13] {\n" + + " iter_var: @c0\n" + + " iter_range: {\n" + + " CREATE_LIST [1] {\n" + + " elements: {\n" + + " CONSTANT [2] { value: false }\n" + + " }\n" + + " }\n" + + " }\n" + + " accu_var: __result__\n" + + " accu_init: {\n" + + " CONSTANT [6] { value: false }\n" + + " }\n" + + " loop_condition: {\n" + + " CALL [9] {\n" + + " function: @not_strictly_false\n" + + " args: {\n" + + " CALL [8] {\n" + + " function: !_\n" + + " args: {\n" + + " IDENT [7] {\n" + + " name: __result__\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + " loop_step: {\n" + + " CALL [11] {\n" + + " function: _||_\n" + + " args: {\n" + + " IDENT [10] {\n" + + " name: __result__\n" + + " }\n" + + " IDENT [5] {\n" + + " name: @c0\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + " result: {\n" + + " IDENT [12] {\n" + + " name: __result__\n" + + " }\n" + + " }\n" + + "}"); + assertThat(CEL_UNPARSER.unparse(mangledAst)).isEqualTo("[false].exists(@c0, @c0)"); + assertThat(CEL.createProgram(CEL.check(mangledAst).getAst()).eval()).isEqualTo(false); + assertConsistentMacroCalls(ast); + } + + @Test + public void mangleComprehensionVariable_nestedMacroWithShadowedVariables() throws Exception { + CelAbstractSyntaxTree ast = CEL.compile("[x].exists(x, [x].exists(x, x == 1))").getAst(); + + CelAbstractSyntaxTree mangledAst = MutableAst.mangleComprehensionIdentifierNames(ast, "@c"); + + assertThat(mangledAst.getExpr().toString()) + .isEqualTo( + "COMPREHENSION [27] {\n" + + " iter_var: @c0\n" + + " iter_range: {\n" + + " CREATE_LIST [1] {\n" + + " elements: {\n" + + " IDENT [2] {\n" + + " name: x\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + " accu_var: __result__\n" + + " accu_init: {\n" + + " CONSTANT [20] { value: false }\n" + + " }\n" + + " loop_condition: {\n" + + " CALL [23] {\n" + + " function: @not_strictly_false\n" + + " args: {\n" + + " CALL [22] {\n" + + " function: !_\n" + + " args: {\n" + + " IDENT [21] {\n" + + " name: __result__\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + " loop_step: {\n" + + " CALL [25] {\n" + + " function: _||_\n" + + " args: {\n" + + " IDENT [24] {\n" + + " name: __result__\n" + + " }\n" + + " COMPREHENSION [19] {\n" + + " iter_var: @c1\n" + + " iter_range: {\n" + + " CREATE_LIST [5] {\n" + + " elements: {\n" + + " IDENT [6] {\n" + + " name: @c0\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + " accu_var: __result__\n" + + " accu_init: {\n" + + " CONSTANT [12] { value: false }\n" + + " }\n" + + " loop_condition: {\n" + + " CALL [15] {\n" + + " function: @not_strictly_false\n" + + " args: {\n" + + " CALL [14] {\n" + + " function: !_\n" + + " args: {\n" + + " IDENT [13] {\n" + + " name: __result__\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + " loop_step: {\n" + + " CALL [17] {\n" + + " function: _||_\n" + + " args: {\n" + + " IDENT [16] {\n" + + " name: __result__\n" + + " }\n" + + " CALL [10] {\n" + + " function: _==_\n" + + " args: {\n" + + " IDENT [9] {\n" + + " name: @c1\n" + + " }\n" + + " CONSTANT [11] { value: 1 }\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + " result: {\n" + + " IDENT [18] {\n" + + " name: __result__\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + " result: {\n" + + " IDENT [26] {\n" + + " name: __result__\n" + + " }\n" + + " }\n" + + "}"); + + assertThat(CEL_UNPARSER.unparse(mangledAst)) + .isEqualTo("[x].exists(@c0, [@c0].exists(@c1, @c1 == 1))"); + assertThat(CEL.createProgram(CEL.check(mangledAst).getAst()).eval(ImmutableMap.of("x", 1))) + .isEqualTo(true); + assertConsistentMacroCalls(ast); + } + + @Test + public void mangleComprehensionVariable_hasMacro_noOp() throws Exception { + CelAbstractSyntaxTree ast = CEL.compile("has(msg.single_int64)").getAst(); + + CelAbstractSyntaxTree mangledAst = MutableAst.mangleComprehensionIdentifierNames(ast, "@c"); + + assertThat(CEL_UNPARSER.unparse(mangledAst)).isEqualTo("has(msg.single_int64)"); + assertThat( + CEL.createProgram(CEL.check(mangledAst).getAst()) + .eval(ImmutableMap.of("msg", TestAllTypes.getDefaultInstance()))) + .isEqualTo(false); + assertConsistentMacroCalls(ast); + } + /** * Asserts that the expressions that appears in source_info's macro calls are consistent with the * actual expr nodes in the AST. diff --git a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java index 157417504..79e04fc64 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java @@ -304,20 +304,25 @@ private enum CseTestCase { "cel.bind(@r0, msg.single_int64, (@r0 > 0) ? " + "cel.bind(@r1, msg.single_int32, (@r1 > 0) ? (@r0 + @r1) : 0) : 0) == 8"), MULTIPLE_MACROS( - "size([[1].exists(x, x > 0)]) + size([[1].exists(x, x > 0)]) + " - + "size([[2].exists(x, x > 1)]) + size([[2].exists(x, x > 1)]) == 4", - "cel.bind(@r1, size([[2].exists(x, x > 1)]), " - + "cel.bind(@r0, size([[1].exists(x, x > 0)]), @r0 + @r0) + @r1 + @r1) == 4"), + // Note that all of these have different iteration variables, but they are still logically + // the same. + "size([[1].exists(i, i > 0)]) + size([[1].exists(j, j > 0)]) + " + + "size([[2].exists(k, k > 1)]) + size([[2].exists(l, l > 1)]) == 4", + "cel.bind(@r1, size([[2].exists(@c0, @c0 > 1)]), " + + "cel.bind(@r0, size([[1].exists(@c0, @c0 > 0)]), @r0 + @r0) + @r1 + @r1) == 4"), NESTED_MACROS( "[1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [[2, 3, 4], [2, 3, 4], [2, 3, 4]]", - "cel.bind(@r0, [1, 2, 3], @r0.map(i, @r0.map(i, i + 1))) == cel.bind(@r1, [2, 3, 4], [@r1," - + " @r1, @r1])"), + "cel.bind(@r0, [1, 2, 3], @r0.map(@c0, @r0.map(@c1, @c1 + 1))) == " + + "cel.bind(@r1, [2, 3, 4], [@r1, @r1, @r1])"), MACRO_SHADOWED_VARIABLE( - // Macro variable `x` in .exists is shadowed. - // This is left intact due to the fact that loop condition is not optimized at the moment. "[x - 1 > 3 ? x - 1 : 5].exists(x, x - 1 > 3) || x - 1 > 3", - "cel.bind(@r0, x - 1, cel.bind(@r1, @r0 > 3, [@r1 ? @r0 : 5].exists(x, x - 1 > 3) ||" - + " @r1))"); + "cel.bind(@r0, x - 1, cel.bind(@r1, @r0 > 3, [@r1 ? @r0 : 5].exists(@c0, @c0 - 1 > 3) ||" + + " @r1))"), + MACRO_SHADOWED_VARIABLE_2( + "size([\"foo\", \"bar\"].map(x, [x + x, x + x]).map(x, [x + x, x + x])) == 2", + "size([\"foo\", \"bar\"].map(@c1, cel.bind(@r0, @c1 + @c1, [@r0, @r0]))" + + ".map(@c0, cel.bind(@r1, @c0 + @c0, [@r1, @r1]))) == 2"), + ; private final String source; private final String unparsed; @@ -379,8 +384,6 @@ public void cse_withoutMacroMap_success(@TestParameter CseTestCase testCase) thr @TestParameters("{source: 'custom_func(1) + custom_func(1)'}") // Duplicated but nested calls. @TestParameters("{source: 'int(timestamp(int(timestamp(1000000000))))'}") - // Loop condition is not optimized at the moment. This requires mangling. - @TestParameters("{source: '[\"foo\", \"bar\"].map(x, [x + x, x + x]).map(x, [x + x, x + x])'}") // Ternary with presence test is not supported yet. @TestParameters("{source: 'has(msg.single_any) ? msg.single_any : 10'}") public void cse_noop(String source) throws Exception { @@ -502,9 +505,9 @@ public void cse_largeNestedMacro() throws Exception { assertThat(CEL_UNPARSER.unparse(optimizedAst)) .isEqualTo( - "cel.bind(@r0, [1, 2, 3], cel.bind(@r1, size(@r0.map(i, @r0.map(i, @r0.map(i," - + " @r0.map(i, @r0.map(i, @r0.map(i, @r0.map(i, @r0.map(i, [1, 2, 3]))))))))), @r1" - + " + @r1 + @r1 + @r1 + @r1 + @r1 + @r1 + @r1 + @r1))"); + "cel.bind(@r0, [1, 2, 3], cel.bind(@r1, size(@r0.map(@c0, @r0.map(@c1, @r0.map(@c2, " + + "@r0.map(@c3, @r0.map(@c4, @r0.map(@c5, @r0.map(@c6, @r0.map(@c7, @r0))))))))), " + + "@r1 + @r1 + @r1 + @r1 + @r1 + @r1 + @r1 + @r1 + @r1))"); assertThat(CEL.createProgram(optimizedAst).eval()).isEqualTo(27); } From cd11baf909a722e28045ebdd9411902880102ab2 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Fri, 19 Jan 2024 11:14:04 -0800 Subject: [PATCH 010/486] Perform CSE on presence tests PiperOrigin-RevId: 599886305 --- .../dev/cel/common/ast/CelExprFormatter.java | 4 +- .../cel/common/ast/CelExprFormatterTest.java | 33 ++++++ .../dev/cel/optimizer/CelAstOptimizer.java | 18 +++ .../java/dev/cel/optimizer/MutableAst.java | 9 ++ .../optimizers/SubexpressionOptimizer.java | 54 ++++++++- .../SubexpressionOptimizerTest.java | 103 +++++++++++++++++- 6 files changed, 209 insertions(+), 12 deletions(-) diff --git a/common/src/main/java/dev/cel/common/ast/CelExprFormatter.java b/common/src/main/java/dev/cel/common/ast/CelExprFormatter.java index 8ab71c094..32e0233d0 100644 --- a/common/src/main/java/dev/cel/common/ast/CelExprFormatter.java +++ b/common/src/main/java/dev/cel/common/ast/CelExprFormatter.java @@ -122,8 +122,8 @@ private void appendSelect(CelExpr.CelSelect celSelect) { indent(); formatExpr(celSelect.operand()); outdent(); - append("."); - append(celSelect.field()); + appendWithoutIndent("."); + appendWithoutIndent(celSelect.field()); if (celSelect.testOnly()) { appendWithoutIndent("~presence_test"); } diff --git a/common/src/test/java/dev/cel/common/ast/CelExprFormatterTest.java b/common/src/test/java/dev/cel/common/ast/CelExprFormatterTest.java index 2c863b1f4..0efb890c1 100644 --- a/common/src/test/java/dev/cel/common/ast/CelExprFormatterTest.java +++ b/common/src/test/java/dev/cel/common/ast/CelExprFormatterTest.java @@ -336,4 +336,37 @@ public void comprehension() throws Exception { + " }\n" + "}"); } + + @Test + public void ternaryWithPresenceTest() throws Exception { + CelCompiler celCompiler = + CelCompilerFactory.standardCelCompilerBuilder() + .addMessageTypes(TestAllTypes.getDescriptor()) + .addVar("msg", StructTypeReference.create(TestAllTypes.getDescriptor().getFullName())) + .setStandardMacros(CelStandardMacro.STANDARD_MACROS) + .build(); + CelAbstractSyntaxTree ast = + celCompiler.compile("has(msg.single_any) ? msg.single_any : 10").getAst(); + + String formattedExpr = CelExprFormatter.format(ast.getExpr()); + + assertThat(formattedExpr) + .isEqualTo( + "CALL [5] {\n" + + " function: _?_:_\n" + + " args: {\n" + + " SELECT [4] {\n" + + " IDENT [2] {\n" + + " name: msg\n" + + " }.single_any~presence_test\n" + + " }\n" + + " SELECT [7] {\n" + + " IDENT [6] {\n" + + " name: msg\n" + + " }.single_any\n" + + " }\n" + + " CONSTANT [8] { value: 10 }\n" + + " }\n" + + "}"); + } } diff --git a/optimizer/src/main/java/dev/cel/optimizer/CelAstOptimizer.java b/optimizer/src/main/java/dev/cel/optimizer/CelAstOptimizer.java index c7f166460..feac4ce91 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/CelAstOptimizer.java +++ b/optimizer/src/main/java/dev/cel/optimizer/CelAstOptimizer.java @@ -26,6 +26,24 @@ public interface CelAstOptimizer { CelAbstractSyntaxTree optimize(CelNavigableAst navigableAst, Cel cel) throws CelOptimizationException; + /** + * Replaces a subtree in the given expression node. This operation is intended for AST + * optimization purposes. + * + *

This is a very dangerous operation. Callers should re-typecheck the mutated AST and + * additionally verify that the resulting AST is semantically valid. + * + *

All expression IDs will be renumbered in a stable manner to ensure there's no ID collision + * between the nodes. The renumbering occurs even if the subtree was not replaced. + * + * @param celExpr Original expression node to rewrite. + * @param newExpr New CelExpr to replace the subtree with. + * @param exprIdToReplace Expression id of the subtree that is getting replaced. + */ + default CelExpr replaceSubtree(CelExpr celExpr, CelExpr newExpr, long exprIdToReplace) { + return MutableAst.replaceSubtree(celExpr, newExpr, exprIdToReplace); + } + /** * Replaces a subtree in the given AST. This operation is intended for AST optimization purposes. * diff --git a/optimizer/src/main/java/dev/cel/optimizer/MutableAst.java b/optimizer/src/main/java/dev/cel/optimizer/MutableAst.java index 45cbb0ff6..1c3427169 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/MutableAst.java +++ b/optimizer/src/main/java/dev/cel/optimizer/MutableAst.java @@ -66,6 +66,15 @@ static CelExpr clearExprIds(CelExpr celExpr) { return renumberExprIds((unused) -> 0, celExpr.toBuilder()).build(); } + /** Mutates the given {@link CelExpr} by replacing a subtree at the given index. */ + static CelExpr replaceSubtree(CelExpr expr, CelExpr newExpr, long exprIdToReplace) { + return replaceSubtree( + CelAbstractSyntaxTree.newParsedAst(expr, CelSource.newBuilder().build()), + CelAbstractSyntaxTree.newParsedAst(newExpr, CelSource.newBuilder().build()), + exprIdToReplace) + .getExpr(); + } + /** * Mutates the given AST by replacing a subtree at a given index. * diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java index d2f1ae7e6..d7eda5b44 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java @@ -97,7 +97,7 @@ public CelAbstractSyntaxTree optimize(CelNavigableAst navigableAst, Cel cel) { int bindIdentifierIndex = 0; int iterCount; for (iterCount = 0; iterCount < cseOptions.maxIterationLimit(); iterCount++) { - CelNavigableExpr cseCandidate = findCseCandidate(astToModify).orElse(null); + CelExpr cseCandidate = findCseCandidate(astToModify).map(CelNavigableExpr::expr).orElse(null); if (cseCandidate == null) { break; } @@ -107,7 +107,7 @@ public CelAbstractSyntaxTree optimize(CelNavigableAst navigableAst, Cel cel) { // Using the CSE candidate, fetch all semantically equivalent subexpressions ahead of time. ImmutableList allCseCandidates = - getAllCseCandidatesStream(astToModify, cseCandidate.expr()).collect(toImmutableList()); + getAllCseCandidatesStream(astToModify, cseCandidate).collect(toImmutableList()); // Replace all CSE candidates with new bind identifier for (CelExpr semanticallyEqualNode : allCseCandidates) { @@ -142,7 +142,7 @@ public CelAbstractSyntaxTree optimize(CelNavigableAst navigableAst, Cel cel) { // Insert the new bind call astToModify = replaceSubtreeWithNewBindMacro( - astToModify, bindIdentifier, cseCandidate.expr(), lca.expr(), lca.id()); + astToModify, bindIdentifier, cseCandidate, lca.expr(), lca.id()); // Retain the existing macro calls in case if the bind identifiers are replacing a subtree // that contains a comprehension. @@ -224,8 +224,8 @@ private Optional findCseCandidate(CelAbstractSyntaxTree ast) { .collect(toImmutableList()); for (CelNavigableExpr node : allNodes) { - // Strip out all IDs to test equivalence - CelExpr celExpr = clearExprIds(node.expr()); + // Normalize the expr to test semantic equivalence. + CelExpr celExpr = normalizeForEquality(node.expr()); if (encounteredNodes.contains(celExpr)) { return Optional.of(node); } @@ -240,6 +240,7 @@ private static boolean canEliminate(CelNavigableExpr navigableExpr) { return !navigableExpr.getKind().equals(Kind.CONSTANT) && !navigableExpr.getKind().equals(Kind.IDENT) && !navigableExpr.expr().identOrDefault().name().startsWith(BIND_IDENTIFIER_PREFIX) + && !navigableExpr.expr().selectOrDefault().testOnly() && isAllowedFunction(navigableExpr) && isWithinInlineableComprehension(navigableExpr); } @@ -271,7 +272,7 @@ private static boolean isWithinInlineableComprehension(CelNavigableExpr expr) { } private boolean areSemanticallyEqual(CelExpr expr1, CelExpr expr2) { - return clearExprIds(expr1).equals(clearExprIds(expr2)); + return normalizeForEquality(expr1).equals(normalizeForEquality(expr2)); } private static boolean isAllowedFunction(CelNavigableExpr navigableExpr) { @@ -282,6 +283,47 @@ private static boolean isAllowedFunction(CelNavigableExpr navigableExpr) { return true; } + /** + * Converts the {@link CelExpr} to make it suitable for performing semantically equals check in + * {@link #areSemanticallyEqual(CelExpr, CelExpr)}. + * + *

Specifically, this will: + * + *

    + *
  • Set all expr IDs in the expression tree to 0. + *
  • Strip all presence tests (i.e: testOnly is marked as false on {@link + * CelExpr.ExprKind.Kind#SELECT} + *
+ */ + private CelExpr normalizeForEquality(CelExpr celExpr) { + int iterCount; + for (iterCount = 0; iterCount < cseOptions.maxIterationLimit(); iterCount++) { + CelExpr presenceTestExpr = + CelNavigableExpr.fromExpr(celExpr) + .allNodes() + .map(CelNavigableExpr::expr) + .filter(expr -> expr.selectOrDefault().testOnly()) + .findAny() + .orElse(null); + if (presenceTestExpr == null) { + break; + } + + CelExpr newExpr = + presenceTestExpr.toBuilder() + .setSelect(presenceTestExpr.select().toBuilder().setTestOnly(false).build()) + .build(); + + celExpr = replaceSubtree(celExpr, newExpr, newExpr.id()); + } + + if (iterCount >= cseOptions.maxIterationLimit()) { + throw new IllegalStateException("Max iteration count reached."); + } + + return clearExprIds(celExpr); + } + /** Options to configure how Common Subexpression Elimination behave. */ @AutoValue public abstract static class SubexpressionOptimizerOptions { diff --git a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java index 79e04fc64..98e1ff75a 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java @@ -31,6 +31,7 @@ import dev.cel.common.CelOptions; import dev.cel.common.ast.CelConstant; import dev.cel.common.ast.CelExpr; +import dev.cel.common.types.OptionalType; import dev.cel.common.types.SimpleType; import dev.cel.common.types.StructTypeReference; import dev.cel.extensions.CelExtensions; @@ -75,7 +76,8 @@ public class SubexpressionOptimizerTest { .setSingleInt64(10L) .putMapInt32Int64(0, 1) .putMapInt32Int64(1, 5) - .putMapInt32Int64(2, 2))) + .putMapInt32Int64(2, 2) + .putMapStringString("key", "A"))) .build(); private static CelBuilder newCelBuilder() { @@ -92,6 +94,7 @@ private static CelBuilder newCelBuilder() { "custom_func", newGlobalOverload("custom_func_overload", SimpleType.INT, SimpleType.INT))) .addVar("x", SimpleType.DYN) + .addVar("opt_x", OptionalType.create(SimpleType.DYN)) .addVar("msg", StructTypeReference.create(TestAllTypes.getDescriptor().getFullName())); } @@ -314,6 +317,13 @@ private enum CseTestCase { "[1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [[2, 3, 4], [2, 3, 4], [2, 3, 4]]", "cel.bind(@r0, [1, 2, 3], @r0.map(@c0, @r0.map(@c1, @c1 + 1))) == " + "cel.bind(@r1, [2, 3, 4], [@r1, @r1, @r1])"), + INCLUSION_LIST( + "1 in [1,2,3] && 2 in [1,2,3] && 3 in [3, [1,2,3]] && 1 in [1,2,3]", + "cel.bind(@r0, [1, 2, 3], cel.bind(@r1, 1 in @r0, @r1 && 2 in @r0 && 3 in [3, @r0] &&" + + " @r1))"), + INCLUSION_MAP( + "2 in {'a': 1, 2: {true: false}, 3: {true: false}}", + "2 in cel.bind(@r0, {true: false}, {\"a\": 1, 2: @r0, 3: @r0})"), MACRO_SHADOWED_VARIABLE( "[x - 1 > 3 ? x - 1 : 5].exists(x, x - 1 > 3) || x - 1 > 3", "cel.bind(@r0, x - 1, cel.bind(@r1, @r0 > 3, [@r1 ? @r0 : 5].exists(@c0, @c0 - 1 > 3) ||" @@ -322,6 +332,86 @@ private enum CseTestCase { "size([\"foo\", \"bar\"].map(x, [x + x, x + x]).map(x, [x + x, x + x])) == 2", "size([\"foo\", \"bar\"].map(@c1, cel.bind(@r0, @c1 + @c1, [@r0, @r0]))" + ".map(@c0, cel.bind(@r1, @c0 + @c0, [@r1, @r1]))) == 2"), + PRESENCE_TEST( + "has({'a': true}.a) && {'a':true}['a']", + "cel.bind(@r0, {\"a\": true}, has(@r0.a) && @r0[\"a\"])"), + PRESENCE_TEST_WITH_TERNARY( + "(has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : 0) == 10", + "cel.bind(@r0, msg.oneof_type, has(@r0.payload) ? @r0.payload.single_int64 : 0) == 10"), + PRESENCE_TEST_WITH_TERNARY_2( + "(has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 :" + + " msg.oneof_type.payload.single_int64 * 0) == 10", + "cel.bind(@r0, msg.oneof_type, cel.bind(@r1, @r0.payload.single_int64, has(@r0.payload) ?" + + " @r1 : (@r1 * 0))) == 10"), + PRESENCE_TEST_WITH_TERNARY_3( + "(has(msg.oneof_type.payload.single_int64) ? msg.oneof_type.payload.single_int64 :" + + " msg.oneof_type.payload.single_int64 * 0) == 10", + "cel.bind(@r0, msg.oneof_type.payload, cel.bind(@r1, @r0.single_int64," + + " has(@r0.single_int64) ? @r1 : (@r1 * 0))) == 10"), + /** + * Input: + * + *
{@code
+     * (
+     *   has(msg.oneof_type) &&
+     *   has(msg.oneof_type.payload) &&
+     *   has(msg.oneof_type.payload.single_int64)
+     * ) ?
+     *   (
+     *     (
+     *       has(msg.oneof_type.payload.map_string_string) &&
+     *       has(msg.oneof_type.payload.map_string_string.key)
+     *     ) ?
+     *       msg.oneof_type.payload.map_string_string.key == "A"
+     *     : false
+     *   )
+     * : false
+     * }
+ * + * Unparsed: + * + *
{@code
+     * cel.bind(
+     *   @r0, msg.oneof_type,
+     *   cel.bind(
+     *     @r1, @r0.payload,
+     *     has(msg.oneof_type) && has(@r0.payload) && has(@r1.single_int64) ?
+     *       cel.bind(
+     *         @r2, @r1.map_string_string,
+     *         has(@r1.map_string_string) && has(@r2.key) ? @r2.key == "A" : false,
+     *       )
+     *     : false,
+     *   ),
+     * )
+     * }
+ */ + PRESENCE_TEST_WITH_TERNARY_NESTED( + "(has(msg.oneof_type) && has(msg.oneof_type.payload) &&" + + " has(msg.oneof_type.payload.single_int64)) ?" + + " ((has(msg.oneof_type.payload.map_string_string) &&" + + " has(msg.oneof_type.payload.map_string_string.key)) ?" + + " msg.oneof_type.payload.map_string_string.key == 'A' : false) : false", + "cel.bind(@r0, msg.oneof_type, cel.bind(@r1, @r0.payload, (has(msg.oneof_type) &&" + + " has(@r0.payload) && has(@r1.single_int64)) ? cel.bind(@r2, @r1.map_string_string," + + " (has(@r1.map_string_string) && has(@r2.key)) ? (@r2.key == \"A\") : false) :" + + " false))"), + OPTIONAL_LIST( + "[10, ?optional.none(), [?optional.none(), ?opt_x], [?optional.none(), ?opt_x]] == [10," + + " [5], [5]]", + "cel.bind(@r0, [?optional.none(), ?opt_x], [10, ?optional.none(), @r0, @r0]) ==" + + " cel.bind(@r1, [5], [10, @r1, @r1])"), + OPTIONAL_MAP( + "{?'hello': optional.of('hello')}['hello'] + {?'hello': optional.of('hello')}['hello'] ==" + + " 'hellohello'", + "cel.bind(@r0, {?\"hello\": optional.of(\"hello\")}[\"hello\"], @r0 + @r0) ==" + + " \"hellohello\""), + OPTIONAL_MESSAGE( + "TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32:" + + " optional.of(4)}.single_int32 + TestAllTypes{?single_int64:" + + " optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}.single_int64 == 5", + "cel.bind(@r0, TestAllTypes{" + + "?single_int64: optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}, " + + "@r0.single_int32 + @r0.single_int64) == 5"), ; private final String source; @@ -342,7 +432,9 @@ public void cse_withMacroMapPopulated_success(@TestParameter CseTestCase testCas assertThat( CEL.createProgram(optimizedAst) - .eval(ImmutableMap.of("msg", TEST_ALL_TYPES_INPUT, "x", 5L))) + .eval( + ImmutableMap.of( + "msg", TEST_ALL_TYPES_INPUT, "x", 5L, "opt_x", Optional.of(5L)))) .isEqualTo(true); assertThat(CEL_UNPARSER.unparse(optimizedAst)).isEqualTo(testCase.unparsed); } @@ -366,7 +458,9 @@ public void cse_withoutMacroMap_success(@TestParameter CseTestCase testCase) thr assertThat( celWithoutMacroMap .createProgram(optimizedAst) - .eval(ImmutableMap.of("msg", TEST_ALL_TYPES_INPUT, "x", 5L))) + .eval( + ImmutableMap.of( + "msg", TEST_ALL_TYPES_INPUT, "x", 5L, "opt_x", Optional.of(5L)))) .isEqualTo(true); } @@ -384,7 +478,8 @@ public void cse_withoutMacroMap_success(@TestParameter CseTestCase testCase) thr @TestParameters("{source: 'custom_func(1) + custom_func(1)'}") // Duplicated but nested calls. @TestParameters("{source: 'int(timestamp(int(timestamp(1000000000))))'}") - // Ternary with presence test is not supported yet. + // This cannot be optimized. Extracting the common subexpression would presence test + // the bound identifier (e.g: has(@r0)), which is not valid. @TestParameters("{source: 'has(msg.single_any) ? msg.single_any : 10'}") public void cse_noop(String source) throws Exception { CelAbstractSyntaxTree ast = CEL.compile(source).getAst(); From f9f370de9532615b711f8c722d3210a80987bb03 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Fri, 19 Jan 2024 16:21:19 -0800 Subject: [PATCH 011/486] Allow configuration of MutableAst by making it instantiable PiperOrigin-RevId: 599966084 --- optimizer/BUILD.bazel | 2 - .../main/java/dev/cel/optimizer/BUILD.bazel | 8 +- .../dev/cel/optimizer/CelAstOptimizer.java | 103 ----- .../java/dev/cel/optimizer/MutableAst.java | 385 ++++++++---------- .../dev/cel/optimizer/MutableExprVisitor.java | 166 ++++++++ .../dev/cel/optimizer/optimizers/BUILD.bazel | 2 + .../optimizers/ConstantFoldingOptimizer.java | 36 +- .../optimizers/SubexpressionOptimizer.java | 30 +- .../dev/cel/optimizer/MutableAstTest.java | 87 ++-- .../ConstantFoldingOptimizerTest.java | 2 +- .../SubexpressionOptimizerTest.java | 10 +- 11 files changed, 450 insertions(+), 381 deletions(-) create mode 100644 optimizer/src/main/java/dev/cel/optimizer/MutableExprVisitor.java diff --git a/optimizer/BUILD.bazel b/optimizer/BUILD.bazel index f0bc0bae7..1dd584b4e 100644 --- a/optimizer/BUILD.bazel +++ b/optimizer/BUILD.bazel @@ -25,8 +25,6 @@ java_library( java_library( name = "mutable_ast", - testonly = 1, - visibility = ["//optimizer/src/test/java/dev/cel/optimizer:__pkg__"], exports = ["//optimizer/src/main/java/dev/cel/optimizer:mutable_ast"], ) diff --git a/optimizer/src/main/java/dev/cel/optimizer/BUILD.bazel b/optimizer/src/main/java/dev/cel/optimizer/BUILD.bazel index 454ab828c..954deb74f 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/BUILD.bazel +++ b/optimizer/src/main/java/dev/cel/optimizer/BUILD.bazel @@ -66,18 +66,19 @@ java_library( tags = [ ], deps = [ - ":mutable_ast", ":optimization_exception", "//bundle:cel", "//common", - "//common/ast", "//common/navigation", ], ) java_library( name = "mutable_ast", - srcs = ["MutableAst.java"], + srcs = [ + "MutableAst.java", + "MutableExprVisitor.java", + ], tags = [ ], deps = [ @@ -87,6 +88,7 @@ java_library( "//common/ast", "//common/ast:expr_factory", "//common/navigation", + "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", ], ) diff --git a/optimizer/src/main/java/dev/cel/optimizer/CelAstOptimizer.java b/optimizer/src/main/java/dev/cel/optimizer/CelAstOptimizer.java index feac4ce91..b9f35dcf4 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/CelAstOptimizer.java +++ b/optimizer/src/main/java/dev/cel/optimizer/CelAstOptimizer.java @@ -16,7 +16,6 @@ import dev.cel.bundle.Cel; import dev.cel.common.CelAbstractSyntaxTree; -import dev.cel.common.ast.CelExpr; import dev.cel.common.navigation.CelNavigableAst; /** Public interface for performing a single, custom optimization on an AST. */ @@ -25,106 +24,4 @@ public interface CelAstOptimizer { /** Optimizes a single AST. */ CelAbstractSyntaxTree optimize(CelNavigableAst navigableAst, Cel cel) throws CelOptimizationException; - - /** - * Replaces a subtree in the given expression node. This operation is intended for AST - * optimization purposes. - * - *

This is a very dangerous operation. Callers should re-typecheck the mutated AST and - * additionally verify that the resulting AST is semantically valid. - * - *

All expression IDs will be renumbered in a stable manner to ensure there's no ID collision - * between the nodes. The renumbering occurs even if the subtree was not replaced. - * - * @param celExpr Original expression node to rewrite. - * @param newExpr New CelExpr to replace the subtree with. - * @param exprIdToReplace Expression id of the subtree that is getting replaced. - */ - default CelExpr replaceSubtree(CelExpr celExpr, CelExpr newExpr, long exprIdToReplace) { - return MutableAst.replaceSubtree(celExpr, newExpr, exprIdToReplace); - } - - /** - * Replaces a subtree in the given AST. This operation is intended for AST optimization purposes. - * - *

This is a very dangerous operation. Callers should re-typecheck the mutated AST and - * additionally verify that the resulting AST is semantically valid. - * - *

All expression IDs will be renumbered in a stable manner to ensure there's no ID collision - * between the nodes. The renumbering occurs even if the subtree was not replaced. - * - *

This will scrub out the description, positions and line offsets from {@code CelSource}. If - * the source contains macro calls, its call IDs will be to be consistent with the renumbered IDs - * in the AST. - * - * @param ast Original ast to mutate. - * @param newExpr New CelExpr to replace the subtree with. - * @param exprIdToReplace Expression id of the subtree that is getting replaced. - */ - default CelAbstractSyntaxTree replaceSubtree( - CelAbstractSyntaxTree ast, CelExpr newExpr, long exprIdToReplace) { - return MutableAst.replaceSubtree(ast, newExpr, exprIdToReplace); - } - - /** - * Generates a new bind macro using the provided initialization and result expression, then - * replaces the subtree using the new bind expr at the designated expr ID. - * - *

The bind call takes the format of: {@code cel.bind(varInit, varName, resultExpr)} - * - * @param ast Original ast to mutate. - * @param varName New variable name for the bind macro call. - * @param varInit Initialization expression to bind to the local variable. - * @param resultExpr Result expression - * @param exprIdToReplace Expression ID of the subtree that is getting replaced. - */ - default CelAbstractSyntaxTree replaceSubtreeWithNewBindMacro( - CelAbstractSyntaxTree ast, - String varName, - CelExpr varInit, - CelExpr resultExpr, - long exprIdToReplace) { - return MutableAst.replaceSubtreeWithNewBindMacro( - ast, varName, varInit, resultExpr, exprIdToReplace); - } - - /** - * Replaces all comprehension identifier names with a unique name based on the given prefix. - * - *

The purpose of this is to avoid errors that can be caused by shadowed variables while - * augmenting an AST. As an example: {@code [2, 3].exists(x, x - 1 > 3) || x - 1 > 3}. Note that - * the scoping of `x - 1` is different between th two LOGICAL_OR branches. Iteration variable `x` - * in `exists` will be mangled to {@code [2, 3].exists(@c0, @c0 - 1 > 3) || x - 1 > 3} to avoid - * erroneously extracting x - 1 as common subexpression. - * - *

The expression IDs are not modified when the identifier names are changed. - * - *

Iteration variables in comprehensions are numbered based on their comprehension nesting - * levels. Examples: - * - *

    - *
  • {@code [true].exists(i, i) && [true].exists(j, j)} -> {@code [true].exists(@c0, @c0) && - * [true].exists(@c0, @c0)} // Note that i,j gets replaced to the same @c0 in this example - *
  • {@code [true].exists(i, i && [true].exists(j, j))} -> {@code [true].exists(@c0, @c0 && - * [true].exists(@c1, @c1))} - *
- * - * @param ast AST to mutate - * @param newIdentPrefix Prefix to use for new identifier names. For example, providing @c will - * produce @c0, @c1, @c2... as new names. - */ - default CelAbstractSyntaxTree mangleComprehensionIdentifierNames( - CelAbstractSyntaxTree ast, String newIdentPrefix) { - return MutableAst.mangleComprehensionIdentifierNames(ast, newIdentPrefix); - } - - /** Sets all expr IDs in the expression tree to 0. */ - default CelExpr clearExprIds(CelExpr celExpr) { - return MutableAst.clearExprIds(celExpr); - } - - /** Renumbers all the expr IDs in the given AST in a consecutive manner starting from 1. */ - default CelAbstractSyntaxTree renumberIdsConsecutively(CelAbstractSyntaxTree ast) { - return MutableAst.renumberIdsConsecutively(ast); - } } diff --git a/optimizer/src/main/java/dev/cel/optimizer/MutableAst.java b/optimizer/src/main/java/dev/cel/optimizer/MutableAst.java index 1c3427169..5562428ca 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/MutableAst.java +++ b/optimizer/src/main/java/dev/cel/optimizer/MutableAst.java @@ -19,23 +19,20 @@ import static java.lang.Math.max; import com.google.auto.value.AutoValue; +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import com.google.errorprone.annotations.Immutable; import dev.cel.common.CelAbstractSyntaxTree; import dev.cel.common.CelSource; -import dev.cel.common.annotations.Internal; import dev.cel.common.ast.CelExpr; -import dev.cel.common.ast.CelExpr.CelCall; -import dev.cel.common.ast.CelExpr.CelComprehension; -import dev.cel.common.ast.CelExpr.CelCreateList; -import dev.cel.common.ast.CelExpr.CelCreateMap; -import dev.cel.common.ast.CelExpr.CelCreateStruct; import dev.cel.common.ast.CelExpr.CelIdent; -import dev.cel.common.ast.CelExpr.CelSelect; import dev.cel.common.ast.CelExpr.ExprKind.Kind; import dev.cel.common.ast.CelExprFactory; import dev.cel.common.ast.CelExprIdGeneratorFactory; import dev.cel.common.ast.CelExprIdGeneratorFactory.ExprIdGenerator; +import dev.cel.common.ast.CelExprIdGeneratorFactory.MonotonicIdGenerator; import dev.cel.common.ast.CelExprIdGeneratorFactory.StableIdGenerator; import dev.cel.common.navigation.CelNavigableAst; import dev.cel.common.navigation.CelNavigableExpr; @@ -44,100 +41,102 @@ import java.util.NoSuchElementException; import java.util.Optional; -/** MutableAst contains logic for mutating a {@link CelExpr}. */ -@Internal -final class MutableAst { - private static final int MAX_ITERATION_COUNT = 1000; +/** MutableAst contains logic for mutating a {@link CelAbstractSyntaxTree}. */ +@Immutable +public final class MutableAst { private static final ExprIdGenerator NO_OP_ID_GENERATOR = id -> id; + private final long iterationLimit; - private final CelExpr.Builder newExpr; - private final ExprIdGenerator celExprIdGenerator; - private int iterationCount; - private long exprIdToReplace; + /** + * Returns a new instance of a Mutable AST with the iteration limit set. + * + *

Mutation is performed by walking the existing AST until the expression node to replace is + * found, then the new subtree is walked to complete the mutation. Visiting of each node + * increments the iteration counter. Replace subtree operations will throw an exception if this + * counter reaches the limit. + * + * @param iterationLimit Must be greater than 0. + */ + public static MutableAst newInstance(long iterationLimit) { + return new MutableAst(iterationLimit); + } - private MutableAst(ExprIdGenerator celExprIdGenerator, CelExpr.Builder newExpr, long exprId) { - this.celExprIdGenerator = celExprIdGenerator; - this.newExpr = newExpr; - this.exprIdToReplace = exprId; + private MutableAst(long iterationLimit) { + Preconditions.checkState(iterationLimit > 0L); + this.iterationLimit = iterationLimit; } /** Replaces all the expression IDs in the expression tree with 0. */ - static CelExpr clearExprIds(CelExpr celExpr) { + public CelExpr clearExprIds(CelExpr celExpr) { return renumberExprIds((unused) -> 0, celExpr.toBuilder()).build(); } - /** Mutates the given {@link CelExpr} by replacing a subtree at the given index. */ - static CelExpr replaceSubtree(CelExpr expr, CelExpr newExpr, long exprIdToReplace) { - return replaceSubtree( - CelAbstractSyntaxTree.newParsedAst(expr, CelSource.newBuilder().build()), - CelAbstractSyntaxTree.newParsedAst(newExpr, CelSource.newBuilder().build()), + /** + * Replaces a subtree in the given expression node. This operation is intended for AST + * optimization purposes. + * + *

This is a very dangerous operation. Callers should re-typecheck the mutated AST and + * additionally verify that the resulting AST is semantically valid. + * + *

All expression IDs will be renumbered in a stable manner to ensure there's no ID collision + * between the nodes. The renumbering occurs even if the subtree was not replaced. + * + *

If the ability to unparse an expression containing a macro call must be retained, use {@link + * #replaceSubtree(CelAbstractSyntaxTree, CelExpr, long) instead.} + * + * @param celExpr Original expression node to rewrite. + * @param newExpr New CelExpr to replace the subtree with. + * @param exprIdToReplace Expression id of the subtree that is getting replaced. + */ + public CelExpr replaceSubtree(CelExpr celExpr, CelExpr newExpr, long exprIdToReplace) { + MonotonicIdGenerator monotonicIdGenerator = + CelExprIdGeneratorFactory.newMonotonicIdGenerator(0); + return mutateExpr( + unused -> monotonicIdGenerator.nextExprId(), + celExpr.toBuilder(), + newExpr.toBuilder(), exprIdToReplace) - .getExpr(); + .build(); } /** - * Mutates the given AST by replacing a subtree at a given index. + * Replaces a subtree in the given AST. This operation is intended for AST optimization purposes. * - * @param ast Existing AST being mutated - * @param newExpr New subtree to perform the replacement with. - * @param exprIdToReplace The expr ID in the existing AST to replace the subtree at. + *

This is a very dangerous operation. Callers should re-typecheck the mutated AST and + * additionally verify that the resulting AST is semantically valid. + * + *

All expression IDs will be renumbered in a stable manner to ensure there's no ID collision + * between the nodes. The renumbering occurs even if the subtree was not replaced. + * + *

This will scrub out the description, positions and line offsets from {@code CelSource}. If + * the source contains macro calls, its call IDs will be to be consistent with the renumbered IDs + * in the AST. + * + * @param ast Original ast to mutate. + * @param newExpr New CelExpr to replace the subtree with. + * @param exprIdToReplace Expression id of the subtree that is getting replaced. */ - static CelAbstractSyntaxTree replaceSubtree( + public CelAbstractSyntaxTree replaceSubtree( CelAbstractSyntaxTree ast, CelExpr newExpr, long exprIdToReplace) { - return replaceSubtree( + return replaceSubtreeWithNewAst( ast, CelAbstractSyntaxTree.newParsedAst(newExpr, CelSource.newBuilder().build()), exprIdToReplace); } /** - * Mutates the given AST by replacing a subtree at a given index. + * Generates a new bind macro using the provided initialization and result expression, then + * replaces the subtree using the new bind expr at the designated expr ID. * - * @param ast Existing AST being mutated - * @param newAst New subtree to perform the replacement with. If the subtree has a macro map - * populated, its macro source is merged with the existing AST's after normalization. - * @param exprIdToReplace The expr ID in the existing AST to replace the subtree at. + *

The bind call takes the format of: {@code cel.bind(varInit, varName, resultExpr)} + * + * @param ast Original ast to mutate. + * @param varName New variable name for the bind macro call. + * @param varInit Initialization expression to bind to the local variable. + * @param resultExpr Result expression + * @param exprIdToReplace Expression ID of the subtree that is getting replaced. */ - static CelAbstractSyntaxTree replaceSubtree( - CelAbstractSyntaxTree ast, CelAbstractSyntaxTree newAst, long exprIdToReplace) { - // Stabilize the incoming AST by renumbering all of its expression IDs. - long maxId = max(getMaxId(ast), getMaxId(newAst)); - newAst = stabilizeAst(newAst, maxId); - - // Mutate the AST root with the new subtree. All the existing expr IDs are renumbered in the - // process, but its original IDs are memoized so that we can normalize the expr IDs - // in the macro source map. - StableIdGenerator stableIdGenerator = - CelExprIdGeneratorFactory.newStableIdGenerator(getMaxId(newAst)); - CelExpr.Builder mutatedRoot = - replaceSubtreeImpl( - stableIdGenerator::renumberId, - ast.getExpr().toBuilder(), - newAst.getExpr().toBuilder(), - exprIdToReplace); - - CelSource newAstSource = ast.getSource(); - if (!newAst.getSource().getMacroCalls().isEmpty()) { - // The root is mutated, but the expr IDs in the macro map needs to be normalized. - // In situations where an AST with a new macro map is being inserted (ex: new bind call), - // the new subtree's expr ID is not memoized in the stable ID generator because the ID never - // existed in the main AST. - // In this case, we forcibly memoize the new subtree ID with a newly generated ID so - // that the macro map IDs can be normalized properly. - stableIdGenerator.memoize( - newAst.getExpr().id(), stableIdGenerator.renumberId(exprIdToReplace)); - newAstSource = combine(newAstSource, newAst.getSource()); - } - - newAstSource = - normalizeMacroSource( - newAstSource, exprIdToReplace, mutatedRoot, stableIdGenerator::renumberId); - - return CelAbstractSyntaxTree.newParsedAst(mutatedRoot.build(), newAstSource); - } - - /** Replaces the subtree at the given ID with a newly created bind macro. */ - static CelAbstractSyntaxTree replaceSubtreeWithNewBindMacro( + public CelAbstractSyntaxTree replaceSubtreeWithNewBindMacro( CelAbstractSyntaxTree ast, String varName, CelExpr varInit, @@ -160,11 +159,12 @@ static CelAbstractSyntaxTree replaceSubtreeWithNewBindMacro( .addMacroCalls(bindMacro.bindExpr().id(), bindMacro.bindMacro()) .build(); - return replaceSubtree( + return replaceSubtreeWithNewAst( ast, CelAbstractSyntaxTree.newParsedAst(bindMacro.bindExpr(), celSource), exprIdToReplace); } - static CelAbstractSyntaxTree renumberIdsConsecutively(CelAbstractSyntaxTree ast) { + /** Renumbers all the expr IDs in the given AST in a consecutive manner starting from 1. */ + public CelAbstractSyntaxTree renumberIdsConsecutively(CelAbstractSyntaxTree ast) { StableIdGenerator stableIdGenerator = CelExprIdGeneratorFactory.newStableIdGenerator(0); CelExpr.Builder root = renumberExprIds(stableIdGenerator::renumberId, ast.getExpr().toBuilder()); @@ -175,12 +175,37 @@ static CelAbstractSyntaxTree renumberIdsConsecutively(CelAbstractSyntaxTree ast) return CelAbstractSyntaxTree.newParsedAst(root.build(), newSource); } - static CelAbstractSyntaxTree mangleComprehensionIdentifierNames( + /** + * Replaces all comprehension identifier names with a unique name based on the given prefix. + * + *

The purpose of this is to avoid errors that can be caused by shadowed variables while + * augmenting an AST. As an example: {@code [2, 3].exists(x, x - 1 > 3) || x - 1 > 3}. Note that + * the scoping of `x - 1` is different between th two LOGICAL_OR branches. Iteration variable `x` + * in `exists` will be mangled to {@code [2, 3].exists(@c0, @c0 - 1 > 3) || x - 1 > 3} to avoid + * erroneously extracting x - 1 as common subexpression. + * + *

The expression IDs are not modified when the identifier names are changed. + * + *

Iteration variables in comprehensions are numbered based on their comprehension nesting + * levels. Examples: + * + *

    + *
  • {@code [true].exists(i, i) && [true].exists(j, j)} -> {@code [true].exists(@c0, @c0) && + * [true].exists(@c0, @c0)} // Note that i,j gets replaced to the same @c0 in this example + *
  • {@code [true].exists(i, i && [true].exists(j, j))} -> {@code [true].exists(@c0, @c0 && + * [true].exists(@c1, @c1))} + *
+ * + * @param ast AST to mutate + * @param newIdentPrefix Prefix to use for new identifier names. For example, providing @c will + * produce @c0, @c1, @c2... as new names. + */ + public CelAbstractSyntaxTree mangleComprehensionIdentifierNames( CelAbstractSyntaxTree ast, String newIdentPrefix) { int iterCount; CelNavigableAst newNavigableAst = CelNavigableAst.fromAst(ast); - for (iterCount = 0; iterCount < MAX_ITERATION_COUNT; iterCount++) { - Optional maybeComprehensionExpr = + for (iterCount = 0; iterCount < iterationLimit; iterCount++) { + CelNavigableExpr comprehensionNode = newNavigableAst .getRoot() // This is important - mangling needs to happen bottom-up to avoid stepping over @@ -188,14 +213,15 @@ static CelAbstractSyntaxTree mangleComprehensionIdentifierNames( .allNodes(TraversalOrder.POST_ORDER) .filter(node -> node.getKind().equals(Kind.COMPREHENSION)) .filter(node -> !node.expr().comprehension().iterVar().startsWith(newIdentPrefix)) - .findAny(); - if (!maybeComprehensionExpr.isPresent()) { + .findAny() + .orElse(null); + if (comprehensionNode == null) { break; } - CelExpr.Builder comprehensionExpr = maybeComprehensionExpr.get().expr().toBuilder(); + CelExpr.Builder comprehensionExpr = comprehensionNode.expr().toBuilder(); String iterVar = comprehensionExpr.comprehension().iterVar(); - int comprehensionNestingLevel = countComprehensionNestingLevel(maybeComprehensionExpr.get()); + int comprehensionNestingLevel = countComprehensionNestingLevel(comprehensionNode); String mangledVarName = newIdentPrefix + comprehensionNestingLevel; CelExpr.Builder mutatedComprehensionExpr = @@ -218,20 +244,70 @@ static CelAbstractSyntaxTree mangleComprehensionIdentifierNames( CelAbstractSyntaxTree.newParsedAst(mutatedComprehensionExpr.build(), newSource)); } - if (iterCount >= MAX_ITERATION_COUNT) { + if (iterCount >= iterationLimit) { + // Note that it's generally impossible to reach this for a well-formed AST. The nesting level + // of AST being mutated is always deeper than the number of identifiers being mangled, thus + // the mutation operation should throw before we ever reach here. throw new IllegalStateException("Max iteration count reached."); } return newNavigableAst.getAst(); } - private static CelExpr.Builder mangleIdentsInComprehensionExpr( + /** + * Mutates the given AST by replacing a subtree at a given index. + * + * @param ast Existing AST being mutated + * @param newAst New subtree to perform the replacement with. If the subtree has a macro map + * populated, its macro source is merged with the existing AST's after normalization. + * @param exprIdToReplace The expr ID in the existing AST to replace the subtree at. + */ + @VisibleForTesting + CelAbstractSyntaxTree replaceSubtreeWithNewAst( + CelAbstractSyntaxTree ast, CelAbstractSyntaxTree newAst, long exprIdToReplace) { + // Stabilize the incoming AST by renumbering all of its expression IDs. + long maxId = max(getMaxId(ast), getMaxId(newAst)); + newAst = stabilizeAst(newAst, maxId); + + // Mutate the AST root with the new subtree. All the existing expr IDs are renumbered in the + // process, but its original IDs are memoized so that we can normalize the expr IDs + // in the macro source map. + StableIdGenerator stableIdGenerator = + CelExprIdGeneratorFactory.newStableIdGenerator(getMaxId(newAst)); + CelExpr.Builder mutatedRoot = + mutateExpr( + stableIdGenerator::renumberId, + ast.getExpr().toBuilder(), + newAst.getExpr().toBuilder(), + exprIdToReplace); + + CelSource newAstSource = ast.getSource(); + if (!newAst.getSource().getMacroCalls().isEmpty()) { + // The root is mutated, but the expr IDs in the macro map needs to be normalized. + // In situations where an AST with a new macro map is being inserted (ex: new bind call), + // the new subtree's expr ID is not memoized in the stable ID generator because the ID never + // existed in the main AST. + // In this case, we forcibly memoize the new subtree ID with a newly generated ID so + // that the macro map IDs can be normalized properly. + stableIdGenerator.memoize( + newAst.getExpr().id(), stableIdGenerator.renumberId(exprIdToReplace)); + newAstSource = combine(newAstSource, newAst.getSource()); + } + + newAstSource = + normalizeMacroSource( + newAstSource, exprIdToReplace, mutatedRoot, stableIdGenerator::renumberId); + + return CelAbstractSyntaxTree.newParsedAst(mutatedRoot.build(), newAstSource); + } + + private CelExpr.Builder mangleIdentsInComprehensionExpr( CelExpr.Builder root, CelExpr.Builder comprehensionExpr, String originalIterVar, String mangledVarName) { int iterCount; - for (iterCount = 0; iterCount < MAX_ITERATION_COUNT; iterCount++) { + for (iterCount = 0; iterCount < iterationLimit; iterCount++) { Optional identToMangle = CelNavigableExpr.fromExpr(comprehensionExpr.comprehension().loopStep()) .descendants() @@ -243,18 +319,18 @@ private static CelExpr.Builder mangleIdentsInComprehensionExpr( } comprehensionExpr = - replaceSubtreeImpl( + mutateExpr( NO_OP_ID_GENERATOR, comprehensionExpr, CelExpr.newBuilder().setIdent(CelIdent.newBuilder().setName(mangledVarName).build()), identToMangle.get().id()); } - if (iterCount >= MAX_ITERATION_COUNT) { + if (iterCount >= iterationLimit) { throw new IllegalStateException("Max iteration count reached."); } - return replaceSubtreeImpl( + return mutateExpr( NO_OP_ID_GENERATOR, root, comprehensionExpr.setComprehension( @@ -262,7 +338,7 @@ private static CelExpr.Builder mangleIdentsInComprehensionExpr( comprehensionExpr.id()); } - private static CelSource mangleIdentsInMacroSource( + private CelSource mangleIdentsInMacroSource( CelAbstractSyntaxTree ast, CelExpr.Builder mutatedComprehensionExpr, String originalIterVar, @@ -291,7 +367,7 @@ private static CelSource mangleIdentsInMacroSource( identToMangle.identOrDefault().name(), originalIterVar)); } macroExpr = - replaceSubtreeImpl( + mutateExpr( NO_OP_ID_GENERATOR, macroExpr, CelExpr.newBuilder().setIdent(CelIdent.newBuilder().setName(mangledVarName).build()), @@ -301,7 +377,7 @@ private static CelSource mangleIdentsInMacroSource( return newSource.build(); } - private static BindMacro newBindMacro( + private BindMacro newBindMacro( String varName, CelExpr varInit, CelExpr resultExpr, StableIdGenerator stableIdGenerator) { // Renumber incoming expression IDs in the init and result expression to avoid collision with // the main AST. Existing IDs are memoized for a macro source sanitization pass at the end @@ -348,7 +424,7 @@ private static CelSource combine(CelSource celSource1, CelSource celSource2) { * (monotonically increased) from the starting seed ID. If the AST contains any macro calls, its * IDs are also normalized. */ - private static CelAbstractSyntaxTree stabilizeAst(CelAbstractSyntaxTree ast, long seedExprId) { + private CelAbstractSyntaxTree stabilizeAst(CelAbstractSyntaxTree ast, long seedExprId) { StableIdGenerator stableIdGenerator = CelExprIdGeneratorFactory.newStableIdGenerator(seedExprId); CelExpr.Builder newExprBuilder = @@ -373,7 +449,7 @@ private static CelAbstractSyntaxTree stabilizeAst(CelAbstractSyntaxTree ast, lon return CelAbstractSyntaxTree.newParsedAst(newExprBuilder.build(), sourceBuilder.build()); } - private static CelSource normalizeMacroSource( + private CelSource normalizeMacroSource( CelSource celSource, long exprIdToReplace, CelExpr.Builder mutatedRoot, @@ -424,8 +500,7 @@ private static CelSource normalizeMacroSource( CelExpr mutatedExpr = allExprs.get(callChild.id()); if (!callChild.equals(mutatedExpr)) { - newCall = - replaceSubtreeImpl((arg) -> arg, newCall, mutatedExpr.toBuilder(), callChild.id()); + newCall = mutateExpr((arg) -> arg, newCall, mutatedExpr.toBuilder(), callChild.id()); } } sourceBuilder.addMacroCalls(callId, newCall.build()); @@ -441,7 +516,7 @@ private static CelSource normalizeMacroSource( .forEach( node -> { CelExpr.Builder mutatedNode = - replaceSubtreeImpl( + mutateExpr( (id) -> id, macroCallExpr.toBuilder(), CelExpr.ofNotSet(node.id()).toBuilder(), @@ -453,18 +528,19 @@ private static CelSource normalizeMacroSource( return sourceBuilder.build(); } - private static CelExpr.Builder replaceSubtreeImpl( + private CelExpr.Builder mutateExpr( ExprIdGenerator idGenerator, CelExpr.Builder root, CelExpr.Builder newExpr, long exprIdToReplace) { - MutableAst mutableAst = new MutableAst(idGenerator, newExpr, exprIdToReplace); + MutableExprVisitor mutableAst = + MutableExprVisitor.newInstance(idGenerator, newExpr, exprIdToReplace, iterationLimit); return mutableAst.visit(root); } - private static CelExpr.Builder renumberExprIds( - ExprIdGenerator idGenerator, CelExpr.Builder root) { - MutableAst mutableAst = new MutableAst(idGenerator, root, Integer.MIN_VALUE); + private CelExpr.Builder renumberExprIds(ExprIdGenerator idGenerator, CelExpr.Builder root) { + MutableExprVisitor mutableAst = + MutableExprVisitor.newInstance(idGenerator, root, Integer.MIN_VALUE, iterationLimit); return mutableAst.visit(root); } @@ -498,105 +574,6 @@ private static int countComprehensionNestingLevel(CelNavigableExpr comprehension return nestedLevel; } - private CelExpr.Builder visit(CelExpr.Builder expr) { - if (++iterationCount > MAX_ITERATION_COUNT) { - throw new IllegalStateException("Max iteration count reached."); - } - - if (expr.id() == exprIdToReplace) { - exprIdToReplace = Integer.MIN_VALUE; // Marks that the subtree has been replaced. - return visit(newExpr.setId(expr.id())); - } - - expr.setId(celExprIdGenerator.generate(expr.id())); - - switch (expr.exprKind().getKind()) { - case SELECT: - return visit(expr, expr.select().toBuilder()); - case CALL: - return visit(expr, expr.call().toBuilder()); - case CREATE_LIST: - return visit(expr, expr.createList().toBuilder()); - case CREATE_STRUCT: - return visit(expr, expr.createStruct().toBuilder()); - case CREATE_MAP: - return visit(expr, expr.createMap().toBuilder()); - case COMPREHENSION: - return visit(expr, expr.comprehension().toBuilder()); - case CONSTANT: // Fall-through is intended - case IDENT: - case NOT_SET: // Note: comprehension arguments can contain a not set expr. - return expr; - default: - throw new IllegalArgumentException("unexpected expr kind: " + expr.exprKind().getKind()); - } - } - - private CelExpr.Builder visit(CelExpr.Builder expr, CelSelect.Builder select) { - select.setOperand(visit(select.operand().toBuilder()).build()); - return expr.setSelect(select.build()); - } - - private CelExpr.Builder visit(CelExpr.Builder expr, CelCall.Builder call) { - if (call.target().isPresent()) { - call.setTarget(visit(call.target().get().toBuilder()).build()); - } - ImmutableList argsBuilders = call.getArgsBuilders(); - for (int i = 0; i < argsBuilders.size(); i++) { - CelExpr.Builder arg = argsBuilders.get(i); - call.setArg(i, visit(arg).build()); - } - - return expr.setCall(call.build()); - } - - private CelExpr.Builder visit(CelExpr.Builder expr, CelCreateStruct.Builder createStruct) { - ImmutableList entries = createStruct.getEntriesBuilders(); - for (int i = 0; i < entries.size(); i++) { - CelCreateStruct.Entry.Builder entry = entries.get(i); - entry.setId(celExprIdGenerator.generate(entry.id())); - entry.setValue(visit(entry.value().toBuilder()).build()); - - createStruct.setEntry(i, entry.build()); - } - - return expr.setCreateStruct(createStruct.build()); - } - - private CelExpr.Builder visit(CelExpr.Builder expr, CelCreateMap.Builder createMap) { - ImmutableList entriesBuilders = createMap.getEntriesBuilders(); - for (int i = 0; i < entriesBuilders.size(); i++) { - CelCreateMap.Entry.Builder entry = entriesBuilders.get(i); - entry.setId(celExprIdGenerator.generate(entry.id())); - entry.setKey(visit(entry.key().toBuilder()).build()); - entry.setValue(visit(entry.value().toBuilder()).build()); - - createMap.setEntry(i, entry.build()); - } - - return expr.setCreateMap(createMap.build()); - } - - private CelExpr.Builder visit(CelExpr.Builder expr, CelCreateList.Builder createList) { - ImmutableList elementsBuilders = createList.getElementsBuilders(); - for (int i = 0; i < elementsBuilders.size(); i++) { - CelExpr.Builder elem = elementsBuilders.get(i); - createList.setElement(i, visit(elem).build()); - } - - return expr.setCreateList(createList.build()); - } - - private CelExpr.Builder visit(CelExpr.Builder expr, CelComprehension.Builder comprehension) { - comprehension.setIterRange(visit(comprehension.iterRange().toBuilder()).build()); - comprehension.setAccuInit(visit(comprehension.accuInit().toBuilder()).build()); - comprehension.setLoopCondition(visit(comprehension.loopCondition().toBuilder()).build()); - comprehension.setLoopStep(visit(comprehension.loopStep().toBuilder()).build()); - comprehension.setResult(visit(comprehension.result().toBuilder()).build()); - - return expr.setComprehension(comprehension.build()); - } - /** * Intermediate value class to store the generated CelExpr for the bind macro and the macro call * information. diff --git a/optimizer/src/main/java/dev/cel/optimizer/MutableExprVisitor.java b/optimizer/src/main/java/dev/cel/optimizer/MutableExprVisitor.java new file mode 100644 index 000000000..36cb86069 --- /dev/null +++ b/optimizer/src/main/java/dev/cel/optimizer/MutableExprVisitor.java @@ -0,0 +1,166 @@ +// Copyright 2024 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.common.base.Preconditions; +import com.google.common.collect.ImmutableList; +import dev.cel.common.annotations.Internal; +import dev.cel.common.ast.CelExpr; +import dev.cel.common.ast.CelExpr.CelCall; +import dev.cel.common.ast.CelExpr.CelComprehension; +import dev.cel.common.ast.CelExpr.CelCreateList; +import dev.cel.common.ast.CelExpr.CelCreateMap; +import dev.cel.common.ast.CelExpr.CelCreateStruct; +import dev.cel.common.ast.CelExpr.CelSelect; +import dev.cel.common.ast.CelExprIdGeneratorFactory.ExprIdGenerator; + +/** + * MutableExprVisitor performs mutation of {@link CelExpr} based on its configured parameters. + * + *

This class is NOT thread-safe. Callers should spawn a new instance of this class each time the + * expression is being mutated. + * + *

Note that CelExpr is immutable by design. Therefore, the logic here doesn't actually mutate + * the existing expression tree. Instead, a brand new CelExpr is produced with the subtree swapped + * at the desired expression ID to replace. + */ +@Internal +final class MutableExprVisitor { + private final CelExpr.Builder newExpr; + private final ExprIdGenerator celExprIdGenerator; + private final long iterationLimit; + private int iterationCount; + private long exprIdToReplace; + + static MutableExprVisitor newInstance( + ExprIdGenerator idGenerator, + CelExpr.Builder newExpr, + long exprIdToReplace, + long iterationLimit) { + // iterationLimit * 2, because the expr can be walked twice due to the immutable nature of + // CelExpr. + return new MutableExprVisitor(idGenerator, newExpr, exprIdToReplace, iterationLimit * 2); + } + + CelExpr.Builder visit(CelExpr.Builder root) { + if (++iterationCount > iterationLimit) { + throw new IllegalStateException("Max iteration count reached."); + } + + if (root.id() == exprIdToReplace) { + exprIdToReplace = Integer.MIN_VALUE; // Marks that the subtree has been replaced. + return visit(this.newExpr.setId(root.id())); + } + + root.setId(celExprIdGenerator.generate(root.id())); + + switch (root.exprKind().getKind()) { + case SELECT: + return visit(root, root.select().toBuilder()); + case CALL: + return visit(root, root.call().toBuilder()); + case CREATE_LIST: + return visit(root, root.createList().toBuilder()); + case CREATE_STRUCT: + return visit(root, root.createStruct().toBuilder()); + case CREATE_MAP: + return visit(root, root.createMap().toBuilder()); + case COMPREHENSION: + return visit(root, root.comprehension().toBuilder()); + case CONSTANT: // Fall-through is intended + case IDENT: + case NOT_SET: // Note: comprehension arguments can contain a not set root. + return root; + } + throw new IllegalArgumentException("unexpected root kind: " + root.exprKind().getKind()); + } + + private CelExpr.Builder visit(CelExpr.Builder expr, CelSelect.Builder select) { + select.setOperand(visit(select.operand().toBuilder()).build()); + return expr.setSelect(select.build()); + } + + private CelExpr.Builder visit(CelExpr.Builder expr, CelCall.Builder call) { + if (call.target().isPresent()) { + call.setTarget(visit(call.target().get().toBuilder()).build()); + } + ImmutableList argsBuilders = call.getArgsBuilders(); + for (int i = 0; i < argsBuilders.size(); i++) { + CelExpr.Builder arg = argsBuilders.get(i); + call.setArg(i, visit(arg).build()); + } + + return expr.setCall(call.build()); + } + + private CelExpr.Builder visit(CelExpr.Builder expr, CelCreateStruct.Builder createStruct) { + ImmutableList entries = createStruct.getEntriesBuilders(); + for (int i = 0; i < entries.size(); i++) { + CelCreateStruct.Entry.Builder entry = entries.get(i); + entry.setId(celExprIdGenerator.generate(entry.id())); + entry.setValue(visit(entry.value().toBuilder()).build()); + + createStruct.setEntry(i, entry.build()); + } + + return expr.setCreateStruct(createStruct.build()); + } + + private CelExpr.Builder visit(CelExpr.Builder expr, CelCreateMap.Builder createMap) { + ImmutableList entriesBuilders = createMap.getEntriesBuilders(); + for (int i = 0; i < entriesBuilders.size(); i++) { + CelCreateMap.Entry.Builder entry = entriesBuilders.get(i); + entry.setId(celExprIdGenerator.generate(entry.id())); + entry.setKey(visit(entry.key().toBuilder()).build()); + entry.setValue(visit(entry.value().toBuilder()).build()); + + createMap.setEntry(i, entry.build()); + } + + return expr.setCreateMap(createMap.build()); + } + + private CelExpr.Builder visit(CelExpr.Builder expr, CelCreateList.Builder createList) { + ImmutableList elementsBuilders = createList.getElementsBuilders(); + for (int i = 0; i < elementsBuilders.size(); i++) { + CelExpr.Builder elem = elementsBuilders.get(i); + createList.setElement(i, visit(elem).build()); + } + + return expr.setCreateList(createList.build()); + } + + private CelExpr.Builder visit(CelExpr.Builder expr, CelComprehension.Builder comprehension) { + comprehension.setIterRange(visit(comprehension.iterRange().toBuilder()).build()); + comprehension.setAccuInit(visit(comprehension.accuInit().toBuilder()).build()); + comprehension.setLoopCondition(visit(comprehension.loopCondition().toBuilder()).build()); + comprehension.setLoopStep(visit(comprehension.loopStep().toBuilder()).build()); + comprehension.setResult(visit(comprehension.result().toBuilder()).build()); + + return expr.setComprehension(comprehension.build()); + } + + private MutableExprVisitor( + ExprIdGenerator celExprIdGenerator, + CelExpr.Builder newExpr, + long exprId, + long iterationLimit) { + Preconditions.checkState(iterationLimit > 0L); + this.iterationLimit = iterationLimit; + this.celExprIdGenerator = celExprIdGenerator; + this.newExpr = newExpr; + this.exprIdToReplace = exprId; + } +} diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel b/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel index f2519c83c..2dcd3b2dc 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel @@ -21,6 +21,7 @@ java_library( "//common/ast:expr_util", "//common/navigation", "//optimizer:ast_optimizer", + "//optimizer:mutable_ast", "//optimizer:optimization_exception", "//parser:operator", "//runtime", @@ -43,6 +44,7 @@ java_library( "//common/ast", "//common/navigation", "//optimizer:ast_optimizer", + "//optimizer:mutable_ast", "//parser:operator", "@maven//:com_google_guava_guava", "@maven//:org_jspecify_jspecify", diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java b/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java index 272cd54f8..ed3eb9096 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java @@ -32,6 +32,7 @@ import dev.cel.common.navigation.CelNavigableExpr; import dev.cel.optimizer.CelAstOptimizer; import dev.cel.optimizer.CelOptimizationException; +import dev.cel.optimizer.MutableAst; import dev.cel.parser.Operator; import dev.cel.runtime.CelEvaluationException; import java.util.Collection; @@ -46,9 +47,10 @@ * calls and select statements with their evaluated result. */ public final class ConstantFoldingOptimizer implements CelAstOptimizer { - public static final ConstantFoldingOptimizer INSTANCE = new ConstantFoldingOptimizer(); private static final int MAX_ITERATION_COUNT = 400; + public static final ConstantFoldingOptimizer INSTANCE = new ConstantFoldingOptimizer(); + // Use optional.of and optional.none as sentinel function names for folding optional calls. // TODO: Leverage CelValue representation of Optionals instead when available. private static final String OPTIONAL_OF_FUNCTION = "optional.of"; @@ -56,6 +58,8 @@ public final class ConstantFoldingOptimizer implements CelAstOptimizer { private static final CelExpr OPTIONAL_NONE_EXPR = CelExpr.ofCallExpr(0, Optional.empty(), OPTIONAL_NONE_FUNCTION, ImmutableList.of()); + private final MutableAst mutableAst; + @Override public CelAbstractSyntaxTree optimize(CelNavigableAst navigableAst, Cel cel) throws CelOptimizationException { @@ -99,7 +103,7 @@ public CelAbstractSyntaxTree optimize(CelNavigableAst navigableAst, Cel cel) // If the output is a list, map, or struct which contains optional entries, then prune it // to make sure that the optionals, if resolved, do not surface in the output literal. CelAbstractSyntaxTree newAst = pruneOptionalElements(navigableAst); - return renumberIdsConsecutively(newAst); + return mutableAst.renumberIdsConsecutively(newAst); } private static boolean canFold(CelNavigableExpr navigableExpr) { @@ -194,7 +198,7 @@ private Optional maybeFold( } return maybeAdaptEvaluatedResult(result) - .map(celExpr -> replaceSubtree(ast, celExpr, expr.id())); + .map(celExpr -> mutableAst.replaceSubtree(ast, celExpr, expr.id())); } private Optional maybeAdaptEvaluatedResult(Object result) { @@ -247,7 +251,7 @@ private Optional maybeRewriteOptional( // An empty optional value was encountered. Rewrite the tree with optional.none call. // This is to account for other optional functions returning an empty optional value // e.g: optional.ofNonZeroValue(0) - return Optional.of(replaceSubtree(ast, OPTIONAL_NONE_EXPR, expr.id())); + return Optional.of(mutableAst.replaceSubtree(ast, OPTIONAL_NONE_EXPR, expr.id())); } } else if (!expr.callOrDefault().function().equals(OPTIONAL_OF_FUNCTION)) { Object unwrappedResult = optResult.get(); @@ -267,7 +271,7 @@ private Optional maybeRewriteOptional( .build()) .build()) .build(); - return Optional.of(replaceSubtree(ast, newOptionalOfCall, expr.id())); + return Optional.of(mutableAst.replaceSubtree(ast, newOptionalOfCall, expr.id())); } return Optional.empty(); @@ -296,7 +300,7 @@ private Optional maybePruneBranches( } CelExpr result = cond.constant().booleanValue() ? truthy : falsy; - return Optional.of(replaceSubtree(ast, result, expr.id())); + return Optional.of(mutableAst.replaceSubtree(ast, result, expr.id())); } else if (function.equals(Operator.IN.getFunction())) { CelExpr callArg = call.args().get(1); if (!callArg.exprKind().getKind().equals(Kind.CREATE_LIST)) { @@ -306,7 +310,7 @@ private Optional maybePruneBranches( CelCreateList haystack = callArg.createList(); if (haystack.elements().isEmpty()) { return Optional.of( - replaceSubtree( + mutableAst.replaceSubtree( ast, CelExpr.newBuilder().setConstant(CelConstant.ofValue(false)).build(), expr.id())); @@ -321,7 +325,7 @@ private Optional maybePruneBranches( if (elem.constantOrDefault().equals(needleValue) || elem.identOrDefault().equals(needleValue)) { return Optional.of( - replaceSubtree( + mutableAst.replaceSubtree( ast, CelExpr.newBuilder().setConstant(CelConstant.ofValue(true)).build(), expr.id())); @@ -354,16 +358,16 @@ private Optional maybeShortCircuitCall( } if (arg.constant().booleanValue() == shortCircuit) { - return Optional.of(replaceSubtree(ast, arg, expr.id())); + return Optional.of(mutableAst.replaceSubtree(ast, arg, expr.id())); } } ImmutableList newArgs = newArgsBuilder.build(); if (newArgs.isEmpty()) { - return Optional.of(replaceSubtree(ast, call.args().get(0), expr.id())); + return Optional.of(mutableAst.replaceSubtree(ast, call.args().get(0), expr.id())); } if (newArgs.size() == 1) { - return Optional.of(replaceSubtree(ast, newArgs.get(0), expr.id())); + return Optional.of(mutableAst.replaceSubtree(ast, newArgs.get(0), expr.id())); } // TODO: Support folding variadic AND/ORs. @@ -441,7 +445,7 @@ private CelAbstractSyntaxTree pruneOptionalListElements(CelAbstractSyntaxTree as updatedIndicesBuilder.add(newOptIndex); } - return replaceSubtree( + return mutableAst.replaceSubtree( ast, CelExpr.newBuilder() .setCreateList( @@ -488,7 +492,7 @@ private CelAbstractSyntaxTree pruneOptionalMapElements(CelAbstractSyntaxTree ast } if (modified) { - return replaceSubtree( + return mutableAst.replaceSubtree( ast, CelExpr.newBuilder() .setCreateMap( @@ -534,7 +538,7 @@ private CelAbstractSyntaxTree pruneOptionalStructElements( } if (modified) { - return replaceSubtree( + return mutableAst.replaceSubtree( ast, CelExpr.newBuilder() .setCreateStruct( @@ -549,5 +553,7 @@ private CelAbstractSyntaxTree pruneOptionalStructElements( return ast; } - private ConstantFoldingOptimizer() {} + private ConstantFoldingOptimizer() { + this.mutableAst = MutableAst.newInstance(MAX_ITERATION_COUNT); + } } diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java index d7eda5b44..8d057c74a 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java @@ -33,6 +33,7 @@ import dev.cel.common.navigation.CelNavigableExpr; import dev.cel.common.navigation.CelNavigableExpr.TraversalOrder; import dev.cel.optimizer.CelAstOptimizer; +import dev.cel.optimizer.MutableAst; import dev.cel.parser.Operator; import java.util.HashMap; import java.util.HashSet; @@ -59,7 +60,6 @@ * */ public class SubexpressionOptimizer implements CelAstOptimizer { - private static final SubexpressionOptimizer INSTANCE = new SubexpressionOptimizer(SubexpressionOptimizerOptions.newBuilder().build()); private static final String BIND_IDENTIFIER_PREFIX = "@r"; @@ -70,6 +70,7 @@ public class SubexpressionOptimizer implements CelAstOptimizer { stream(Standard.Function.values()).map(Standard.Function::getFunction)) .collect(toImmutableSet()); private final SubexpressionOptimizerOptions cseOptions; + private final MutableAst mutableAst; /** * Returns a default instance of common subexpression elimination optimizer with preconfigured @@ -90,13 +91,13 @@ public static SubexpressionOptimizer newInstance(SubexpressionOptimizerOptions c @Override public CelAbstractSyntaxTree optimize(CelNavigableAst navigableAst, Cel cel) { CelAbstractSyntaxTree astToModify = - mangleComprehensionIdentifierNames( + mutableAst.mangleComprehensionIdentifierNames( navigableAst.getAst(), MANGLED_COMPREHENSION_IDENTIFIER_PREFIX); CelSource sourceToModify = astToModify.getSource(); int bindIdentifierIndex = 0; int iterCount; - for (iterCount = 0; iterCount < cseOptions.maxIterationLimit(); iterCount++) { + for (iterCount = 0; iterCount < cseOptions.iterationLimit(); iterCount++) { CelExpr cseCandidate = findCseCandidate(astToModify).map(CelNavigableExpr::expr).orElse(null); if (cseCandidate == null) { break; @@ -122,7 +123,7 @@ public CelAbstractSyntaxTree optimize(CelNavigableAst navigableAst, Cel cel) { "No value present for expr ID: " + semanticallyEqualNode.id())); astToModify = - replaceSubtree( + mutableAst.replaceSubtree( astToModify, CelExpr.newBuilder() .setIdent(CelIdent.newBuilder().setName(bindIdentifier).build()) @@ -141,7 +142,7 @@ public CelAbstractSyntaxTree optimize(CelNavigableAst navigableAst, Cel cel) { // Insert the new bind call astToModify = - replaceSubtreeWithNewBindMacro( + mutableAst.replaceSubtreeWithNewBindMacro( astToModify, bindIdentifier, cseCandidate, lca.expr(), lca.id()); // Retain the existing macro calls in case if the bind identifiers are replacing a subtree @@ -149,7 +150,7 @@ public CelAbstractSyntaxTree optimize(CelNavigableAst navigableAst, Cel cel) { sourceToModify = astToModify.getSource(); } - if (iterCount >= cseOptions.maxIterationLimit()) { + if (iterCount >= cseOptions.iterationLimit()) { throw new IllegalStateException("Max iteration count reached."); } @@ -163,7 +164,7 @@ public CelAbstractSyntaxTree optimize(CelNavigableAst navigableAst, Cel cel) { CelAbstractSyntaxTree.newParsedAst(astToModify.getExpr(), CelSource.newBuilder().build()); } - return renumberIdsConsecutively(astToModify); + return mutableAst.renumberIdsConsecutively(astToModify); } private Stream getAllCseCandidatesStream( @@ -297,7 +298,7 @@ private static boolean isAllowedFunction(CelNavigableExpr navigableExpr) { */ private CelExpr normalizeForEquality(CelExpr celExpr) { int iterCount; - for (iterCount = 0; iterCount < cseOptions.maxIterationLimit(); iterCount++) { + for (iterCount = 0; iterCount < cseOptions.iterationLimit(); iterCount++) { CelExpr presenceTestExpr = CelNavigableExpr.fromExpr(celExpr) .allNodes() @@ -314,20 +315,20 @@ private CelExpr normalizeForEquality(CelExpr celExpr) { .setSelect(presenceTestExpr.select().toBuilder().setTestOnly(false).build()) .build(); - celExpr = replaceSubtree(celExpr, newExpr, newExpr.id()); + celExpr = mutableAst.replaceSubtree(celExpr, newExpr, newExpr.id()); } - if (iterCount >= cseOptions.maxIterationLimit()) { + if (iterCount >= cseOptions.iterationLimit()) { throw new IllegalStateException("Max iteration count reached."); } - return clearExprIds(celExpr); + return mutableAst.clearExprIds(celExpr); } /** Options to configure how Common Subexpression Elimination behave. */ @AutoValue public abstract static class SubexpressionOptimizerOptions { - public abstract int maxIterationLimit(); + public abstract int iterationLimit(); public abstract boolean populateMacroCalls(); @@ -339,7 +340,7 @@ public abstract static class Builder { * Limit the number of iteration while performing CSE. An exception is thrown if the iteration * count exceeds the set value. */ - public abstract Builder maxIterationLimit(int value); + public abstract Builder iterationLimit(int value); /** * Populate the macro_calls map in source_info with macro calls on the resulting optimized @@ -355,7 +356,7 @@ public abstract static class Builder { /** Returns a new options builder with recommended defaults pre-configured. */ public static Builder newBuilder() { return new AutoValue_SubexpressionOptimizer_SubexpressionOptimizerOptions.Builder() - .maxIterationLimit(500) + .iterationLimit(500) .populateMacroCalls(false); } @@ -364,5 +365,6 @@ public static Builder newBuilder() { private SubexpressionOptimizer(SubexpressionOptimizerOptions cseOptions) { this.cseOptions = cseOptions; + this.mutableAst = MutableAst.newInstance(cseOptions.iterationLimit()); } } diff --git a/optimizer/src/test/java/dev/cel/optimizer/MutableAstTest.java b/optimizer/src/test/java/dev/cel/optimizer/MutableAstTest.java index 8f79838c3..d027c6b8e 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/MutableAstTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/MutableAstTest.java @@ -16,6 +16,7 @@ import static com.google.common.collect.ImmutableMap.toImmutableMap; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertThrows; import com.google.common.collect.ImmutableMap; import com.google.testing.junit.testparameterinjector.TestParameterInjector; @@ -61,13 +62,14 @@ public class MutableAstTest { .build(); private static final CelUnparser CEL_UNPARSER = CelUnparserFactory.newUnparser(); + private static final MutableAst MUTABLE_AST = MutableAst.newInstance(1000); @Test public void constExpr() throws Exception { CelAbstractSyntaxTree ast = CEL.compile("10").getAst(); CelAbstractSyntaxTree mutatedAst = - MutableAst.replaceSubtree( + MUTABLE_AST.replaceSubtree( ast, CelExpr.newBuilder().setConstant(CelConstant.ofValue(true)).build(), 1); assertThat(mutatedAst.getExpr()) @@ -79,7 +81,7 @@ public void mutableAst_returnsParsedAst() throws Exception { CelAbstractSyntaxTree ast = CEL.compile("10").getAst(); CelAbstractSyntaxTree mutatedAst = - MutableAst.replaceSubtree( + MUTABLE_AST.replaceSubtree( ast, CelExpr.newBuilder().setConstant(CelConstant.ofValue(true)).build(), 1); assertThat(ast.isChecked()).isTrue(); @@ -91,7 +93,7 @@ public void mutableAst_nonMacro_sourceCleared() throws Exception { CelAbstractSyntaxTree ast = CEL.compile("10").getAst(); CelAbstractSyntaxTree mutatedAst = - MutableAst.replaceSubtree( + MUTABLE_AST.replaceSubtree( ast, CelExpr.newBuilder().setConstant(CelConstant.ofValue(true)).build(), 1); assertThat(mutatedAst.getSource().getDescription()).isEmpty(); @@ -105,7 +107,7 @@ public void mutableAst_macro_sourceMacroCallsPopulated() throws Exception { CelAbstractSyntaxTree ast = CEL.compile("has(TestAllTypes{}.single_int32)").getAst(); CelAbstractSyntaxTree mutatedAst = - MutableAst.replaceSubtree( + MUTABLE_AST.replaceSubtree( ast, CelExpr.newBuilder().setConstant(CelConstant.ofValue(true)).build(), 1); assertThat(mutatedAst.getSource().getDescription()).isEmpty(); @@ -126,7 +128,8 @@ public void replaceSubtree_rootReplacedWithMacro_macroCallPopulated( CelAbstractSyntaxTree ast2 = CEL.compile(source).getAst(); CelAbstractSyntaxTree mutatedAst = - MutableAst.replaceSubtree(ast, ast2, CelNavigableAst.fromAst(ast).getRoot().id()); + MUTABLE_AST.replaceSubtreeWithNewAst( + ast, ast2, CelNavigableAst.fromAst(ast).getRoot().id()); assertThat(mutatedAst.getSource().getMacroCalls()).hasSize(expectedMacroCallSize); assertThat(CEL_UNPARSER.unparse(mutatedAst)).isEqualTo(source); @@ -139,9 +142,9 @@ public void replaceSubtree_branchReplacedWithMacro_macroCallPopulated() throws E CelAbstractSyntaxTree ast2 = CEL.compile("[1].exists(x, x > 0)").getAst(); CelAbstractSyntaxTree mutatedAst = - MutableAst.replaceSubtree(ast, ast2, 3); // Replace false with the macro expr + MUTABLE_AST.replaceSubtreeWithNewAst(ast, ast2, 3); // Replace false with the macro expr CelAbstractSyntaxTree mutatedAst2 = - MutableAst.replaceSubtree(ast, ast2, 1); // Replace true with the macro expr + MUTABLE_AST.replaceSubtreeWithNewAst(ast, ast2, 1); // Replace true with the macro expr assertThat(mutatedAst.getSource().getMacroCalls()).hasSize(1); assertThat(CEL_UNPARSER.unparse(mutatedAst)).isEqualTo("true && [1].exists(x, x > 0)"); @@ -157,7 +160,7 @@ public void replaceSubtree_macroInsertedIntoExistingMacro_macroCallPopulated() t CelAbstractSyntaxTree ast2 = CEL.compile("[2].exists(y, y > 0)").getAst(); CelAbstractSyntaxTree mutatedAst = - MutableAst.replaceSubtree(ast, ast2, 9); // Replace true with the ast2 maro expr + MUTABLE_AST.replaceSubtreeWithNewAst(ast, ast2, 9); // Replace true with the ast2 maro expr assertThat(mutatedAst.getSource().getMacroCalls()).hasSize(2); assertThat(CEL_UNPARSER.unparse(mutatedAst)) @@ -180,7 +183,7 @@ public void replaceSubtreeWithNewBindMacro_replaceRoot() throws Exception { .build(); CelAbstractSyntaxTree mutatedAst = - MutableAst.replaceSubtreeWithNewBindMacro( + MUTABLE_AST.replaceSubtreeWithNewBindMacro( ast, variableName, CelExpr.ofConstantExpr(0, CelConstant.ofValue(3L)), @@ -212,7 +215,7 @@ public void replaceSubtreeWithNewBindMacro_nestedBindMacro_replaceComprehensionR // Act // Perform the initial replacement. (1 + 1) -> cel.bind(@r0, 3, @r0 + @r0) CelAbstractSyntaxTree mutatedAst = - MutableAst.replaceSubtreeWithNewBindMacro( + MUTABLE_AST.replaceSubtreeWithNewBindMacro( ast, variableName, CelExpr.ofConstantExpr(0, CelConstant.ofValue(3L)), @@ -261,7 +264,7 @@ public void replaceSubtreeWithNewBindMacro_nestedBindMacro_replaceComprehensionR .id(); // This should produce cel.bind(@r1, 1, cel.bind(@r0, 3, @r0 + @r0 + @r1 + @r1)) mutatedAst = - MutableAst.replaceSubtreeWithNewBindMacro( + MUTABLE_AST.replaceSubtreeWithNewBindMacro( mutatedAst, nestedVariableName, CelExpr.ofConstantExpr(0, CelConstant.ofValue(1L)), @@ -293,7 +296,7 @@ public void replaceSubtreeWithNewBindMacro_replaceRootWithNestedBindMacro() thro // Act // Perform the initial replacement. (1 + 1 + 3 + 3) -> cel.bind(@r0, 1, @r0 + @r0) + 3 + 3 CelAbstractSyntaxTree mutatedAst = - MutableAst.replaceSubtreeWithNewBindMacro( + MUTABLE_AST.replaceSubtreeWithNewBindMacro( ast, variableName, CelExpr.ofConstantExpr(0, CelConstant.ofValue(1L)), @@ -328,7 +331,7 @@ public void replaceSubtreeWithNewBindMacro_replaceRootWithNestedBindMacro() thro .build(); // Replace the root with the new result and a bind macro inserted mutatedAst = - MutableAst.replaceSubtreeWithNewBindMacro( + MUTABLE_AST.replaceSubtreeWithNewBindMacro( mutatedAst, nestedVariableName, CelExpr.ofConstantExpr(0, CelConstant.ofValue(3L)), @@ -349,7 +352,8 @@ public void replaceSubtree_macroReplacedWithConstExpr_macroCallCleared() throws CelAbstractSyntaxTree ast2 = CEL.compile("1").getAst(); CelAbstractSyntaxTree mutatedAst = - MutableAst.replaceSubtree(ast, ast2, CelNavigableAst.fromAst(ast).getRoot().id()); + MUTABLE_AST.replaceSubtreeWithNewAst( + ast, ast2, CelNavigableAst.fromAst(ast).getRoot().id()); assertThat(mutatedAst.getSource().getMacroCalls()).isEmpty(); assertThat(CEL_UNPARSER.unparse(mutatedAst)).isEqualTo("1"); @@ -365,7 +369,7 @@ public void globalCallExpr_replaceRoot() throws Exception { CelAbstractSyntaxTree ast = CEL.compile("1 + 2 + x").getAst(); CelAbstractSyntaxTree replacedAst = - MutableAst.replaceSubtree( + MUTABLE_AST.replaceSubtree( ast, CelExpr.newBuilder().setConstant(CelConstant.ofValue(10)).build(), 4); assertThat(replacedAst.getExpr()).isEqualTo(CelExpr.ofConstantExpr(7, CelConstant.ofValue(10))); @@ -380,7 +384,7 @@ public void globalCallExpr_replaceLeaf() throws Exception { CelAbstractSyntaxTree ast = CEL.compile("1 + 2 + x").getAst(); CelAbstractSyntaxTree replacedAst = - MutableAst.replaceSubtree( + MUTABLE_AST.replaceSubtree( ast, CelExpr.newBuilder().setConstant(CelConstant.ofValue(10)).build(), 1); assertThat(CEL_UNPARSER.unparse(replacedAst)).isEqualTo("10 + 2 + x"); @@ -395,7 +399,7 @@ public void globalCallExpr_replaceMiddleBranch() throws Exception { CelAbstractSyntaxTree ast = CEL.compile("1 + 2 + x").getAst(); CelAbstractSyntaxTree replacedAst = - MutableAst.replaceSubtree( + MUTABLE_AST.replaceSubtree( ast, CelExpr.newBuilder().setConstant(CelConstant.ofValue(10)).build(), 2); assertThat(CEL_UNPARSER.unparse(replacedAst)).isEqualTo("10 + x"); @@ -410,7 +414,7 @@ public void globalCallExpr_replaceMiddleBranch_withCallExpr() throws Exception { CelAbstractSyntaxTree ast = CEL.compile("1 + 2 + x").getAst(); CelAbstractSyntaxTree ast2 = CEL.compile("4 + 5 + 6").getAst(); - CelAbstractSyntaxTree replacedAst = MutableAst.replaceSubtree(ast, ast2.getExpr(), 2); + CelAbstractSyntaxTree replacedAst = MUTABLE_AST.replaceSubtree(ast, ast2.getExpr(), 2); assertThat(CEL_UNPARSER.unparse(replacedAst)).isEqualTo("4 + 5 + 6 + x"); } @@ -432,7 +436,7 @@ public void memberCallExpr_replaceLeafTarget() throws Exception { CelAbstractSyntaxTree ast = cel.compile("10.func(4.func(5))").getAst(); CelAbstractSyntaxTree replacedAst = - MutableAst.replaceSubtree( + MUTABLE_AST.replaceSubtree( ast, CelExpr.newBuilder().setConstant(CelConstant.ofValue(20)).build(), 3); assertThat(CEL_UNPARSER.unparse(replacedAst)).isEqualTo("10.func(20.func(5))"); @@ -455,7 +459,7 @@ public void memberCallExpr_replaceLeafArgument() throws Exception { CelAbstractSyntaxTree ast = cel.compile("10.func(4.func(5))").getAst(); CelAbstractSyntaxTree replacedAst = - MutableAst.replaceSubtree( + MUTABLE_AST.replaceSubtree( ast, CelExpr.newBuilder().setConstant(CelConstant.ofValue(20)).build(), 5); assertThat(CEL_UNPARSER.unparse(replacedAst)).isEqualTo("10.func(4.func(20))"); @@ -478,7 +482,7 @@ public void memberCallExpr_replaceMiddleBranchTarget() throws Exception { CelAbstractSyntaxTree ast = cel.compile("10.func(4.func(5))").getAst(); CelAbstractSyntaxTree replacedAst = - MutableAst.replaceSubtree( + MUTABLE_AST.replaceSubtree( ast, CelExpr.newBuilder().setConstant(CelConstant.ofValue(20)).build(), 1); assertThat(CEL_UNPARSER.unparse(replacedAst)).isEqualTo("20.func(4.func(5))"); @@ -501,7 +505,7 @@ public void memberCallExpr_replaceMiddleBranchArgument() throws Exception { CelAbstractSyntaxTree ast = cel.compile("10.func(4.func(5))").getAst(); CelAbstractSyntaxTree replacedAst = - MutableAst.replaceSubtree( + MUTABLE_AST.replaceSubtree( ast, CelExpr.newBuilder().setConstant(CelConstant.ofValue(20)).build(), 4); assertThat(CEL_UNPARSER.unparse(replacedAst)).isEqualTo("10.func(20)"); @@ -516,7 +520,7 @@ public void select_replaceField() throws Exception { CelAbstractSyntaxTree ast = CEL.compile("5 + msg.single_int64").getAst(); CelAbstractSyntaxTree replacedAst = - MutableAst.replaceSubtree( + MUTABLE_AST.replaceSubtree( ast, CelExpr.newBuilder() .setSelect( @@ -542,7 +546,7 @@ public void select_replaceOperand() throws Exception { CelAbstractSyntaxTree ast = CEL.compile("5 + msg.single_int64").getAst(); CelAbstractSyntaxTree replacedAst = - MutableAst.replaceSubtree( + MUTABLE_AST.replaceSubtree( ast, CelExpr.newBuilder().setIdent(CelIdent.newBuilder().setName("test").build()).build(), 3); @@ -558,7 +562,7 @@ public void list_replaceElement() throws Exception { CelAbstractSyntaxTree ast = CEL.compile("[2, 3, 4]").getAst(); CelAbstractSyntaxTree replacedAst = - MutableAst.replaceSubtree( + MUTABLE_AST.replaceSubtree( ast, CelExpr.newBuilder().setConstant(CelConstant.ofValue(5)).build(), 4); assertThat(CEL_UNPARSER.unparse(replacedAst)).isEqualTo("[2, 3, 5]"); @@ -573,7 +577,7 @@ public void createStruct_replaceValue() throws Exception { CelAbstractSyntaxTree ast = CEL.compile("TestAllTypes{single_int64: 2}").getAst(); CelAbstractSyntaxTree replacedAst = - MutableAst.replaceSubtree( + MUTABLE_AST.replaceSubtree( ast, CelExpr.newBuilder().setConstant(CelConstant.ofValue(5)).build(), 3); assertThat(CEL_UNPARSER.unparse(replacedAst)).isEqualTo("TestAllTypes{single_int64: 5}"); @@ -588,7 +592,7 @@ public void createMap_replaceKey() throws Exception { CelAbstractSyntaxTree ast = CEL.compile("{'a': 1}").getAst(); CelAbstractSyntaxTree replacedAst = - MutableAst.replaceSubtree( + MUTABLE_AST.replaceSubtree( ast, CelExpr.newBuilder().setConstant(CelConstant.ofValue(5)).build(), 3); assertThat(CEL_UNPARSER.unparse(replacedAst)).isEqualTo("{5: 1}"); @@ -603,7 +607,7 @@ public void createMap_replaceValue() throws Exception { CelAbstractSyntaxTree ast = CEL.compile("{'a': 1}").getAst(); CelAbstractSyntaxTree replacedAst = - MutableAst.replaceSubtree( + MUTABLE_AST.replaceSubtree( ast, CelExpr.newBuilder().setConstant(CelConstant.ofValue(5)).build(), 4); assertThat(CEL_UNPARSER.unparse(replacedAst)).isEqualTo("{\"a\": 5}"); @@ -614,7 +618,7 @@ public void comprehension_replaceIterRange() throws Exception { CelAbstractSyntaxTree ast = CEL.compile("[true].exists(i, i)").getAst(); CelAbstractSyntaxTree replacedAst = - MutableAst.replaceSubtree( + MUTABLE_AST.replaceSubtree( ast, CelExpr.newBuilder().setConstant(CelConstant.ofValue(false)).build(), 2); assertThat(CEL_UNPARSER.unparse(replacedAst)).isEqualTo("[false].exists(i, i)"); @@ -627,7 +631,7 @@ public void comprehension_replaceAccuInit() throws Exception { CelAbstractSyntaxTree ast = CEL.compile("[false].exists(i, i)").getAst(); CelAbstractSyntaxTree replacedAst = - MutableAst.replaceSubtree( + MUTABLE_AST.replaceSubtree( ast, CelExpr.newBuilder().setConstant(CelConstant.ofValue(true)).build(), 6); assertThat(CEL_UNPARSER.unparse(replacedAst)).isEqualTo("[false].exists(i, i)"); @@ -643,7 +647,7 @@ public void comprehension_replaceLoopStep() throws Exception { CelAbstractSyntaxTree ast = CEL.compile("[false].exists(i, i)").getAst(); CelAbstractSyntaxTree replacedAst = - MutableAst.replaceSubtree( + MUTABLE_AST.replaceSubtree( ast, CelExpr.newBuilder().setIdent(CelIdent.newBuilder().setName("test").build()).build(), 5); @@ -656,7 +660,7 @@ public void comprehension_replaceLoopStep() throws Exception { public void mangleComprehensionVariable_singleMacro() throws Exception { CelAbstractSyntaxTree ast = CEL.compile("[false].exists(i, i)").getAst(); - CelAbstractSyntaxTree mangledAst = MutableAst.mangleComprehensionIdentifierNames(ast, "@c"); + CelAbstractSyntaxTree mangledAst = MUTABLE_AST.mangleComprehensionIdentifierNames(ast, "@c"); assertThat(mangledAst.getExpr().toString()) .isEqualTo( @@ -716,7 +720,7 @@ public void mangleComprehensionVariable_singleMacro() throws Exception { public void mangleComprehensionVariable_nestedMacroWithShadowedVariables() throws Exception { CelAbstractSyntaxTree ast = CEL.compile("[x].exists(x, [x].exists(x, x == 1))").getAst(); - CelAbstractSyntaxTree mangledAst = MutableAst.mangleComprehensionIdentifierNames(ast, "@c"); + CelAbstractSyntaxTree mangledAst = MUTABLE_AST.mangleComprehensionIdentifierNames(ast, "@c"); assertThat(mangledAst.getExpr().toString()) .isEqualTo( @@ -833,7 +837,7 @@ public void mangleComprehensionVariable_nestedMacroWithShadowedVariables() throw public void mangleComprehensionVariable_hasMacro_noOp() throws Exception { CelAbstractSyntaxTree ast = CEL.compile("has(msg.single_int64)").getAst(); - CelAbstractSyntaxTree mangledAst = MutableAst.mangleComprehensionIdentifierNames(ast, "@c"); + CelAbstractSyntaxTree mangledAst = MUTABLE_AST.mangleComprehensionIdentifierNames(ast, "@c"); assertThat(CEL_UNPARSER.unparse(mangledAst)).isEqualTo("has(msg.single_int64)"); assertThat( @@ -843,6 +847,21 @@ public void mangleComprehensionVariable_hasMacro_noOp() throws Exception { assertConsistentMacroCalls(ast); } + @Test + public void replaceSubtree_iterationLimitReached_throws() throws Exception { + CelAbstractSyntaxTree ast = CEL.compile("true && false").getAst(); + MutableAst mutableAst = MutableAst.newInstance(1); + + IllegalStateException e = + assertThrows( + IllegalStateException.class, + () -> + mutableAst.replaceSubtree( + ast, CelExpr.ofConstantExpr(0, CelConstant.ofValue(false)), 1)); + + assertThat(e).hasMessageThat().isEqualTo("Max iteration count reached."); + } + /** * Asserts that the expressions that appears in source_info's macro calls are consistent with the * actual expr nodes in the AST. diff --git a/optimizer/src/test/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizerTest.java b/optimizer/src/test/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizerTest.java index eaa8c6ced..7b560adf4 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizerTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizerTest.java @@ -381,7 +381,7 @@ public void constantFold_astProducesConsistentlyNumberedIds() throws Exception { } @Test - public void maxIterationCountReached_throws() throws Exception { + public void iterationLimitReached_throws() throws Exception { StringBuilder sb = new StringBuilder(); sb.append("0"); for (int i = 1; i < 400; i++) { diff --git a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java index 98e1ff75a..b0cd64863 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java @@ -634,12 +634,12 @@ public void cse_applyConstFoldingAfter() throws Exception { } @Test - public void maxIterationLimitReached_throws() throws Exception { + public void iterationLimitReached_throws() throws Exception { StringBuilder largeExprBuilder = new StringBuilder(); - int maxIterationLimit = 100; - for (int i = 0; i < maxIterationLimit; i++) { + int iterationLimit = 100; + for (int i = 0; i < iterationLimit; i++) { largeExprBuilder.append("[1,2]"); - if (i < maxIterationLimit - 1) { + if (i < iterationLimit - 1) { largeExprBuilder.append("+"); } } @@ -653,7 +653,7 @@ public void maxIterationLimitReached_throws() throws Exception { .addAstOptimizers( SubexpressionOptimizer.newInstance( SubexpressionOptimizerOptions.newBuilder() - .maxIterationLimit(maxIterationLimit) + .iterationLimit(iterationLimit) .build())) .build() .optimize(ast)); From 7d28e89bddc4a15ec6f0a965d9dcd0bbab0919ba Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Fri, 19 Jan 2024 16:36:13 -0800 Subject: [PATCH 012/486] Add ConstantFoldingOptions PiperOrigin-RevId: 599969298 --- .../dev/cel/optimizer/optimizers/BUILD.bazel | 1 + .../optimizers/ConstantFoldingOptimizer.java | 55 +++++++++++++++++-- .../ConstantFoldingOptimizerTest.java | 19 ++++--- .../SubexpressionOptimizerTest.java | 2 +- 4 files changed, 63 insertions(+), 14 deletions(-) diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel b/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel index 2dcd3b2dc..10096a73d 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel @@ -14,6 +14,7 @@ java_library( tags = [ ], deps = [ + "//:auto_value", "//bundle:cel", "//common", "//common:compiler_common", diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java b/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java index ed3eb9096..2e63c0364 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java @@ -16,6 +16,7 @@ import static com.google.common.collect.ImmutableList.toImmutableList; import static com.google.common.collect.MoreCollectors.onlyElement; +import com.google.auto.value.AutoValue; import com.google.common.collect.ImmutableList; import dev.cel.bundle.Cel; import dev.cel.common.CelAbstractSyntaxTree; @@ -47,9 +48,22 @@ * calls and select statements with their evaluated result. */ public final class ConstantFoldingOptimizer implements CelAstOptimizer { - private static final int MAX_ITERATION_COUNT = 400; + private static final ConstantFoldingOptimizer INSTANCE = + new ConstantFoldingOptimizer(ConstantFoldingOptions.newBuilder().build()); - public static final ConstantFoldingOptimizer INSTANCE = new ConstantFoldingOptimizer(); + /** Returns a default instance of constant folding optimizer with preconfigured defaults. */ + public static ConstantFoldingOptimizer getInstance() { + return INSTANCE; + } + + /** + * Returns a new instance of constant folding optimizer configured with the provided {@link + * ConstantFoldingOptions}. + */ + public static ConstantFoldingOptimizer newInstance( + ConstantFoldingOptions constantFoldingOptions) { + return new ConstantFoldingOptimizer(constantFoldingOptions); + } // Use optional.of and optional.none as sentinel function names for folding optional calls. // TODO: Leverage CelValue representation of Optionals instead when available. @@ -58,6 +72,7 @@ public final class ConstantFoldingOptimizer implements CelAstOptimizer { private static final CelExpr OPTIONAL_NONE_EXPR = CelExpr.ofCallExpr(0, Optional.empty(), OPTIONAL_NONE_FUNCTION, ImmutableList.of()); + private final ConstantFoldingOptions constantFoldingOptions; private final MutableAst mutableAst; @Override @@ -67,7 +82,7 @@ public CelAbstractSyntaxTree optimize(CelNavigableAst navigableAst, Cel cel) int iterCount = 0; while (true) { iterCount++; - if (iterCount == MAX_ITERATION_COUNT) { + if (iterCount >= constantFoldingOptions.maxIterationLimit()) { throw new IllegalStateException("Max iteration count reached."); } Optional foldableExpr = @@ -553,7 +568,37 @@ private CelAbstractSyntaxTree pruneOptionalStructElements( return ast; } - private ConstantFoldingOptimizer() { - this.mutableAst = MutableAst.newInstance(MAX_ITERATION_COUNT); + /** Options to configure how Constant Folding behave. */ + @AutoValue + public abstract static class ConstantFoldingOptions { + public abstract int maxIterationLimit(); + + /** Builder for configuring the {@link ConstantFoldingOptions}. */ + @AutoValue.Builder + public abstract static class Builder { + + /** + * Limit the number of iteration while performing constant folding. An exception is thrown if + * the iteration count exceeds the set value. + */ + public abstract Builder maxIterationLimit(int value); + + public abstract ConstantFoldingOptions build(); + + Builder() {} + } + + /** Returns a new options builder with recommended defaults pre-configured. */ + public static Builder newBuilder() { + return new AutoValue_ConstantFoldingOptimizer_ConstantFoldingOptions.Builder() + .maxIterationLimit(400); + } + + ConstantFoldingOptions() {} + } + + private ConstantFoldingOptimizer(ConstantFoldingOptions constantFoldingOptions) { + this.constantFoldingOptions = constantFoldingOptions; + this.mutableAst = MutableAst.newInstance(constantFoldingOptions.maxIterationLimit()); } } diff --git a/optimizer/src/test/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizerTest.java b/optimizer/src/test/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizerTest.java index 7b560adf4..2ed564cc9 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizerTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizerTest.java @@ -30,6 +30,7 @@ import dev.cel.optimizer.CelOptimizationException; import dev.cel.optimizer.CelOptimizer; import dev.cel.optimizer.CelOptimizerFactory; +import dev.cel.optimizer.optimizers.ConstantFoldingOptimizer.ConstantFoldingOptions; import dev.cel.parser.CelStandardMacro; import dev.cel.parser.CelUnparser; import dev.cel.parser.CelUnparserFactory; @@ -53,7 +54,7 @@ public class ConstantFoldingOptimizerTest { private static final CelOptimizer CEL_OPTIMIZER = CelOptimizerFactory.standardCelOptimizerBuilder(CEL) - .addAstOptimizers(ConstantFoldingOptimizer.INSTANCE) + .addAstOptimizers(ConstantFoldingOptimizer.getInstance()) .build(); private static final CelUnparser CEL_UNPARSER = CelUnparserFactory.newUnparser(); @@ -211,7 +212,7 @@ public void constantFold_macros_macroCallMetadataPopulated(String source, String .build(); CelOptimizer celOptimizer = CelOptimizerFactory.standardCelOptimizerBuilder(cel) - .addAstOptimizers(ConstantFoldingOptimizer.INSTANCE) + .addAstOptimizers(ConstantFoldingOptimizer.getInstance()) .build(); CelAbstractSyntaxTree ast = cel.compile(source).getAst(); @@ -253,7 +254,7 @@ public void constantFold_macros_withoutMacroCallMetadata(String source) throws E .build(); CelOptimizer celOptimizer = CelOptimizerFactory.standardCelOptimizerBuilder(cel) - .addAstOptimizers(ConstantFoldingOptimizer.INSTANCE) + .addAstOptimizers(ConstantFoldingOptimizer.getInstance()) .build(); CelAbstractSyntaxTree ast = cel.compile(source).getAst(); @@ -299,7 +300,7 @@ public void constantFold_withMacroCallPopulated_comprehensionsAreReplacedWithNot .build(); CelOptimizer celOptimizer = CelOptimizerFactory.standardCelOptimizerBuilder(cel) - .addAstOptimizers(ConstantFoldingOptimizer.INSTANCE) + .addAstOptimizers(ConstantFoldingOptimizer.getInstance()) .build(); CelAbstractSyntaxTree ast = cel.compile("[1, 1 + 1, 1 + 1+ 1].map(i, i).filter(j, j % 2 == x)").getAst(); @@ -384,17 +385,19 @@ public void constantFold_astProducesConsistentlyNumberedIds() throws Exception { public void iterationLimitReached_throws() throws Exception { StringBuilder sb = new StringBuilder(); sb.append("0"); - for (int i = 1; i < 400; i++) { + for (int i = 1; i < 200; i++) { sb.append(" + ").append(i); - } // 0 + 1 + 2 + 3 + ... 400 + } // 0 + 1 + 2 + 3 + ... 200 Cel cel = CelFactory.standardCelBuilder() - .setOptions(CelOptions.current().maxParseRecursionDepth(400).build()) + .setOptions(CelOptions.current().maxParseRecursionDepth(200).build()) .build(); CelAbstractSyntaxTree ast = cel.compile(sb.toString()).getAst(); CelOptimizer optimizer = CelOptimizerFactory.standardCelOptimizerBuilder(cel) - .addAstOptimizers(ConstantFoldingOptimizer.INSTANCE) + .addAstOptimizers( + ConstantFoldingOptimizer.newInstance( + ConstantFoldingOptions.newBuilder().maxIterationLimit(200).build())) .build(); CelOptimizationException e = diff --git a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java index b0cd64863..9b516bdd5 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java @@ -616,7 +616,7 @@ public void cse_applyConstFoldingAfter() throws Exception { .addAstOptimizers( SubexpressionOptimizer.newInstance( SubexpressionOptimizerOptions.newBuilder().populateMacroCalls(true).build()), - ConstantFoldingOptimizer.INSTANCE) + ConstantFoldingOptimizer.getInstance()) .build(); CelAbstractSyntaxTree optimizedAst = optimizer.optimize(ast); From b7823ba8467783d9f0b728de6903b462ba0f9fca Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Wed, 24 Jan 2024 10:18:58 -0800 Subject: [PATCH 013/486] Prevent string.format injection when interpreter exception is being built PiperOrigin-RevId: 601159713 --- .../test/java/dev/cel/bundle/CelImplTest.java | 9 +++++++++ .../dev/cel/runtime/InterpreterException.java | 16 ++++++++++++++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/bundle/src/test/java/dev/cel/bundle/CelImplTest.java b/bundle/src/test/java/dev/cel/bundle/CelImplTest.java index 4cb3a75e7..f844246c3 100644 --- a/bundle/src/test/java/dev/cel/bundle/CelImplTest.java +++ b/bundle/src/test/java/dev/cel/bundle/CelImplTest.java @@ -1045,6 +1045,15 @@ public void program_wrongTypeComprehensionThrows() throws Exception { assertThat(e).hasMessageThat().contains("expected a list or a map"); } + @Test + public void program_stringFormatInjection_throwsEvaluationException() throws Exception { + Cel cel = standardCelBuilderWithMacros().build(); + CelRuntime.Program program = cel.createProgram(cel.compile("{}['%2000222222s']").getAst()); + + CelEvaluationException e = assertThrows(CelEvaluationException.class, program::eval); + assertThat(e).hasMessageThat().contains("evaluation error"); + } + @Test public void program_emptyTypeProviderConfig() throws Exception { Cel cel = standardCelBuilderWithMacros().build(); diff --git a/runtime/src/main/java/dev/cel/runtime/InterpreterException.java b/runtime/src/main/java/dev/cel/runtime/InterpreterException.java index 04b0968dc..2802726a4 100644 --- a/runtime/src/main/java/dev/cel/runtime/InterpreterException.java +++ b/runtime/src/main/java/dev/cel/runtime/InterpreterException.java @@ -16,6 +16,7 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.errorprone.annotations.CheckReturnValue; +import com.google.re2j.Pattern; import dev.cel.common.CelErrorCode; import dev.cel.common.CelRuntimeException; import dev.cel.common.annotations.Internal; @@ -31,6 +32,8 @@ */ @Internal public class InterpreterException extends Exception { + // Allow format specifiers of %d, %f, %s and %n only. + private static final Pattern ALLOWED_FORMAT_SPECIFIERS = Pattern.compile("%[^dfsn]"); private final CelErrorCode errorCode; public CelErrorCode getErrorCode() { @@ -47,7 +50,7 @@ public static class Builder { @SuppressWarnings({"AnnotateFormatMethod"}) // Format strings are optional. public Builder(String message, Object... args) { - this.message = args.length > 0 ? String.format(message, args) : message; + this.message = safeFormat(message, args); } @SuppressWarnings({"AnnotateFormatMethod"}) // Format strings are optional. @@ -64,7 +67,7 @@ public Builder(RuntimeException e, String message, Object... args) { this.cause = e; } - this.message = args.length > 0 ? String.format(message, args) : message; + this.message = safeFormat(message, args); } @CanIgnoreReturnValue @@ -97,6 +100,15 @@ public InterpreterException build() { cause, errorCode); } + + private static String safeFormat(String message, Object[] args) { + if (args.length == 0) { + return message; + } + + String sanitizedMessage = ALLOWED_FORMAT_SPECIFIERS.matcher(message).replaceAll(""); + return String.format(sanitizedMessage, args); + } } private InterpreterException(String message, Throwable cause, CelErrorCode errorCode) { From 90e9b2a9cd140b4659d091de0066eb94e9a51af0 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Thu, 25 Jan 2024 11:34:28 -0800 Subject: [PATCH 014/486] Allow cel.bind to be lazily evaluated PiperOrigin-RevId: 601512156 --- .../main/java/dev/cel/common/CelOptions.java | 9 + .../test/java/dev/cel/extensions/BUILD.bazel | 1 + .../extensions/CelBindingsExtensionsTest.java | 169 ++++++++++++++++-- .../SubexpressionOptimizerTest.java | 6 +- .../dev/cel/runtime/DefaultInterpreter.java | 77 +++++++- 5 files changed, 236 insertions(+), 26 deletions(-) diff --git a/common/src/main/java/dev/cel/common/CelOptions.java b/common/src/main/java/dev/cel/common/CelOptions.java index eaa812e2b..2032752ae 100644 --- a/common/src/main/java/dev/cel/common/CelOptions.java +++ b/common/src/main/java/dev/cel/common/CelOptions.java @@ -89,6 +89,8 @@ public abstract class CelOptions { public abstract boolean enableCelValue(); + public abstract boolean enableComprehensionLazyEval(); + public abstract int comprehensionMaxIterations(); public abstract Builder toBuilder(); @@ -179,6 +181,7 @@ public static Builder newBuilder() { .resolveTypeDependencies(true) .enableUnknownTracking(false) .enableCelValue(false) + .enableComprehensionLazyEval(false) .comprehensionMaxIterations(-1); } @@ -452,6 +455,12 @@ public abstract static class Builder { */ public abstract Builder comprehensionMaxIterations(int value); + /** + * Enables certain comprehension expressions to be lazily evaluated where safe. Currently, this + * only works for cel.bind. + */ + public abstract Builder enableComprehensionLazyEval(boolean value); + public abstract CelOptions build(); } } diff --git a/extensions/src/test/java/dev/cel/extensions/BUILD.bazel b/extensions/src/test/java/dev/cel/extensions/BUILD.bazel index b5b40d072..c71df2d8a 100644 --- a/extensions/src/test/java/dev/cel/extensions/BUILD.bazel +++ b/extensions/src/test/java/dev/cel/extensions/BUILD.bazel @@ -15,6 +15,7 @@ java_library( "//common/resources/testdata/proto2:messages_extensions_proto2_java_proto", "//common/resources/testdata/proto2:messages_proto2_java_proto", "//common/resources/testdata/proto2:test_all_types_java_proto", + "//common/resources/testdata/proto3:test_all_types_java_proto", "//common/types", "//common/types:type_providers", "//compiler", diff --git a/extensions/src/test/java/dev/cel/extensions/CelBindingsExtensionsTest.java b/extensions/src/test/java/dev/cel/extensions/CelBindingsExtensionsTest.java index 2b836dcc5..65657fbd1 100644 --- a/extensions/src/test/java/dev/cel/extensions/CelBindingsExtensionsTest.java +++ b/extensions/src/test/java/dev/cel/extensions/CelBindingsExtensionsTest.java @@ -17,20 +17,27 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertThrows; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.testing.junit.testparameterinjector.TestParameter; import com.google.testing.junit.testparameterinjector.TestParameterInjector; import com.google.testing.junit.testparameterinjector.TestParameters; import dev.cel.common.CelAbstractSyntaxTree; import dev.cel.common.CelFunctionDecl; +import dev.cel.common.CelOptions; import dev.cel.common.CelOverloadDecl; import dev.cel.common.CelValidationException; import dev.cel.common.types.SimpleType; +import dev.cel.common.types.StructTypeReference; import dev.cel.compiler.CelCompiler; import dev.cel.compiler.CelCompilerFactory; import dev.cel.parser.CelStandardMacro; import dev.cel.runtime.CelRuntime; import dev.cel.runtime.CelRuntime.CelFunctionBinding; import dev.cel.runtime.CelRuntimeFactory; +import dev.cel.testing.testdata.proto3.TestAllTypesProto.TestAllTypes; import java.util.Arrays; +import java.util.concurrent.atomic.AtomicInteger; import org.junit.Test; import org.junit.runner.RunWith; @@ -45,25 +52,46 @@ public final class CelBindingsExtensionsTest { private static final CelRuntime RUNTIME = CelRuntimeFactory.standardCelRuntimeBuilder().build(); + private enum BindingTestCase { + BOOL_LITERAL("cel.bind(t, true, t)"), + STRING_CONCAT("cel.bind(msg, \"hello\", msg + msg + msg) == \"hellohellohello\""), + NESTED_BINDS("cel.bind(t1, true, cel.bind(t2, true, t1 && t2))"), + NESTED_BINDS_SPECIFIER_ONLY( + "cel.bind(x, cel.bind(x, \"a\", x + x), x + \":\" + x) == \"aa:aa\""), + NESTED_BINDS_SPECIFIER_AND_VALUE( + "cel.bind(x, cel.bind(x, \"a\", x + x), cel.bind(y, x + x, y + \":\" + y)) ==" + + " \"aaaa:aaaa\""), + BIND_WITH_EXISTS_TRUE( + "cel.bind(valid_elems, [1, 2, 3], [3, 4, 5].exists(e, e in valid_elems))"), + BIND_WITH_EXISTS_FALSE("cel.bind(valid_elems, [1, 2, 3], ![4, 5].exists(e, e in valid_elems))"); + + private final String source; + + BindingTestCase(String source) { + this.source = source; + } + } + @Test - @TestParameters("{expr: 'cel.bind(t, true, t)', expectedResult: true}") - @TestParameters( - "{expr: 'cel.bind(msg, \"hello\", msg + msg + msg) == \"hellohellohello\"'," - + " expectedResult: true}") - @TestParameters( - "{expr: 'cel.bind(t1, true, cel.bind(t2, true, t1 && t2))', expectedResult: true}") - @TestParameters( - "{expr: 'cel.bind(valid_elems, [1, 2, 3], [3, 4, 5]" - + ".exists(e, e in valid_elems))', expectedResult: true}") - @TestParameters( - "{expr: 'cel.bind(valid_elems, [1, 2, 3], ![4, 5].exists(e, e in valid_elems))'," - + " expectedResult: true}") - public void binding_success(String expr, boolean expectedResult) throws Exception { - CelAbstractSyntaxTree ast = COMPILER.compile(expr).getAst(); + public void binding_success(@TestParameter BindingTestCase testCase) throws Exception { + CelAbstractSyntaxTree ast = COMPILER.compile(testCase.source).getAst(); CelRuntime.Program program = RUNTIME.createProgram(ast); - Object evaluatedResult = program.eval(); + boolean evaluatedResult = (boolean) program.eval(); + + assertThat(evaluatedResult).isTrue(); + } + + @Test + public void binding_lazyEval_success(@TestParameter BindingTestCase testCase) throws Exception { + CelAbstractSyntaxTree ast = COMPILER.compile(testCase.source).getAst(); + CelRuntime.Program program = + CelRuntimeFactory.standardCelRuntimeBuilder() + .setOptions(CelOptions.current().enableComprehensionLazyEval(true).build()) + .build() + .createProgram(ast); + boolean evaluatedResult = (boolean) program.eval(); - assertThat(evaluatedResult).isEqualTo(expectedResult); + assertThat(evaluatedResult).isTrue(); } @Test @@ -105,4 +133,113 @@ public void binding_throwsCompilationException(String expr) throws Exception { assertThat(e).hasMessageThat().contains("cel.bind() variable name must be a simple identifier"); } + + @Test + @SuppressWarnings("Immutable") // Test only + public void lazyBinding_bindingVarNeverReferenced() throws Exception { + CelCompiler celCompiler = + CelCompilerFactory.standardCelCompilerBuilder() + .setStandardMacros(CelStandardMacro.HAS) + .addMessageTypes(TestAllTypes.getDescriptor()) + .addVar("msg", StructTypeReference.create(TestAllTypes.getDescriptor().getFullName())) + .addLibraries(CelExtensions.bindings()) + .addFunctionDeclarations( + CelFunctionDecl.newFunctionDeclaration( + "get_true", + CelOverloadDecl.newGlobalOverload("get_true_overload", SimpleType.BOOL))) + .build(); + AtomicInteger invocation = new AtomicInteger(); + CelRuntime celRuntime = + CelRuntimeFactory.standardCelRuntimeBuilder() + .addMessageTypes(TestAllTypes.getDescriptor()) + .setOptions(CelOptions.current().enableComprehensionLazyEval(true).build()) + .addFunctionBindings( + CelFunctionBinding.from( + "get_true_overload", + ImmutableList.of(), + arg -> { + invocation.getAndIncrement(); + return true; + })) + .build(); + CelAbstractSyntaxTree ast = + celCompiler.compile("cel.bind(t, get_true(), has(msg.single_int64) ? t : false)").getAst(); + + boolean result = + (boolean) + celRuntime + .createProgram(ast) + .eval(ImmutableMap.of("msg", TestAllTypes.getDefaultInstance())); + + assertThat(result).isFalse(); + assertThat(invocation.get()).isEqualTo(0); + } + + @Test + @SuppressWarnings("Immutable") // Test only + public void lazyBinding_accuInitEvaluatedOnce() throws Exception { + CelCompiler celCompiler = + CelCompilerFactory.standardCelCompilerBuilder() + .addLibraries(CelExtensions.bindings()) + .addFunctionDeclarations( + CelFunctionDecl.newFunctionDeclaration( + "get_true", + CelOverloadDecl.newGlobalOverload("get_true_overload", SimpleType.BOOL))) + .build(); + AtomicInteger invocation = new AtomicInteger(); + CelRuntime celRuntime = + CelRuntimeFactory.standardCelRuntimeBuilder() + .setOptions(CelOptions.current().enableComprehensionLazyEval(true).build()) + .addFunctionBindings( + CelFunctionBinding.from( + "get_true_overload", + ImmutableList.of(), + arg -> { + invocation.getAndIncrement(); + return true; + })) + .build(); + CelAbstractSyntaxTree ast = + celCompiler.compile("cel.bind(t, get_true(), t && t && t && t)").getAst(); + + boolean result = (boolean) celRuntime.createProgram(ast).eval(); + + assertThat(result).isTrue(); + assertThat(invocation.get()).isEqualTo(1); + } + + @Test + @SuppressWarnings("Immutable") // Test only + public void lazyBinding_withNestedBinds() throws Exception { + CelCompiler celCompiler = + CelCompilerFactory.standardCelCompilerBuilder() + .addLibraries(CelExtensions.bindings()) + .addFunctionDeclarations( + CelFunctionDecl.newFunctionDeclaration( + "get_true", + CelOverloadDecl.newGlobalOverload("get_true_overload", SimpleType.BOOL))) + .build(); + AtomicInteger invocation = new AtomicInteger(); + CelRuntime celRuntime = + CelRuntimeFactory.standardCelRuntimeBuilder() + .setOptions(CelOptions.current().enableComprehensionLazyEval(true).build()) + .addFunctionBindings( + CelFunctionBinding.from( + "get_true_overload", + ImmutableList.of(), + arg -> { + invocation.getAndIncrement(); + return true; + })) + .build(); + CelAbstractSyntaxTree ast = + celCompiler + .compile("cel.bind(t1, get_true(), cel.bind(t2, get_true(), t1 && t2 && t1 && t2))") + .getAst(); + + boolean result = (boolean) celRuntime.createProgram(ast).eval(); + + assertThat(result).isTrue(); + assertThat(invocation.get()).isEqualTo(2); + } } diff --git a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java index 9b516bdd5..3ff4a249b 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java @@ -86,7 +86,11 @@ private static CelBuilder newCelBuilder() { .setContainer("dev.cel.testing.testdata.proto3") .setStandardMacros(CelStandardMacro.STANDARD_MACROS) .setOptions( - CelOptions.current().enableTimestampEpoch(true).populateMacroCalls(true).build()) + CelOptions.current() + .enableTimestampEpoch(true) + .enableComprehensionLazyEval(true) + .populateMacroCalls(true) + .build()) .addCompilerLibraries(CelOptionalLibrary.INSTANCE, CelExtensions.bindings()) .addRuntimeLibraries(CelOptionalLibrary.INSTANCE) .addFunctionDeclarations( diff --git a/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java b/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java index 44832a2e7..b0f18d873 100644 --- a/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java +++ b/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java @@ -275,11 +275,27 @@ private IntermediateResult resolveIdent(ExecutionFrame frame, CelExpr expr, Stri return IntermediateResult.create(typeValue); } + IntermediateResult cachedResult = frame.lookupLazilyEvaluatedResult(name).orElse(null); + if (cachedResult != null) { + return cachedResult; + } + IntermediateResult rawResult = frame.resolveSimpleName(name, expr.id()); + Object value = rawResult.value(); + boolean isLazyExpression = value instanceof LazyExpression; + if (isLazyExpression) { + value = evalInternal(frame, ((LazyExpression) value).celExpr).value(); + } // Value resolved from Binding, it could be Message, PartialMessage or unbound(null) - Object value = InterpreterUtil.strict(typeProvider.adapt(rawResult.value())); - return IntermediateResult.create(rawResult.attribute(), value); + value = InterpreterUtil.strict(typeProvider.adapt(value)); + IntermediateResult result = IntermediateResult.create(rawResult.attribute(), value); + + if (isLazyExpression) { + frame.cacheLazilyEvaluatedResult(name, result); + } + + return result; } private IntermediateResult evalSelect(ExecutionFrame frame, CelExpr expr, CelSelect selectExpr) @@ -404,7 +420,7 @@ private IntermediateResult evalCall(ExecutionFrame frame, CelExpr expr, CelCall return IntermediateResult.create(attr, unknowns.get()); } - Object[] argArray = Arrays.stream(argResults).map(v -> v.value()).toArray(); + Object[] argArray = Arrays.stream(argResults).map(IntermediateResult::value).toArray(); return IntermediateResult.create( attr, @@ -754,11 +770,12 @@ private IntermediateResult evalStruct( fields.put(entry.fieldKey(), value); } - Optional unknowns = argChecker.maybeUnknowns(); - if (unknowns.isPresent()) { - return IntermediateResult.create(unknowns.get()); - } - return IntermediateResult.create(typeProvider.createMessage(reference.name(), fields)); + return argChecker + .maybeUnknowns() + .map(IntermediateResult::create) + .orElseGet( + () -> + IntermediateResult.create(typeProvider.createMessage(reference.name(), fields))); } // Evaluates the expression and returns a value-or-throwable. @@ -796,7 +813,12 @@ private IntermediateResult evalComprehension( .setLocation(metadata, compre.iterRange().id()) .build(); } - IntermediateResult accuValue = evalNonstrictly(frame, compre.accuInit()); + IntermediateResult accuValue; + if (celOptions.enableComprehensionLazyEval() && LazyExpression.isLazilyEvaluable(compre)) { + accuValue = IntermediateResult.create(new LazyExpression(compre.accuInit())); + } else { + accuValue = evalNonstrictly(frame, compre.accuInit()); + } int i = 0; for (Object elem : iterRange) { frame.incrementIterations(); @@ -831,11 +853,39 @@ private IntermediateResult evalComprehension( } } + /** Contains a CelExpr that is to be lazily evaluated. */ + private static class LazyExpression { + private final CelExpr celExpr; + + /** + * Checks whether the provided expression can be evaluated lazily then cached. For example, the + * accumulator initializer in `cel.bind` macro is a good candidate because it never needs to be + * updated after being evaluated once. + */ + private static boolean isLazilyEvaluable(CelComprehension comprehension) { + // For now, just handle cel.bind. cel.block will be a future addition. + return comprehension + .loopCondition() + .constantOrDefault() + .getKind() + .equals(CelConstant.Kind.BOOLEAN_VALUE) + && !comprehension.loopCondition().constant().booleanValue() + && comprehension.iterVar().equals("#unused") + && comprehension.iterRange().exprKind().getKind().equals(ExprKind.Kind.CREATE_LIST) + && comprehension.iterRange().createList().elements().isEmpty(); + } + + private LazyExpression(CelExpr celExpr) { + this.celExpr = celExpr; + } + } + /** This class tracks the state meaningful to a single evaluation pass. */ private static class ExecutionFrame { private final CelEvaluationListener evaluationListener; private final int maxIterations; private final ArrayDeque resolvers; + private final Map lazyEvalResultCache; private RuntimeUnknownResolver currentResolver; private int iterations; @@ -848,6 +898,7 @@ private ExecutionFrame( this.resolvers.add(resolver); this.currentResolver = resolver; this.maxIterations = maxIterations; + this.lazyEvalResultCache = new HashMap<>(); } private CelEvaluationListener getEvaluationListener() { @@ -878,6 +929,14 @@ private Optional resolveAttribute(CelAttribute attr) { return currentResolver.resolveAttribute(attr); } + private Optional lookupLazilyEvaluatedResult(String name) { + return Optional.ofNullable(lazyEvalResultCache.get(name)); + } + + private void cacheLazilyEvaluatedResult(String name, IntermediateResult result) { + lazyEvalResultCache.put(name, result); + } + private void pushScope(ImmutableMap scope) { RuntimeUnknownResolver scopedResolver = currentResolver.withScope(scope); currentResolver = scopedResolver; From e69a4dd6ece01771ed9857473a285be81f04516e Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Thu, 25 Jan 2024 16:28:15 -0800 Subject: [PATCH 015/486] Enable lazy comprehension eval by default PiperOrigin-RevId: 601600918 --- common/src/main/java/dev/cel/common/CelOptions.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/src/main/java/dev/cel/common/CelOptions.java b/common/src/main/java/dev/cel/common/CelOptions.java index 2032752ae..29202945b 100644 --- a/common/src/main/java/dev/cel/common/CelOptions.java +++ b/common/src/main/java/dev/cel/common/CelOptions.java @@ -181,7 +181,7 @@ public static Builder newBuilder() { .resolveTypeDependencies(true) .enableUnknownTracking(false) .enableCelValue(false) - .enableComprehensionLazyEval(false) + .enableComprehensionLazyEval(true) .comprehensionMaxIterations(-1); } From 948fd365064648052aecf861483d82be259d0e06 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Thu, 25 Jan 2024 16:58:23 -0800 Subject: [PATCH 016/486] Add SafeStringFormatter. Address fuzzing issue around CelValidationException. PiperOrigin-RevId: 601609078 --- common/internal/BUILD.bazel | 5 ++ .../src/main/java/dev/cel/common/BUILD.bazel | 1 + .../main/java/dev/cel/common/CelIssue.java | 3 +- .../cel/common/CelValidationException.java | 22 ++++++++- .../java/dev/cel/common/internal/BUILD.bazel | 11 +++++ .../common/internal/SafeStringFormatter.java | 48 +++++++++++++++++++ .../src/test/java/dev/cel/common/BUILD.bazel | 1 + .../common/CelValidationExceptionTest.java | 42 ++++++++++++++++ .../src/main/java/dev/cel/runtime/BUILD.bazel | 1 + .../dev/cel/runtime/InterpreterException.java | 17 ++----- 10 files changed, 134 insertions(+), 17 deletions(-) create mode 100644 common/src/main/java/dev/cel/common/internal/SafeStringFormatter.java create mode 100644 common/src/test/java/dev/cel/common/CelValidationExceptionTest.java diff --git a/common/internal/BUILD.bazel b/common/internal/BUILD.bazel index 95b367684..6293804f2 100644 --- a/common/internal/BUILD.bazel +++ b/common/internal/BUILD.bazel @@ -67,3 +67,8 @@ java_library( name = "cel_descriptor_pools", exports = ["//common/src/main/java/dev/cel/common/internal:cel_descriptor_pools"], ) + +java_library( + name = "safe_string_formatter", + exports = ["//common/src/main/java/dev/cel/common/internal:safe_string_formatter"], +) diff --git a/common/src/main/java/dev/cel/common/BUILD.bazel b/common/src/main/java/dev/cel/common/BUILD.bazel index dd39523fc..31b593708 100644 --- a/common/src/main/java/dev/cel/common/BUILD.bazel +++ b/common/src/main/java/dev/cel/common/BUILD.bazel @@ -64,6 +64,7 @@ java_library( ":common", "//:auto_value", "//common/annotations", + "//common/internal:safe_string_formatter", "//common/types:cel_types", "//common/types:type_providers", "@cel_spec//proto/cel/expr:expr_java_proto", diff --git a/common/src/main/java/dev/cel/common/CelIssue.java b/common/src/main/java/dev/cel/common/CelIssue.java index 4ad48ceac..7f7417a53 100644 --- a/common/src/main/java/dev/cel/common/CelIssue.java +++ b/common/src/main/java/dev/cel/common/CelIssue.java @@ -17,6 +17,7 @@ import com.google.auto.value.AutoValue; import com.google.errorprone.annotations.CheckReturnValue; import com.google.errorprone.annotations.Immutable; +import dev.cel.common.internal.SafeStringFormatter; import java.util.Optional; import java.util.PrimitiveIterator; @@ -76,7 +77,7 @@ public static CelIssue formatError(int line, int column, String message) { public String toDisplayString(CelSource source) { // Based onhttps://github.com/google/cel-go/blob/v0.5.1/common/error.go#L42. String result = - String.format( + SafeStringFormatter.format( "%s: %s:%d:%d: %s", getSeverity(), source.getDescription(), diff --git a/common/src/main/java/dev/cel/common/CelValidationException.java b/common/src/main/java/dev/cel/common/CelValidationException.java index 84f5bcbf0..ef136f8a7 100644 --- a/common/src/main/java/dev/cel/common/CelValidationException.java +++ b/common/src/main/java/dev/cel/common/CelValidationException.java @@ -18,18 +18,21 @@ import com.google.common.base.Joiner; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; +import java.util.List; /** Base class for all checked exceptions explicitly thrown by the library during parsing. */ public final class CelValidationException extends CelException { private static final Joiner JOINER = Joiner.on('\n'); + // Truncates all errors beyond this limit in the message. + private static final int MAX_ERRORS_TO_REPORT = 1000; private final CelSource source; private final ImmutableList errors; @VisibleForTesting - public CelValidationException(CelSource source, Iterable errors) { - super(JOINER.join(Iterables.transform(errors, error -> error.toDisplayString(source)))); + public CelValidationException(CelSource source, List errors) { + super(safeJoinErrorMessage(source, errors)); this.source = source; this.errors = ImmutableList.copyOf(errors); } @@ -41,6 +44,21 @@ public CelValidationException(CelSource source, Iterable errors) { this.errors = ImmutableList.copyOf(errors); } + private static String safeJoinErrorMessage(CelSource source, List errors) { + if (errors.size() <= MAX_ERRORS_TO_REPORT) { + return JOINER.join(Iterables.transform(errors, error -> error.toDisplayString(source))); + } + + List truncatedErrors = errors.subList(0, MAX_ERRORS_TO_REPORT); + StringBuilder sb = new StringBuilder(); + JOINER.appendTo( + sb, Iterables.transform(truncatedErrors, error -> error.toDisplayString(source))); + sb.append( + String.format("%n...and %d more errors (truncated)", errors.size() - MAX_ERRORS_TO_REPORT)); + + return sb.toString(); + } + /** Returns the {@link CelSource} that was being validated. */ public CelSource getSource() { return source; diff --git a/common/src/main/java/dev/cel/common/internal/BUILD.bazel b/common/src/main/java/dev/cel/common/internal/BUILD.bazel index 88d7dd517..e373f442b 100644 --- a/common/src/main/java/dev/cel/common/internal/BUILD.bazel +++ b/common/src/main/java/dev/cel/common/internal/BUILD.bazel @@ -227,3 +227,14 @@ java_library( "@maven//:com_google_protobuf_protobuf_java", ], ) + +java_library( + name = "safe_string_formatter", + srcs = ["SafeStringFormatter.java"], + tags = [ + ], + deps = [ + "//common/annotations", + "@maven//:com_google_re2j_re2j", + ], +) diff --git a/common/src/main/java/dev/cel/common/internal/SafeStringFormatter.java b/common/src/main/java/dev/cel/common/internal/SafeStringFormatter.java new file mode 100644 index 000000000..7c22e834d --- /dev/null +++ b/common/src/main/java/dev/cel/common/internal/SafeStringFormatter.java @@ -0,0 +1,48 @@ +// Copyright 2024 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.common.internal; + +import com.google.re2j.Pattern; +import dev.cel.common.annotations.Internal; + +/** + * {@link SafeStringFormatter} is a wrapper around JDK's {@link String#format}. It prevents any + * unsafe string.format calls by only allowing known formatting specifiers to be provided. + * + *

CEL Library Internals. Do Not Use. + */ +@Internal +public final class SafeStringFormatter { + // Allow format specifiers of %d, %f, %s and %n only. + private static final Pattern FORBIDDEN_FORMAT_SPECIFIERS = Pattern.compile("%[^dfsn]"); + + /** + * Performs a safe {@link String#format}. + * + * @param format A format string. Only %d, %f, %s and %n are allowed as formatting specifiers. All + * other formatting specifiers will be stripped out. + * @return A formatted string + */ + public static String format(String format, Object... args) { + if (args.length == 0) { + return format; + } + + String sanitizedMessage = FORBIDDEN_FORMAT_SPECIFIERS.matcher(format).replaceAll(""); + return String.format(sanitizedMessage, args); + } + + private SafeStringFormatter() {} +} diff --git a/common/src/test/java/dev/cel/common/BUILD.bazel b/common/src/test/java/dev/cel/common/BUILD.bazel index 6001ed1b4..d22f00e7f 100644 --- a/common/src/test/java/dev/cel/common/BUILD.bazel +++ b/common/src/test/java/dev/cel/common/BUILD.bazel @@ -11,6 +11,7 @@ java_library( deps = [ "//:java_truth", "//common", + "//common:compiler_common", "//common:features", "//common:options", "//common:proto_v1alpha1_ast", diff --git a/common/src/test/java/dev/cel/common/CelValidationExceptionTest.java b/common/src/test/java/dev/cel/common/CelValidationExceptionTest.java new file mode 100644 index 000000000..be428a64c --- /dev/null +++ b/common/src/test/java/dev/cel/common/CelValidationExceptionTest.java @@ -0,0 +1,42 @@ +// Copyright 2024 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.common; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.common.collect.ImmutableList; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class CelValidationExceptionTest { + + @Test + public void construct_withLargeErrorCount() { + ImmutableList.Builder issueBuilder = ImmutableList.builder(); + for (int i = 0; i < 1500; i++) { + issueBuilder.add(CelIssue.formatError(i + 1, i + 1, "generic error")); + } + + CelValidationException celValidationException = + new CelValidationException(CelSource.newBuilder().build(), issueBuilder.build()); + + assertThat(celValidationException.getErrors()).hasSize(1500); + assertThat(celValidationException) + .hasMessageThat() + .endsWith("...and 500 more errors (truncated)"); + } +} diff --git a/runtime/src/main/java/dev/cel/runtime/BUILD.bazel b/runtime/src/main/java/dev/cel/runtime/BUILD.bazel index d713b5113..f9d3dc6a2 100644 --- a/runtime/src/main/java/dev/cel/runtime/BUILD.bazel +++ b/runtime/src/main/java/dev/cel/runtime/BUILD.bazel @@ -54,6 +54,7 @@ java_library( "//common/internal:comparison_functions", "//common/internal:default_message_factory", "//common/internal:dynamic_proto", + "//common/internal:safe_string_formatter", "//common/types", "//common/types:type_providers", "@cel_spec//proto/cel/expr:expr_java_proto", diff --git a/runtime/src/main/java/dev/cel/runtime/InterpreterException.java b/runtime/src/main/java/dev/cel/runtime/InterpreterException.java index 2802726a4..98595ee88 100644 --- a/runtime/src/main/java/dev/cel/runtime/InterpreterException.java +++ b/runtime/src/main/java/dev/cel/runtime/InterpreterException.java @@ -16,10 +16,10 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.errorprone.annotations.CheckReturnValue; -import com.google.re2j.Pattern; import dev.cel.common.CelErrorCode; import dev.cel.common.CelRuntimeException; import dev.cel.common.annotations.Internal; +import dev.cel.common.internal.SafeStringFormatter; import org.jspecify.nullness.Nullable; /** @@ -32,8 +32,6 @@ */ @Internal public class InterpreterException extends Exception { - // Allow format specifiers of %d, %f, %s and %n only. - private static final Pattern ALLOWED_FORMAT_SPECIFIERS = Pattern.compile("%[^dfsn]"); private final CelErrorCode errorCode; public CelErrorCode getErrorCode() { @@ -50,7 +48,7 @@ public static class Builder { @SuppressWarnings({"AnnotateFormatMethod"}) // Format strings are optional. public Builder(String message, Object... args) { - this.message = safeFormat(message, args); + this.message = SafeStringFormatter.format(message, args); } @SuppressWarnings({"AnnotateFormatMethod"}) // Format strings are optional. @@ -67,7 +65,7 @@ public Builder(RuntimeException e, String message, Object... args) { this.cause = e; } - this.message = safeFormat(message, args); + this.message = SafeStringFormatter.format(message, args); } @CanIgnoreReturnValue @@ -100,15 +98,6 @@ public InterpreterException build() { cause, errorCode); } - - private static String safeFormat(String message, Object[] args) { - if (args.length == 0) { - return message; - } - - String sanitizedMessage = ALLOWED_FORMAT_SPECIFIERS.matcher(message).replaceAll(""); - return String.format(sanitizedMessage, args); - } } private InterpreterException(String message, Throwable cause, CelErrorCode errorCode) { From c24b99540a6908294343eb583b465d1b15fd9d3f Mon Sep 17 00:00:00 2001 From: Chris Kennelly Date: Mon, 29 Jan 2024 17:33:31 -0800 Subject: [PATCH 017/486] No public description PiperOrigin-RevId: 602549697 --- .../src/main/resources/testdata/proto2/test_all_types.proto | 4 ++-- .../src/main/resources/testdata/proto3/test_all_types.proto | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/common/src/main/resources/testdata/proto2/test_all_types.proto b/common/src/main/resources/testdata/proto2/test_all_types.proto index 6da50a05b..7307b2970 100644 --- a/common/src/main/resources/testdata/proto2/test_all_types.proto +++ b/common/src/main/resources/testdata/proto2/test_all_types.proto @@ -108,7 +108,7 @@ message TestAllTypes { repeated NestedEnum repeated_nested_enum = 52; repeated string repeated_string_piece = 53 [ctype = STRING_PIECE]; repeated string repeated_cord = 54 [ctype = CORD]; - repeated NestedMessage repeated_lazy_message = 55 [lazy = true]; + repeated NestedMessage repeated_lazy_message = 55; // Map map map_string_string = 61; @@ -131,4 +131,4 @@ enum GlobalEnum { GOO = 0; GAR = 1; GAZ = 2; -} \ No newline at end of file +} diff --git a/common/src/main/resources/testdata/proto3/test_all_types.proto b/common/src/main/resources/testdata/proto3/test_all_types.proto index 26df9d899..2ed2d9900 100644 --- a/common/src/main/resources/testdata/proto3/test_all_types.proto +++ b/common/src/main/resources/testdata/proto3/test_all_types.proto @@ -110,7 +110,7 @@ message TestAllTypes { repeated NestedEnum repeated_nested_enum = 52; repeated string repeated_string_piece = 53 [ctype = STRING_PIECE]; repeated string repeated_cord = 54 [ctype = CORD]; - repeated NestedMessage repeated_lazy_message = 55 [lazy = true]; + repeated NestedMessage repeated_lazy_message = 55; // Map map map_int32_int64 = 56; From 3a7345923815579a09e64629344d65642464fb31 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Tue, 30 Jan 2024 10:14:52 -0800 Subject: [PATCH 018/486] Remove enableComprehensionLazyEval flag PiperOrigin-RevId: 602764888 --- .../main/java/dev/cel/common/CelOptions.java | 8 -------- .../extensions/CelBindingsExtensionsTest.java | 17 ----------------- .../optimizers/SubexpressionOptimizerTest.java | 6 +----- .../dev/cel/runtime/DefaultInterpreter.java | 2 +- 4 files changed, 2 insertions(+), 31 deletions(-) diff --git a/common/src/main/java/dev/cel/common/CelOptions.java b/common/src/main/java/dev/cel/common/CelOptions.java index 29202945b..f4082f918 100644 --- a/common/src/main/java/dev/cel/common/CelOptions.java +++ b/common/src/main/java/dev/cel/common/CelOptions.java @@ -89,7 +89,6 @@ public abstract class CelOptions { public abstract boolean enableCelValue(); - public abstract boolean enableComprehensionLazyEval(); public abstract int comprehensionMaxIterations(); @@ -181,7 +180,6 @@ public static Builder newBuilder() { .resolveTypeDependencies(true) .enableUnknownTracking(false) .enableCelValue(false) - .enableComprehensionLazyEval(true) .comprehensionMaxIterations(-1); } @@ -455,12 +453,6 @@ public abstract static class Builder { */ public abstract Builder comprehensionMaxIterations(int value); - /** - * Enables certain comprehension expressions to be lazily evaluated where safe. Currently, this - * only works for cel.bind. - */ - public abstract Builder enableComprehensionLazyEval(boolean value); - public abstract CelOptions build(); } } diff --git a/extensions/src/test/java/dev/cel/extensions/CelBindingsExtensionsTest.java b/extensions/src/test/java/dev/cel/extensions/CelBindingsExtensionsTest.java index 65657fbd1..a11a6a93b 100644 --- a/extensions/src/test/java/dev/cel/extensions/CelBindingsExtensionsTest.java +++ b/extensions/src/test/java/dev/cel/extensions/CelBindingsExtensionsTest.java @@ -24,7 +24,6 @@ import com.google.testing.junit.testparameterinjector.TestParameters; import dev.cel.common.CelAbstractSyntaxTree; import dev.cel.common.CelFunctionDecl; -import dev.cel.common.CelOptions; import dev.cel.common.CelOverloadDecl; import dev.cel.common.CelValidationException; import dev.cel.common.types.SimpleType; @@ -81,19 +80,6 @@ public void binding_success(@TestParameter BindingTestCase testCase) throws Exce assertThat(evaluatedResult).isTrue(); } - @Test - public void binding_lazyEval_success(@TestParameter BindingTestCase testCase) throws Exception { - CelAbstractSyntaxTree ast = COMPILER.compile(testCase.source).getAst(); - CelRuntime.Program program = - CelRuntimeFactory.standardCelRuntimeBuilder() - .setOptions(CelOptions.current().enableComprehensionLazyEval(true).build()) - .build() - .createProgram(ast); - boolean evaluatedResult = (boolean) program.eval(); - - assertThat(evaluatedResult).isTrue(); - } - @Test @TestParameters("{expr: 'false.bind(false, false, false)'}") public void binding_nonCelNamespace_success(String expr) throws Exception { @@ -152,7 +138,6 @@ public void lazyBinding_bindingVarNeverReferenced() throws Exception { CelRuntime celRuntime = CelRuntimeFactory.standardCelRuntimeBuilder() .addMessageTypes(TestAllTypes.getDescriptor()) - .setOptions(CelOptions.current().enableComprehensionLazyEval(true).build()) .addFunctionBindings( CelFunctionBinding.from( "get_true_overload", @@ -189,7 +174,6 @@ public void lazyBinding_accuInitEvaluatedOnce() throws Exception { AtomicInteger invocation = new AtomicInteger(); CelRuntime celRuntime = CelRuntimeFactory.standardCelRuntimeBuilder() - .setOptions(CelOptions.current().enableComprehensionLazyEval(true).build()) .addFunctionBindings( CelFunctionBinding.from( "get_true_overload", @@ -222,7 +206,6 @@ public void lazyBinding_withNestedBinds() throws Exception { AtomicInteger invocation = new AtomicInteger(); CelRuntime celRuntime = CelRuntimeFactory.standardCelRuntimeBuilder() - .setOptions(CelOptions.current().enableComprehensionLazyEval(true).build()) .addFunctionBindings( CelFunctionBinding.from( "get_true_overload", diff --git a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java index 3ff4a249b..9b516bdd5 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java @@ -86,11 +86,7 @@ private static CelBuilder newCelBuilder() { .setContainer("dev.cel.testing.testdata.proto3") .setStandardMacros(CelStandardMacro.STANDARD_MACROS) .setOptions( - CelOptions.current() - .enableTimestampEpoch(true) - .enableComprehensionLazyEval(true) - .populateMacroCalls(true) - .build()) + CelOptions.current().enableTimestampEpoch(true).populateMacroCalls(true).build()) .addCompilerLibraries(CelOptionalLibrary.INSTANCE, CelExtensions.bindings()) .addRuntimeLibraries(CelOptionalLibrary.INSTANCE) .addFunctionDeclarations( diff --git a/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java b/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java index b0f18d873..f21cd18bf 100644 --- a/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java +++ b/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java @@ -814,7 +814,7 @@ private IntermediateResult evalComprehension( .build(); } IntermediateResult accuValue; - if (celOptions.enableComprehensionLazyEval() && LazyExpression.isLazilyEvaluable(compre)) { + if (LazyExpression.isLazilyEvaluable(compre)) { accuValue = IntermediateResult.create(new LazyExpression(compre.accuInit())); } else { accuValue = evalNonstrictly(frame, compre.accuInit()); From 61b20df0f370f58846c6e47f157462ee5f4b58e1 Mon Sep 17 00:00:00 2001 From: cpovirk Date: Tue, 30 Jan 2024 13:27:32 -0800 Subject: [PATCH 019/486] No public description PiperOrigin-RevId: 602823902 --- .../dev/cel/checker/CelIdentDeclTest.java | 8 +- .../ProtoTypeMaskTypeProviderTest.java | 14 +-- .../dev/cel/checker/TypeInferencerTest.java | 104 ++++++++-------- .../cel/common/CelAbstractSyntaxTreeTest.java | 26 ++-- .../java/dev/cel/common/CelSourceTest.java | 6 +- .../cel/common/ast/CelExprVisitorTest.java | 4 +- .../dev/cel/common/ast/CelReferenceTest.java | 8 +- .../internal/CombinedDescriptorPoolTest.java | 13 +- .../DefaultInstanceMessageFactoryTest.java | 8 +- .../internal/DefaultMessageFactoryTest.java | 8 +- .../dev/cel/common/internal/ErrorsTest.java | 10 +- .../cel/common/internal/ProtoAdapterTest.java | 33 ++--- .../navigation/CelNavigableAstTest.java | 4 +- .../navigation/CelNavigableExprTest.java | 8 +- .../CelNavigableExprVisitorTest.java | 6 +- .../types/ProtoMessageTypeProviderTest.java | 117 ++++++++++-------- .../common/types/ProtoMessageTypeTest.java | 10 +- .../cel/common/values/OptionalValueTest.java | 4 +- .../common/values/ProtoMessageValueTest.java | 16 +-- .../extensions/CelOptionalLibraryTest.java | 26 ++-- .../cel/parser/CelMacroExprFactoryTest.java | 6 +- .../dev/cel/parser/CelParserImplTest.java | 76 +++++++----- .../dev/cel/runtime/UnknownContextTest.java | 31 ++--- 23 files changed, 289 insertions(+), 257 deletions(-) diff --git a/checker/src/test/java/dev/cel/checker/CelIdentDeclTest.java b/checker/src/test/java/dev/cel/checker/CelIdentDeclTest.java index 424d83452..1d131eb8f 100644 --- a/checker/src/test/java/dev/cel/checker/CelIdentDeclTest.java +++ b/checker/src/test/java/dev/cel/checker/CelIdentDeclTest.java @@ -15,7 +15,6 @@ package dev.cel.checker; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; import dev.cel.expr.Constant; @@ -23,6 +22,7 @@ import dev.cel.expr.Decl.IdentDecl; import dev.cel.expr.Type; import dev.cel.expr.Type.PrimitiveType; +import com.google.common.truth.Truth8; import dev.cel.common.ast.CelConstant; import dev.cel.common.types.SimpleType; import org.junit.Test; @@ -45,7 +45,7 @@ public void celIdentBuilder_success() { assertThat(stringIdent.name()).isEqualTo("ident"); assertThat(stringIdent.type()).isEqualTo(SimpleType.STRING); assertThat(stringIdent.doc()).isEqualTo("doc"); - assertThat(stringIdent.constant()).hasValue(CelConstant.ofValue("str")); + Truth8.assertThat(stringIdent.constant()).hasValue(CelConstant.ofValue("str")); } @Test @@ -58,7 +58,7 @@ public void celIdentBuilder_clearConstant() { builder.clearConstant(); - assertThat(builder.build().constant()).isEmpty(); + Truth8.assertThat(builder.build().constant()).isEmpty(); } @Test @@ -68,7 +68,7 @@ public void newIdentDeclaration_success() { assertThat(intIdent.name()).isEqualTo("ident"); assertThat(intIdent.type()).isEqualTo(SimpleType.INT); assertThat(intIdent.doc()).isEmpty(); - assertThat(intIdent.constant()).isEmpty(); + Truth8.assertThat(intIdent.constant()).isEmpty(); } @Test diff --git a/checker/src/test/java/dev/cel/checker/ProtoTypeMaskTypeProviderTest.java b/checker/src/test/java/dev/cel/checker/ProtoTypeMaskTypeProviderTest.java index a2a9f88ef..79269e47a 100644 --- a/checker/src/test/java/dev/cel/checker/ProtoTypeMaskTypeProviderTest.java +++ b/checker/src/test/java/dev/cel/checker/ProtoTypeMaskTypeProviderTest.java @@ -17,11 +17,11 @@ import static com.google.common.collect.ImmutableList.toImmutableList; import static com.google.common.collect.ImmutableSet.toImmutableSet; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import static org.junit.Assert.assertThrows; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; +import com.google.common.truth.Truth8; import com.google.protobuf.FieldMask; import com.google.rpc.context.AttributeContext; import dev.cel.common.types.CelType; @@ -64,7 +64,7 @@ public void lookupFieldNames_undeclaredMessageType() { CelTypeProvider celTypeProvider = new ProtoMessageTypeProvider(); ProtoTypeMaskTypeProvider protoTypeMaskProvider = new ProtoTypeMaskTypeProvider(celTypeProvider, ImmutableList.of()); - assertThat(protoTypeMaskProvider.findType(ATTRIBUTE_CONTEXT_TYPE)).isEmpty(); + Truth8.assertThat(protoTypeMaskProvider.findType(ATTRIBUTE_CONTEXT_TYPE)).isEmpty(); } @Test @@ -206,7 +206,7 @@ public void lookupFieldType() { .addPaths("request.auth.*") .build()))); ProtoMessageType ctxType = assertTypeFound(protoTypeMaskProvider, ATTRIBUTE_CONTEXT_TYPE); - assertThat(ctxType.findField("resource")).isPresent(); + Truth8.assertThat(ctxType.findField("resource")).isPresent(); assertTypeHasFieldWithType(ctxType, "resource", RESOURCE_TYPE); assertTypeHasFieldWithType(ctxType, "request", REQUEST_TYPE); @@ -238,7 +238,7 @@ public void lookupFieldType_notExposedField() { "google.rpc.context.AttributeContext", FieldMask.newBuilder().addPaths("resource.name").build()))); ProtoMessageType resourceType = assertTypeFound(protoTypeMaskProvider, RESOURCE_TYPE); - assertThat(resourceType.findField("type")).isEmpty(); + Truth8.assertThat(resourceType.findField("type")).isEmpty(); } @Test @@ -252,12 +252,12 @@ public void lookupType_notExposed() { ProtoTypeMask.of( "google.rpc.context.AttributeContext", FieldMask.newBuilder().addPaths("resource.name").build()))); - assertThat(protoTypeMaskProvider.findType(REQUEST_TYPE)).isPresent(); + Truth8.assertThat(protoTypeMaskProvider.findType(REQUEST_TYPE)).isPresent(); } private ProtoMessageType assertTypeFound(CelTypeProvider celTypeProvider, String typeName) { Optional foundType = celTypeProvider.findType(typeName); - assertThat(foundType).isPresent(); + Truth8.assertThat(foundType).isPresent(); CelType celType = foundType.get(); assertThat(celType).isInstanceOf(ProtoMessageType.class); return (ProtoMessageType) celType; @@ -271,7 +271,7 @@ private void assertTypeHasFields(ProtoMessageType protoType, ImmutableSet result = inferencer.unify(mapInst, mapParamFresh); - assertThat(result).isPresent(); + Truth8.assertThat(result).isPresent(); assertThat(result.get().substitutions()) .containsExactly( mapParamFresh.keyType().name(), @@ -86,8 +86,8 @@ public void unify_success_parameterizedMapReversedArgs() { MapType mapInst = MapType.create(SimpleType.STRING, ListType.create(TypeParamType.create("V"))); MapType mapParamFresh = (MapType) mapParam.withFreshTypeParamVariables(typeVarGenerator); Optional result = inferencer.unify(mapParamFresh, mapInst); - assertThat(result).isPresent(); - assertThat(result.get().unifiedType()).hasValue(mapInst); + Truth8.assertThat(result).isPresent(); + Truth8.assertThat(result.get().unifiedType()).hasValue(mapInst); assertThat(result.get().substitutions()) .containsExactly( mapParamFresh.keyType().name(), @@ -103,12 +103,12 @@ public void unify_success_jsonEqualsDoubleOneByOne() { TypeParamType equalsArg = TypeParamType.create("T"); CelType equalsArgFresh = equalsArg.withFreshTypeParamVariables(typeVarGenerator); Optional firstArg = inferencer.unify(JsonType.JSON, equalsArgFresh); - assertThat(firstArg).isPresent(); - assertThat(firstArg.get().unifiedType()).hasValue(JsonType.JSON); + Truth8.assertThat(firstArg).isPresent(); + Truth8.assertThat(firstArg.get().unifiedType()).hasValue(JsonType.JSON); inferencer.recordSubstitutions(firstArg.get().substitutions()); Optional secondArg = inferencer.unify(SimpleType.DOUBLE, equalsArgFresh); - assertThat(secondArg).isPresent(); - assertThat(secondArg.get().unifiedType()).hasValue(JsonType.JSON); + Truth8.assertThat(secondArg).isPresent(); + Truth8.assertThat(secondArg.get().unifiedType()).hasValue(JsonType.JSON); inferencer.recordSubstitutions(secondArg.get().substitutions()); assertThat(inferencer.specialize(equalsArgFresh)).isEqualTo(JsonType.JSON); } @@ -118,12 +118,12 @@ public void unify_success_jsonEqualsDoubleOneByOneDifferentInferencer() { TypeParamType equalsArg = TypeParamType.create("T"); CelType equalsArgFresh = equalsArg.withFreshTypeParamVariables(typeVarGenerator); Optional firstArg = inferencer.unify(JsonType.JSON, equalsArgFresh); - assertThat(firstArg).isPresent(); - assertThat(firstArg.get().unifiedType()).hasValue(JsonType.JSON); + Truth8.assertThat(firstArg).isPresent(); + Truth8.assertThat(firstArg.get().unifiedType()).hasValue(JsonType.JSON); TypeInferencer inferencer2 = new TypeInferencer(UNION_TYPES, firstArg.get().substitutions()); Optional secondArg = inferencer2.unify(SimpleType.DOUBLE, equalsArgFresh); - assertThat(secondArg).isPresent(); - assertThat(secondArg.get().unifiedType()).hasValue(JsonType.JSON); + Truth8.assertThat(secondArg).isPresent(); + Truth8.assertThat(secondArg.get().unifiedType()).hasValue(JsonType.JSON); inferencer2.recordSubstitutions(secondArg.get().substitutions()); assertThat(inferencer2.specialize(equalsArgFresh)).isEqualTo(JsonType.JSON); } @@ -131,15 +131,15 @@ public void unify_success_jsonEqualsDoubleOneByOneDifferentInferencer() { @Test public void unify_success_jsonToDouble() { Optional result = inferencer.unify(JsonType.JSON, SimpleType.DOUBLE); - assertThat(result).isPresent(); - assertThat(result.get().unifiedType()).hasValue(JsonType.JSON); + Truth8.assertThat(result).isPresent(); + Truth8.assertThat(result.get().unifiedType()).hasValue(JsonType.JSON); } @Test public void unify_success_doubleToJson() { Optional result = inferencer.unify(SimpleType.DOUBLE, JsonType.JSON); - assertThat(result).isPresent(); - assertThat(result.get().unifiedType()).hasValue(JsonType.JSON); + Truth8.assertThat(result).isPresent(); + Truth8.assertThat(result.get().unifiedType()).hasValue(JsonType.JSON); } @Test @@ -147,14 +147,14 @@ public void unify_false_nestedTypeParamReference() { TypeParamType typeParamArg = TypeParamType.create("T"); ListType listType = ListType.create(typeParamArg); Optional result = inferencer.unify(typeParamArg, listType); - assertThat(result).isEmpty(); + Truth8.assertThat(result).isEmpty(); } @Test public void unify_success_dynOrErrorYieldsError() { Optional result = inferencer.unify(SimpleType.DYN, SimpleType.ERROR); - assertThat(result).isPresent(); - assertThat(result.get().unifiedType()).hasValue(SimpleType.ERROR); + Truth8.assertThat(result).isPresent(); + Truth8.assertThat(result.get().unifiedType()).hasValue(SimpleType.ERROR); } @Test @@ -162,8 +162,8 @@ public void unify_success_doubleNullToNullableDoubleWithTypeParam() { CelType outputType = TypeParamType.create("O").withFreshTypeParamVariables(typeVarGenerator); Optional result = inferencer.unify(ImmutableList.of(SimpleType.DOUBLE, SimpleType.NULL_TYPE), outputType); - assertThat(result).isPresent(); - assertThat(result.get().unifiedType()).hasValue(NullableType.create(SimpleType.DOUBLE)); + Truth8.assertThat(result).isPresent(); + Truth8.assertThat(result.get().unifiedType()).hasValue(NullableType.create(SimpleType.DOUBLE)); } @Test @@ -171,8 +171,8 @@ public void unify_success_doubleNullToNullableDoubleWithConcreteType() { CelType outputType = NullableType.create(SimpleType.DOUBLE); Optional result = inferencer.unify(ImmutableList.of(SimpleType.DOUBLE, SimpleType.NULL_TYPE), outputType); - assertThat(result).isPresent(); - assertThat(result.get().unifiedType()).hasValue(outputType); + Truth8.assertThat(result).isPresent(); + Truth8.assertThat(result.get().unifiedType()).hasValue(outputType); } @Test @@ -182,8 +182,8 @@ public void unify_success_doubleNullStringToJson() { inferencer.unify( ImmutableList.of(SimpleType.DOUBLE, SimpleType.NULL_TYPE, SimpleType.STRING), outputType); - assertThat(result).isPresent(); - assertThat(result.get().unifiedType()).hasValue(JsonType.JSON); + Truth8.assertThat(result).isPresent(); + Truth8.assertThat(result.get().unifiedType()).hasValue(JsonType.JSON); } @Test @@ -194,8 +194,8 @@ public void unify_success_doubleNullStringToDyn() { inferencer.unify( ImmutableList.of(SimpleType.DOUBLE, SimpleType.NULL_TYPE, SimpleType.STRING), outputType); - assertThat(result).isPresent(); - assertThat(result.get().unifiedType()).hasValue(SimpleType.DYN); + Truth8.assertThat(result).isPresent(); + Truth8.assertThat(result.get().unifiedType()).hasValue(SimpleType.DYN); } @Test @@ -206,7 +206,7 @@ public void unify_false_doubleNullStringNoJsonNoTopType() { inferencer.unify( ImmutableList.of(SimpleType.DOUBLE, SimpleType.NULL_TYPE, SimpleType.STRING), outputType); - assertThat(result).isEmpty(); + Truth8.assertThat(result).isEmpty(); } @Test @@ -216,8 +216,8 @@ public void unify_success_abstractTypeListToJsonParam() { CelType outputType = TypeParamType.create("O").withFreshTypeParamVariables(typeVarGenerator); Optional result = inferencer.unify(ImmutableList.of(setListDouble, setString), outputType); - assertThat(result).isPresent(); - assertThat(result.get().unifiedType()).hasValue(OpaqueType.create("set", JsonType.JSON)); + Truth8.assertThat(result).isPresent(); + Truth8.assertThat(result.get().unifiedType()).hasValue(OpaqueType.create("set", JsonType.JSON)); } @Test @@ -229,8 +229,8 @@ public void unify_success_abstractTypeMapToMapJsonParam() { CelType outputType = TypeParamType.create("O").withFreshTypeParamVariables(typeVarGenerator); Optional result = inferencer.unify(ImmutableList.of(setListDouble, setString), outputType); - assertThat(result).isPresent(); - assertThat(result.get().unifiedType()) + Truth8.assertThat(result).isPresent(); + Truth8.assertThat(result.get().unifiedType()) .hasValue(OpaqueType.create("set", MapType.create(SimpleType.STRING, JsonType.JSON))); } @@ -242,8 +242,8 @@ public void unify_success_abstractTypeMapToJsonParam() { CelType outputType = TypeParamType.create("0").withFreshTypeParamVariables(typeVarGenerator); Optional result = inferencer.unify(ImmutableList.of(setListDouble, setString), outputType); - assertThat(result).isPresent(); - assertThat(result.get().unifiedType()).hasValue(OpaqueType.create("set", JsonType.JSON)); + Truth8.assertThat(result).isPresent(); + Truth8.assertThat(result.get().unifiedType()).hasValue(OpaqueType.create("set", JsonType.JSON)); } @Test @@ -258,8 +258,9 @@ public void unify_success_opaqueTypeMapToDynParam() { // to enter into the type resolution. Optional result = inferencer.unify(ImmutableList.of(setListDouble, setString), outputType); - assertThat(result).isPresent(); - assertThat(result.get().unifiedType()).hasValue(OpaqueType.create("set", SimpleType.DYN)); + Truth8.assertThat(result).isPresent(); + Truth8.assertThat(result.get().unifiedType()) + .hasValue(OpaqueType.create("set", SimpleType.DYN)); } @Test @@ -269,8 +270,9 @@ public void unify_success_jsonIntSetsToDynSet() { CelType outputType = TypeParamType.create("O").withFreshTypeParamVariables(typeVarGenerator); Optional result = inferencer.unify(ImmutableList.of(setJson, setInt), outputType); - assertThat(result).isPresent(); - assertThat(result.get().unifiedType()).hasValue(OpaqueType.create("set", SimpleType.DYN)); + Truth8.assertThat(result).isPresent(); + Truth8.assertThat(result.get().unifiedType()) + .hasValue(OpaqueType.create("set", SimpleType.DYN)); } @Test @@ -281,35 +283,35 @@ public void unify_success_nullableStruct() { CelType outputType = TypeParamType.create("O").withFreshTypeParamVariables(typeVarGenerator); Optional result = inferencer.unify(ImmutableList.of(nullableStructType, structType), outputType); - assertThat(result).isPresent(); - assertThat(result.get().unifiedType()).hasValue(nullableStructType); + Truth8.assertThat(result).isPresent(); + Truth8.assertThat(result.get().unifiedType()).hasValue(nullableStructType); } @Test public void unify_false_differentKinds() { OpaqueType vectorType = OpaqueType.create("vector", SimpleType.STRING); - assertThat(inferencer.unify(JsonType.JSON, vectorType)).isEmpty(); + Truth8.assertThat(inferencer.unify(JsonType.JSON, vectorType)).isEmpty(); } @Test public void unify_false_sameKindDifferentTypeName() { OpaqueType setType = OpaqueType.create("set", SimpleType.STRING); OpaqueType vectorType = OpaqueType.create("vector", SimpleType.STRING); - assertThat(inferencer.unify(setType, vectorType)).isEmpty(); + Truth8.assertThat(inferencer.unify(setType, vectorType)).isEmpty(); } @Test public void unify_false_sameTypeDifferentParameterTypes() { OpaqueType setType = OpaqueType.create("set", SimpleType.INT); OpaqueType vectorType = OpaqueType.create("set", SimpleType.STRING); - assertThat(inferencer.unify(setType, vectorType)).isEmpty(); + Truth8.assertThat(inferencer.unify(setType, vectorType)).isEmpty(); } @Test public void unify_false_sameTypeDifferentParameterCounts() { OpaqueType setType = OpaqueType.create("set", SimpleType.INT); OpaqueType vectorType = OpaqueType.create("set", SimpleType.INT, SimpleType.INT); - assertThat(inferencer.unify(setType, vectorType)).isEmpty(); + Truth8.assertThat(inferencer.unify(setType, vectorType)).isEmpty(); } @Test @@ -321,7 +323,7 @@ public void isAssignable_success_jsonSelect() { inferencer.isAssignable( ImmutableList.of(mapInst, SimpleType.STRING), ImmutableList.of(mapParamFresh, mapParamFresh.keyType())); - assertThat(result).isPresent(); + Truth8.assertThat(result).isPresent(); assertThat(result.get()) .containsExactly( mapParamFresh.keyType().name(), @@ -340,7 +342,7 @@ public void isAssignable_success_jsonEqualsDoubleAsList() { inferencer.isAssignable( ImmutableList.of(JsonType.JSON, SimpleType.DOUBLE), ImmutableList.of(equalsArgFresh, equalsArgFresh)); - assertThat(result).isPresent(); + Truth8.assertThat(result).isPresent(); inferencer.recordSubstitutions(result.get()); assertThat(inferencer.specialize(equalsArgFresh)).isEqualTo(JsonType.JSON); } @@ -353,7 +355,7 @@ public void isAssignable_success_doubleEqualsJsonAsList() { inferencer.isAssignable( ImmutableList.of(SimpleType.DOUBLE, JsonType.JSON), ImmutableList.of(equalsArgFresh, equalsArgFresh)); - assertThat(result).isPresent(); + Truth8.assertThat(result).isPresent(); inferencer.recordSubstitutions(result.get()); assertThat(inferencer.specialize(equalsArgFresh)).isEqualTo(JsonType.JSON); } @@ -366,7 +368,7 @@ public void isAssignable_false_doubleEqualsString() { inferencer.isAssignable( ImmutableList.of(SimpleType.DOUBLE, SimpleType.STRING), ImmutableList.of(equalsArgFresh, equalsArgFresh)); - assertThat(result).isEmpty(); + Truth8.assertThat(result).isEmpty(); } @Test @@ -375,7 +377,7 @@ public void isAssignable_false_sameTypeDifferentParameterCounts() { OpaqueType setType2 = OpaqueType.create("set", SimpleType.STRING, SimpleType.INT); Optional> result = inferencer.isAssignable(setType.parameters(), setType2.parameters()); - assertThat(result).isEmpty(); + Truth8.assertThat(result).isEmpty(); } @Test @@ -387,8 +389,8 @@ public void finalize_success_typeFinalize() { CelType typeOfTypeWithFreshVars = typeOfType.withFreshTypeParamVariables(typeVarGenerator); Optional result = inferencer.unify(typeOfStructType, typeOfTypeWithFreshVars); - assertThat(result).isPresent(); - assertThat(result.get().unifiedType()).hasValue(typeOfStructType); + Truth8.assertThat(result).isPresent(); + Truth8.assertThat(result.get().unifiedType()).hasValue(typeOfStructType); inferencer.recordSubstitutions(result.get().substitutions()); assertThat(inferencer.finalize(typeOfTypeWithFreshVars, SimpleType.DYN)) .isEqualTo(typeOfStructType); diff --git a/common/src/test/java/dev/cel/common/CelAbstractSyntaxTreeTest.java b/common/src/test/java/dev/cel/common/CelAbstractSyntaxTreeTest.java index 03e1a5619..960ba6642 100644 --- a/common/src/test/java/dev/cel/common/CelAbstractSyntaxTreeTest.java +++ b/common/src/test/java/dev/cel/common/CelAbstractSyntaxTreeTest.java @@ -15,7 +15,6 @@ package dev.cel.common; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; import dev.cel.expr.CheckedExpr; @@ -27,6 +26,7 @@ import dev.cel.expr.SourceInfo; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import com.google.common.truth.Truth8; import dev.cel.common.ast.CelConstant; import dev.cel.common.ast.CelExpr; import dev.cel.common.types.CelTypes; @@ -107,9 +107,9 @@ public void getResultType_isStaticWhenCheckedExpr() { @Test public void findEnumValue_findsConstantInCheckedExpr() { CelAbstractSyntaxTree ast = CHECKED_ENUM_AST; - assertThat(ast.findEnumValue(1)).isEmpty(); - assertThat(ast.findEnumValue(2)).hasValue(CelConstant.ofValue(2)); - assertThat(ast.findEnumValue(3)).isEmpty(); + Truth8.assertThat(ast.findEnumValue(1)).isEmpty(); + Truth8.assertThat(ast.findEnumValue(2)).hasValue(CelConstant.ofValue(2)); + Truth8.assertThat(ast.findEnumValue(3)).isEmpty(); } @Test @@ -118,17 +118,17 @@ public void findEnumValue_doesNotFindConstantInParsedExpr() { CelAbstractSyntaxTree.newParsedAst( CHECKED_ENUM_AST.getExpr(), CHECKED_ENUM_AST.getSource()); - assertThat(ast.findEnumValue(1)).isEmpty(); - assertThat(ast.findEnumValue(2)).isEmpty(); - assertThat(ast.findEnumValue(3)).isEmpty(); + Truth8.assertThat(ast.findEnumValue(1)).isEmpty(); + Truth8.assertThat(ast.findEnumValue(2)).isEmpty(); + Truth8.assertThat(ast.findEnumValue(3)).isEmpty(); } @Test public void findOverloadIDs_findsOverloadsInCheckedExpr() { CelAbstractSyntaxTree ast = CHECKED_ENUM_AST; - assertThat(ast.findOverloadIDs(1)).isEmpty(); - assertThat(ast.findOverloadIDs(2)).isEmpty(); - assertThat(ast.findOverloadIDs(3)).hasValue(ImmutableList.of("not_equals")); + Truth8.assertThat(ast.findOverloadIDs(1)).isEmpty(); + Truth8.assertThat(ast.findOverloadIDs(2)).isEmpty(); + Truth8.assertThat(ast.findOverloadIDs(3)).hasValue(ImmutableList.of("not_equals")); } @Test @@ -137,9 +137,9 @@ public void findOverloadIDs_doesNotFindsOverloadsInParsedExpr() { CelAbstractSyntaxTree.newParsedAst( CHECKED_ENUM_AST.getExpr(), CHECKED_ENUM_AST.getSource()); - assertThat(ast.findOverloadIDs(1)).isEmpty(); - assertThat(ast.findOverloadIDs(2)).isEmpty(); - assertThat(ast.findOverloadIDs(3)).isEmpty(); + Truth8.assertThat(ast.findOverloadIDs(1)).isEmpty(); + Truth8.assertThat(ast.findOverloadIDs(2)).isEmpty(); + Truth8.assertThat(ast.findOverloadIDs(3)).isEmpty(); } @Test diff --git a/common/src/test/java/dev/cel/common/CelSourceTest.java b/common/src/test/java/dev/cel/common/CelSourceTest.java index 5fc14fa0e..e7b2aaf0c 100644 --- a/common/src/test/java/dev/cel/common/CelSourceTest.java +++ b/common/src/test/java/dev/cel/common/CelSourceTest.java @@ -15,10 +15,10 @@ package dev.cel.common; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import static org.antlr.v4.runtime.IntStream.UNKNOWN_SOURCE_NAME; import static org.junit.Assert.assertThrows; +import com.google.common.truth.Truth8; import dev.cel.common.internal.BasicCodePointArray; import dev.cel.common.internal.CodePointStream; import dev.cel.common.internal.Latin1CodePointArray; @@ -44,13 +44,13 @@ public final class CelSourceTest { @Test public void getLocationOffset_correctStartingLocation() throws Exception { CelSource source = CelSource.newBuilder(LATIN_1_EXPR).build(); - assertThat(source.getLocationOffset(CelSourceLocation.of(1, 0))).hasValue(0); + Truth8.assertThat(source.getLocationOffset(CelSourceLocation.of(1, 0))).hasValue(0); } @Test public void getOffsetLocation_correctStartingLocation() throws Exception { CelSource source = CelSource.newBuilder(LATIN_1_EXPR).build(); - assertThat(source.getOffsetLocation(0)).hasValue(CelSourceLocation.of(1, 0)); + Truth8.assertThat(source.getOffsetLocation(0)).hasValue(CelSourceLocation.of(1, 0)); } @Test diff --git a/common/src/test/java/dev/cel/common/ast/CelExprVisitorTest.java b/common/src/test/java/dev/cel/common/ast/CelExprVisitorTest.java index ce8df4d7f..5443266bf 100644 --- a/common/src/test/java/dev/cel/common/ast/CelExprVisitorTest.java +++ b/common/src/test/java/dev/cel/common/ast/CelExprVisitorTest.java @@ -15,11 +15,11 @@ package dev.cel.common.ast; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import static org.junit.Assert.assertThrows; import com.google.auto.value.AutoValue; import com.google.common.collect.ImmutableList; +import com.google.common.truth.Truth8; import dev.cel.common.CelAbstractSyntaxTree; import dev.cel.common.ast.CelExpr.CelCall; import dev.cel.common.ast.CelExpr.CelComprehension; @@ -346,7 +346,7 @@ public void visitComprehension() throws Exception { .isEqualTo(Operator.LOGICAL_AND.getFunction()); assertThat(comprehension.loopStep().call().args()).hasSize(2); assertThat(visitedReference.createList().get().elements()).isEqualTo(iterRangeElements); - assertThat(visitedReference.identifier()) + Truth8.assertThat(visitedReference.identifier()) .hasValue(CelIdent.newBuilder().setName("__result__").build()); assertThat(visitedReference.arguments()).hasSize(10); } diff --git a/common/src/test/java/dev/cel/common/ast/CelReferenceTest.java b/common/src/test/java/dev/cel/common/ast/CelReferenceTest.java index 0eb73e4c8..79395c55a 100644 --- a/common/src/test/java/dev/cel/common/ast/CelReferenceTest.java +++ b/common/src/test/java/dev/cel/common/ast/CelReferenceTest.java @@ -15,10 +15,10 @@ package dev.cel.common.ast; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import static org.junit.Assert.assertThrows; import com.google.common.collect.ImmutableList; +import com.google.common.truth.Truth8; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -32,7 +32,7 @@ public void constructCelReference_withEmptyArguments() { assertThat(reference.name()).isEqualTo("refName"); assertThat(reference.overloadIds()).isEmpty(); - assertThat(reference.value()).isEmpty(); + Truth8.assertThat(reference.value()).isEmpty(); } @Test @@ -42,7 +42,7 @@ public void constructCelReference_withOverloadIds() { assertThat(reference.name()).isEqualTo("refName"); assertThat(reference.overloadIds()).containsExactly("a", "b", "c"); - assertThat(reference.value()).isEmpty(); + Truth8.assertThat(reference.value()).isEmpty(); } @Test @@ -52,7 +52,7 @@ public void constructCelReference_withValue() { assertThat(reference.name()).isEqualTo("refName"); assertThat(reference.overloadIds()).isEmpty(); - assertThat(reference.value()).hasValue(CelConstant.ofValue(10)); + Truth8.assertThat(reference.value()).hasValue(CelConstant.ofValue(10)); } @Test diff --git a/common/src/test/java/dev/cel/common/internal/CombinedDescriptorPoolTest.java b/common/src/test/java/dev/cel/common/internal/CombinedDescriptorPoolTest.java index 07f33fc8b..d232ac246 100644 --- a/common/src/test/java/dev/cel/common/internal/CombinedDescriptorPoolTest.java +++ b/common/src/test/java/dev/cel/common/internal/CombinedDescriptorPoolTest.java @@ -15,9 +15,9 @@ package dev.cel.common.internal; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import com.google.common.collect.ImmutableList; +import com.google.common.truth.Truth8; import com.google.protobuf.Descriptors.FieldDescriptor; import com.google.protobuf.ExtensionRegistry; import com.google.protobuf.Value; @@ -43,10 +43,11 @@ public void findDescriptor_descriptorReturnedFromBothPool() { CombinedDescriptorPool.create( ImmutableList.of(DefaultDescriptorPool.INSTANCE, dynamicDescriptorPool)); - assertThat(combinedDescriptorPool.findDescriptor(Value.getDescriptor().getFullName())) + Truth8.assertThat(combinedDescriptorPool.findDescriptor(Value.getDescriptor().getFullName())) .hasValue( Value.getDescriptor()); // Retrieved from default descriptor pool (well-known-type) - assertThat(combinedDescriptorPool.findDescriptor(TestAllTypes.getDescriptor().getFullName())) + Truth8.assertThat( + combinedDescriptorPool.findDescriptor(TestAllTypes.getDescriptor().getFullName())) .hasValue(TestAllTypes.getDescriptor()); // Retrieved from the dynamic descriptor pool. } @@ -60,7 +61,7 @@ public void findDescriptor_returnsEmpty() { CombinedDescriptorPool.create( ImmutableList.of(DefaultDescriptorPool.INSTANCE, descriptorPool)); - assertThat(combinedDescriptorPool.findDescriptor("bogus")).isEmpty(); + Truth8.assertThat(combinedDescriptorPool.findDescriptor("bogus")).isEmpty(); } @Test @@ -77,7 +78,7 @@ public void findExtensionDescriptor_success() { combinedDescriptorPool.findExtensionDescriptor( Proto2Message.getDescriptor(), "dev.cel.testing.testdata.proto2.test_all_types_ext"); - assertThat(fieldDescriptor).isPresent(); + Truth8.assertThat(fieldDescriptor).isPresent(); assertThat(fieldDescriptor.get().isExtension()).isTrue(); assertThat(fieldDescriptor.get().getFullName()) .isEqualTo("dev.cel.testing.testdata.proto2.test_all_types_ext"); @@ -93,7 +94,7 @@ public void findExtensionDescriptor_returnsEmpty() { CombinedDescriptorPool.create( ImmutableList.of(DefaultDescriptorPool.INSTANCE, dynamicDescriptorPool)); - assertThat( + Truth8.assertThat( combinedDescriptorPool.findExtensionDescriptor(TestAllTypes.getDescriptor(), "bogus")) .isEmpty(); } diff --git a/common/src/test/java/dev/cel/common/internal/DefaultInstanceMessageFactoryTest.java b/common/src/test/java/dev/cel/common/internal/DefaultInstanceMessageFactoryTest.java index 175adb121..0f24aafd0 100644 --- a/common/src/test/java/dev/cel/common/internal/DefaultInstanceMessageFactoryTest.java +++ b/common/src/test/java/dev/cel/common/internal/DefaultInstanceMessageFactoryTest.java @@ -16,10 +16,10 @@ import static com.google.common.collect.ImmutableList.toImmutableList; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import static java.util.Arrays.stream; import com.google.common.collect.ImmutableList; +import com.google.common.truth.Truth8; import com.google.common.util.concurrent.MoreExecutors; import com.google.protobuf.Descriptors.Descriptor; import com.google.protobuf.Message; @@ -95,7 +95,7 @@ public void getPrototype_success(@TestParameter PrototypeDescriptorTestCase test Optional defaultMessage = DefaultInstanceMessageFactory.getInstance().getPrototype(descriptor); - assertThat(defaultMessage).hasValue(testCase.defaultInstance); + Truth8.assertThat(defaultMessage).hasValue(testCase.defaultInstance); } @Test @@ -107,8 +107,8 @@ public void getPrototype_cached_success(@TestParameter PrototypeDescriptorTestCa Optional defaultMessage2 = DefaultInstanceMessageFactory.getInstance().getPrototype(descriptor); - assertThat(defaultMessage).hasValue(testCase.defaultInstance); - assertThat(defaultMessage2).hasValue(testCase.defaultInstance); + Truth8.assertThat(defaultMessage).hasValue(testCase.defaultInstance); + Truth8.assertThat(defaultMessage2).hasValue(testCase.defaultInstance); } @Test diff --git a/common/src/test/java/dev/cel/common/internal/DefaultMessageFactoryTest.java b/common/src/test/java/dev/cel/common/internal/DefaultMessageFactoryTest.java index 593817d10..8d75652ee 100644 --- a/common/src/test/java/dev/cel/common/internal/DefaultMessageFactoryTest.java +++ b/common/src/test/java/dev/cel/common/internal/DefaultMessageFactoryTest.java @@ -15,13 +15,13 @@ package dev.cel.common.internal; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import static java.nio.charset.StandardCharsets.UTF_8; import com.google.common.base.Ascii; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.io.Resources; +import com.google.common.truth.Truth8; import com.google.protobuf.DescriptorProtos.FileDescriptorSet; import com.google.protobuf.Descriptors.FileDescriptor; import com.google.protobuf.DynamicMessage; @@ -70,7 +70,7 @@ public void newBuilder_withDescriptor_producesNewMessageBuilder() { public void newBuilder_unknownMessage_returnsEmpty() { DefaultMessageFactory messageFactory = DefaultMessageFactory.INSTANCE; - assertThat(messageFactory.newBuilder("unknown_message")).isEmpty(); + Truth8.assertThat(messageFactory.newBuilder("unknown_message")).isEmpty(); } @Test @@ -85,7 +85,7 @@ public void newBuilder_unequalDescriptorForSameMessage_returnsDynamicMessage() t DefaultMessageFactory messageFactory = DefaultMessageFactory.create(DefaultDescriptorPool.create(celDescriptors)); - assertThat(messageFactory.newBuilder("google.api.expr.Value")).isPresent(); + Truth8.assertThat(messageFactory.newBuilder("google.api.expr.Value")).isPresent(); assertThat(messageFactory.newBuilder("google.api.expr.Value").get()) .isInstanceOf(DynamicMessage.Builder.class); } @@ -114,6 +114,6 @@ public void combinedMessageFactoryTest() { assertThat(messageFactory.newBuilder("test").get().build()) .isEqualTo(TestAllTypes.getDefaultInstance()); - assertThat(messageFactory.newBuilder("bogus")).isEmpty(); + Truth8.assertThat(messageFactory.newBuilder("bogus")).isEmpty(); } } diff --git a/common/src/test/java/dev/cel/common/internal/ErrorsTest.java b/common/src/test/java/dev/cel/common/internal/ErrorsTest.java index 2b7690715..0bdfed17c 100644 --- a/common/src/test/java/dev/cel/common/internal/ErrorsTest.java +++ b/common/src/test/java/dev/cel/common/internal/ErrorsTest.java @@ -15,8 +15,8 @@ package dev.cel.common.internal; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; +import com.google.common.truth.Truth8; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -61,9 +61,9 @@ public void getPositionLocation() { @Test public void getSnippet() { Errors errors = new Errors("test", "hello\nworld\n"); - assertThat(errors.getSnippet(1)).hasValue("hello"); - assertThat(errors.getSnippet(2)).hasValue("world"); - assertThat(errors.getSnippet(3)).hasValue(""); - assertThat(errors.getSnippet(4)).isEmpty(); + Truth8.assertThat(errors.getSnippet(1)).hasValue("hello"); + Truth8.assertThat(errors.getSnippet(2)).hasValue("world"); + Truth8.assertThat(errors.getSnippet(3)).hasValue(""); + Truth8.assertThat(errors.getSnippet(4)).isEmpty(); } } diff --git a/common/src/test/java/dev/cel/common/internal/ProtoAdapterTest.java b/common/src/test/java/dev/cel/common/internal/ProtoAdapterTest.java index 83795b554..118bd393d 100644 --- a/common/src/test/java/dev/cel/common/internal/ProtoAdapterTest.java +++ b/common/src/test/java/dev/cel/common/internal/ProtoAdapterTest.java @@ -15,11 +15,11 @@ package dev.cel.common.internal; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.primitives.UnsignedLong; +import com.google.common.truth.Truth8; import com.google.protobuf.Any; import com.google.protobuf.BoolValue; import com.google.protobuf.ByteString; @@ -162,7 +162,8 @@ public static List data() { public void adaptValueToProto_bidirectionalConversion() { DynamicProto dynamicProto = DynamicProto.create(DefaultMessageFactory.INSTANCE); ProtoAdapter protoAdapter = new ProtoAdapter(dynamicProto, options.enableUnsignedLongs()); - assertThat(protoAdapter.adaptValueToProto(value, proto.getDescriptorForType().getFullName())) + Truth8.assertThat( + protoAdapter.adaptValueToProto(value, proto.getDescriptorForType().getFullName())) .hasValue(proto); assertThat(protoAdapter.adaptProtoToValue(proto)).isEqualTo(value); } @@ -181,7 +182,7 @@ public void adaptAnyValue_hermeticTypes_bidirectionalConversion() { ? Optional.of(Expr.newBuilder()) : Optional.empty()), LEGACY.enableUnsignedLongs()); - assertThat(protoAdapter.adaptValueToProto(expr, Any.getDescriptor().getFullName())) + Truth8.assertThat(protoAdapter.adaptValueToProto(expr, Any.getDescriptor().getFullName())) .hasValue(Any.pack(expr)); assertThat(protoAdapter.adaptProtoToValue(Any.pack(expr))).isEqualTo(expr); } @@ -192,7 +193,7 @@ public static class AsymmetricConversionTest { @Test public void adaptValueToProto_asymmetricNullConversion() { ProtoAdapter protoAdapter = new ProtoAdapter(DYNAMIC_PROTO, LEGACY.enableUnsignedLongs()); - assertThat(protoAdapter.adaptValueToProto(null, Any.getDescriptor().getFullName())) + Truth8.assertThat(protoAdapter.adaptValueToProto(null, Any.getDescriptor().getFullName())) .hasValue(Any.pack(Value.newBuilder().setNullValue(NullValue.NULL_VALUE).build())); assertThat( protoAdapter.adaptProtoToValue( @@ -203,7 +204,7 @@ public void adaptValueToProto_asymmetricNullConversion() { @Test public void adaptValueToProto_asymmetricFloatConversion() { ProtoAdapter protoAdapter = new ProtoAdapter(DYNAMIC_PROTO, LEGACY.enableUnsignedLongs()); - assertThat(protoAdapter.adaptValueToProto(1.5F, Any.getDescriptor().getFullName())) + Truth8.assertThat(protoAdapter.adaptValueToProto(1.5F, Any.getDescriptor().getFullName())) .hasValue(Any.pack(FloatValue.of(1.5F))); assertThat(protoAdapter.adaptProtoToValue(Any.pack(FloatValue.of(1.5F)))).isEqualTo(1.5D); } @@ -211,7 +212,8 @@ public void adaptValueToProto_asymmetricFloatConversion() { @Test public void adaptValueToProto_asymmetricDoubleFloatConversion() { ProtoAdapter protoAdapter = new ProtoAdapter(DYNAMIC_PROTO, LEGACY.enableUnsignedLongs()); - assertThat(protoAdapter.adaptValueToProto(1.5D, FloatValue.getDescriptor().getFullName())) + Truth8.assertThat( + protoAdapter.adaptValueToProto(1.5D, FloatValue.getDescriptor().getFullName())) .hasValue(FloatValue.of(1.5F)); assertThat(protoAdapter.adaptProtoToValue(FloatValue.of(1.5F))).isEqualTo(1.5D); } @@ -219,27 +221,28 @@ public void adaptValueToProto_asymmetricDoubleFloatConversion() { @Test public void adaptValueToProto_asymmetricFloatDoubleConversion() { ProtoAdapter protoAdapter = new ProtoAdapter(DYNAMIC_PROTO, LEGACY.enableUnsignedLongs()); - assertThat(protoAdapter.adaptValueToProto(1.5F, DoubleValue.getDescriptor().getFullName())) + Truth8.assertThat( + protoAdapter.adaptValueToProto(1.5F, DoubleValue.getDescriptor().getFullName())) .hasValue(DoubleValue.of(1.5D)); } @Test public void adaptValueToProto_asymmetricJsonConversion() { ProtoAdapter protoAdapter = new ProtoAdapter(DYNAMIC_PROTO, CURRENT.enableUnsignedLongs()); - assertThat( + Truth8.assertThat( protoAdapter.adaptValueToProto( UnsignedLong.valueOf(1L), Value.getDescriptor().getFullName())) .hasValue(Value.newBuilder().setNumberValue(1).build()); - assertThat( + Truth8.assertThat( protoAdapter.adaptValueToProto( UnsignedLong.fromLongBits(-1L), Value.getDescriptor().getFullName())) .hasValue(Value.newBuilder().setStringValue(Long.toUnsignedString(-1L)).build()); - assertThat(protoAdapter.adaptValueToProto(1L, Value.getDescriptor().getFullName())) + Truth8.assertThat(protoAdapter.adaptValueToProto(1L, Value.getDescriptor().getFullName())) .hasValue(Value.newBuilder().setNumberValue(1).build()); - assertThat( + Truth8.assertThat( protoAdapter.adaptValueToProto(Long.MAX_VALUE, Value.getDescriptor().getFullName())) .hasValue(Value.newBuilder().setStringValue(Long.toString(Long.MAX_VALUE)).build()); - assertThat( + Truth8.assertThat( protoAdapter.adaptValueToProto( ByteString.copyFromUtf8("foo"), Value.getDescriptor().getFullName())) .hasValue(Value.newBuilder().setStringValue("Zm9v").build()); @@ -248,7 +251,7 @@ public void adaptValueToProto_asymmetricJsonConversion() { @Test public void adaptValueToProto_unsupportedJsonConversion() { ProtoAdapter protoAdapter = new ProtoAdapter(DYNAMIC_PROTO, LEGACY.enableUnsignedLongs()); - assertThat( + Truth8.assertThat( protoAdapter.adaptValueToProto( ImmutableMap.of(1, 1), Any.getDescriptor().getFullName())) .isEmpty(); @@ -257,7 +260,7 @@ public void adaptValueToProto_unsupportedJsonConversion() { @Test public void adaptValueToProto_unsupportedJsonListConversion() { ProtoAdapter protoAdapter = new ProtoAdapter(DYNAMIC_PROTO, LEGACY.enableUnsignedLongs()); - assertThat( + Truth8.assertThat( protoAdapter.adaptValueToProto( ImmutableMap.of(1, 1), ListValue.getDescriptor().getFullName())) .isEmpty(); @@ -266,7 +269,7 @@ public void adaptValueToProto_unsupportedJsonListConversion() { @Test public void adaptValueToProto_unsupportedConversion() { ProtoAdapter protoAdapter = new ProtoAdapter(DYNAMIC_PROTO, LEGACY.enableUnsignedLongs()); - assertThat(protoAdapter.adaptValueToProto("Hello", Expr.getDescriptor().getFullName())) + Truth8.assertThat(protoAdapter.adaptValueToProto("Hello", Expr.getDescriptor().getFullName())) .isEmpty(); } diff --git a/common/src/test/java/dev/cel/common/navigation/CelNavigableAstTest.java b/common/src/test/java/dev/cel/common/navigation/CelNavigableAstTest.java index e4d293098..2c595f0d1 100644 --- a/common/src/test/java/dev/cel/common/navigation/CelNavigableAstTest.java +++ b/common/src/test/java/dev/cel/common/navigation/CelNavigableAstTest.java @@ -15,8 +15,8 @@ package dev.cel.common.navigation; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; +import com.google.common.truth.Truth8; import dev.cel.common.CelAbstractSyntaxTree; import dev.cel.common.ast.CelConstant; import dev.cel.common.ast.CelExpr; @@ -39,7 +39,7 @@ public void construct_success() throws Exception { assertThat(navigableAst.getAst()).isEqualTo(ast); assertThat(navigableAst.getRoot().expr()) .isEqualTo(CelExpr.ofConstantExpr(1, CelConstant.ofValue("Hello World"))); - assertThat(navigableAst.getRoot().parent()).isEmpty(); + Truth8.assertThat(navigableAst.getRoot().parent()).isEmpty(); assertThat(navigableAst.getRoot().depth()).isEqualTo(0); } } diff --git a/common/src/test/java/dev/cel/common/navigation/CelNavigableExprTest.java b/common/src/test/java/dev/cel/common/navigation/CelNavigableExprTest.java index 303fef42e..b76da7a21 100644 --- a/common/src/test/java/dev/cel/common/navigation/CelNavigableExprTest.java +++ b/common/src/test/java/dev/cel/common/navigation/CelNavigableExprTest.java @@ -15,8 +15,8 @@ package dev.cel.common.navigation; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; +import com.google.common.truth.Truth8; import dev.cel.common.ast.CelConstant; import dev.cel.common.ast.CelExpr; import org.junit.Test; @@ -34,7 +34,7 @@ public void construct_withoutParent_success() { assertThat(navigableExpr.expr()).isEqualTo(constExpr); assertThat(navigableExpr.depth()).isEqualTo(2); - assertThat(navigableExpr.parent()).isEmpty(); + Truth8.assertThat(navigableExpr.parent()).isEmpty(); } @Test @@ -47,9 +47,9 @@ public void construct_withParent_success() { assertThat(parentExpr.expr()).isEqualTo(identExpr); assertThat(parentExpr.depth()).isEqualTo(1); - assertThat(parentExpr.parent()).isEmpty(); + Truth8.assertThat(parentExpr.parent()).isEmpty(); assertThat(navigableExpr.expr()).isEqualTo(constExpr); assertThat(navigableExpr.depth()).isEqualTo(2); - assertThat(navigableExpr.parent()).hasValue(parentExpr); + Truth8.assertThat(navigableExpr.parent()).hasValue(parentExpr); } } diff --git a/common/src/test/java/dev/cel/common/navigation/CelNavigableExprVisitorTest.java b/common/src/test/java/dev/cel/common/navigation/CelNavigableExprVisitorTest.java index a496a133a..9aeefa6a4 100644 --- a/common/src/test/java/dev/cel/common/navigation/CelNavigableExprVisitorTest.java +++ b/common/src/test/java/dev/cel/common/navigation/CelNavigableExprVisitorTest.java @@ -16,13 +16,13 @@ import static com.google.common.collect.ImmutableList.toImmutableList; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import static dev.cel.common.CelFunctionDecl.newFunctionDeclaration; import static dev.cel.common.CelOverloadDecl.newMemberOverload; import static org.junit.Assert.assertThrows; import com.google.common.collect.ImmutableList; import com.google.common.primitives.UnsignedLong; +import com.google.common.truth.Truth8; import com.google.testing.junit.testparameterinjector.TestParameterInjector; import com.google.testing.junit.testparameterinjector.TestParameters; import dev.cel.common.CelAbstractSyntaxTree; @@ -273,7 +273,7 @@ public void stringFormatCall_filterList_success() throws Exception { assertThat(allConstants).hasSize(1); CelNavigableExpr listExpr = allConstants.get(0); assertThat(listExpr.getKind()).isEqualTo(Kind.CREATE_LIST); - assertThat(listExpr.parent()).isPresent(); + Truth8.assertThat(listExpr.parent()).isPresent(); CelNavigableExpr stringFormatExpr = listExpr.parent().get(); assertThat(stringFormatExpr.getKind()).isEqualTo(Kind.CALL); CelCall call = listExpr.parent().get().expr().exprKind().call(); @@ -676,7 +676,7 @@ public void comprehension_allNodes_parentsPopulated() throws Exception { CelExpr.ofComprehension( 13, "i", iterRange, "__result__", accuInit, loopCondition, loopStep, result); assertThat(allNodes).hasSize(11); - assertThat(allNodes.get(0).parent()).isEmpty(); // comprehension + Truth8.assertThat(allNodes.get(0).parent()).isEmpty(); // comprehension assertThat(allNodes.get(1).parent().get().expr()).isEqualTo(comprehension); // iter_range assertThat(allNodes.get(2).parent().get().expr()) .isEqualTo(iterRange); // const_expr within iter_range diff --git a/common/src/test/java/dev/cel/common/types/ProtoMessageTypeProviderTest.java b/common/src/test/java/dev/cel/common/types/ProtoMessageTypeProviderTest.java index 7efc23620..cb6f03d30 100644 --- a/common/src/test/java/dev/cel/common/types/ProtoMessageTypeProviderTest.java +++ b/common/src/test/java/dev/cel/common/types/ProtoMessageTypeProviderTest.java @@ -16,10 +16,10 @@ import static com.google.common.collect.ImmutableList.toImmutableList; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; +import com.google.common.truth.Truth8; import dev.cel.common.types.CelTypeProvider.CombinedCelTypeProvider; import dev.cel.testing.testdata.proto2.MessagesProto2; import dev.cel.testing.testdata.proto2.MessagesProto2Extensions; @@ -49,7 +49,7 @@ public void types_emptyTypeSet() { @Test public void findType_emptyTypeSet() { - assertThat(emptyProvider.findType("any")).isEmpty(); + Truth8.assertThat(emptyProvider.findType("any")).isEmpty(); } @Test @@ -67,78 +67,82 @@ public void types_allGlobalAndNestedDeclarations() { public void findType_globalEnumWithAllNamesAndNumbers() { Optional celType = proto3Provider.findType("dev.cel.testing.testdata.proto3.GlobalEnum"); - assertThat(celType).isPresent(); + Truth8.assertThat(celType).isPresent(); assertThat(celType.get()).isInstanceOf(EnumType.class); EnumType enumType = (EnumType) celType.get(); assertThat(enumType.name()).isEqualTo("dev.cel.testing.testdata.proto3.GlobalEnum"); - assertThat(enumType.findNameByNumber(0)).hasValue("GOO"); - assertThat(enumType.findNameByNumber(1)).hasValue("GAR"); - assertThat(enumType.findNameByNumber(2)).hasValue("GAZ"); - assertThat(enumType.findNameByNumber(3)).isEmpty(); + Truth8.assertThat(enumType.findNameByNumber(0)).hasValue("GOO"); + Truth8.assertThat(enumType.findNameByNumber(1)).hasValue("GAR"); + Truth8.assertThat(enumType.findNameByNumber(2)).hasValue("GAZ"); + Truth8.assertThat(enumType.findNameByNumber(3)).isEmpty(); } @Test public void findType_nestedEnumWithAllNamesAndNumbers() { Optional celType = proto3Provider.findType("dev.cel.testing.testdata.proto3.TestAllTypes.NestedEnum"); - assertThat(celType).isPresent(); + Truth8.assertThat(celType).isPresent(); assertThat(celType.get()).isInstanceOf(EnumType.class); EnumType enumType = (EnumType) celType.get(); assertThat(enumType.name()) .isEqualTo("dev.cel.testing.testdata.proto3.TestAllTypes.NestedEnum"); - assertThat(enumType.findNumberByName("FOO")).hasValue(0); - assertThat(enumType.findNumberByName("BAR")).hasValue(1); - assertThat(enumType.findNumberByName("BAZ")).hasValue(2); - assertThat(enumType.findNumberByName("MISSING")).isEmpty(); + Truth8.assertThat(enumType.findNumberByName("FOO")).hasValue(0); + Truth8.assertThat(enumType.findNumberByName("BAR")).hasValue(1); + Truth8.assertThat(enumType.findNumberByName("BAZ")).hasValue(2); + Truth8.assertThat(enumType.findNumberByName("MISSING")).isEmpty(); } @Test public void findType_globalMessageTypeNoExtensions() { Optional celType = proto3Provider.findType("dev.cel.testing.testdata.proto3.NestedTestAllTypes"); - assertThat(celType).isPresent(); + Truth8.assertThat(celType).isPresent(); assertThat(celType.get()).isInstanceOf(ProtoMessageType.class); ProtoMessageType protoType = (ProtoMessageType) celType.get(); assertThat(protoType.name()).isEqualTo("dev.cel.testing.testdata.proto3.NestedTestAllTypes"); - assertThat(protoType.findField("payload")).isPresent(); - assertThat(protoType.findField("child")).isPresent(); - assertThat(protoType.findField("missing")).isEmpty(); + Truth8.assertThat(protoType.findField("payload")).isPresent(); + Truth8.assertThat(protoType.findField("child")).isPresent(); + Truth8.assertThat(protoType.findField("missing")).isEmpty(); assertThat(protoType.fields()).hasSize(2); - assertThat(protoType.findExtension("dev.cel.testing.testdata.proto3.any")).isEmpty(); + Truth8.assertThat(protoType.findExtension("dev.cel.testing.testdata.proto3.any")).isEmpty(); } @Test public void findType_globalMessageWithExtensions() { Optional celType = proto2Provider.findType("dev.cel.testing.testdata.proto2.Proto2Message"); - assertThat(celType).isPresent(); + Truth8.assertThat(celType).isPresent(); assertThat(celType.get()).isInstanceOf(ProtoMessageType.class); ProtoMessageType protoType = (ProtoMessageType) celType.get(); assertThat(protoType.name()).isEqualTo("dev.cel.testing.testdata.proto2.Proto2Message"); - assertThat(protoType.findField("single_int32")).isPresent(); - assertThat(protoType.findField("single_enum")).isPresent(); - assertThat(protoType.findField("single_nested_test_all_types")).isPresent(); - assertThat(protoType.findField("nestedgroup")).isPresent(); - assertThat(protoType.findField("nested_ext")).isEmpty(); + Truth8.assertThat(protoType.findField("single_int32")).isPresent(); + Truth8.assertThat(protoType.findField("single_enum")).isPresent(); + Truth8.assertThat(protoType.findField("single_nested_test_all_types")).isPresent(); + Truth8.assertThat(protoType.findField("nestedgroup")).isPresent(); + Truth8.assertThat(protoType.findField("nested_ext")).isEmpty(); - assertThat(protoType.findExtension("dev.cel.testing.testdata.proto2.nested_ext")).isPresent(); - assertThat(protoType.findExtension("dev.cel.testing.testdata.proto2.int32_ext")).isPresent(); - assertThat(protoType.findExtension("dev.cel.testing.testdata.proto2.test_all_types_ext")) + Truth8.assertThat(protoType.findExtension("dev.cel.testing.testdata.proto2.nested_ext")) .isPresent(); - assertThat(protoType.findExtension("dev.cel.testing.testdata.proto2.nested_enum_ext")) + Truth8.assertThat(protoType.findExtension("dev.cel.testing.testdata.proto2.int32_ext")) .isPresent(); - assertThat( + Truth8.assertThat(protoType.findExtension("dev.cel.testing.testdata.proto2.test_all_types_ext")) + .isPresent(); + Truth8.assertThat(protoType.findExtension("dev.cel.testing.testdata.proto2.nested_enum_ext")) + .isPresent(); + Truth8.assertThat( protoType.findExtension("dev.cel.testing.testdata.proto2.repeated_string_holder_ext")) .isPresent(); - assertThat(protoType.findExtension("dev.cel.testing.testdata.proto2.Proto2Message.int32_ext")) + Truth8.assertThat( + protoType.findExtension("dev.cel.testing.testdata.proto2.Proto2Message.int32_ext")) .isEmpty(); Optional holderType = proto2Provider.findType("dev.cel.testing.testdata.proto2.StringHolder"); - assertThat(holderType).isPresent(); + Truth8.assertThat(holderType).isPresent(); ProtoMessageType stringHolderType = (ProtoMessageType) holderType.get(); - assertThat(stringHolderType.findExtension("dev.cel.testing.testdata.proto2.nested_enum_ext")) + Truth8.assertThat( + stringHolderType.findExtension("dev.cel.testing.testdata.proto2.nested_enum_ext")) .isEmpty(); } @@ -146,24 +150,24 @@ public void findType_globalMessageWithExtensions() { public void findType_scopedMessageWithExtensions() { Optional celType = proto2Provider.findType("dev.cel.testing.testdata.proto2.Proto2Message"); - assertThat(celType).isPresent(); + Truth8.assertThat(celType).isPresent(); assertThat(celType.get()).isInstanceOf(ProtoMessageType.class); ProtoMessageType protoType = (ProtoMessageType) celType.get(); - assertThat( + Truth8.assertThat( protoType.findExtension( "dev.cel.testing.testdata.proto2.Proto2ExtensionScopedMessage.message_scoped_nested_ext")) .isPresent(); - assertThat( + Truth8.assertThat( protoType.findExtension( "dev.cel.testing.testdata.proto2.Proto2ExtensionScopedMessage.int64_ext")) .isPresent(); - assertThat( + Truth8.assertThat( protoType.findExtension( "dev.cel.testing.testdata.proto2.Proto2ExtensionScopedMessage.string_ext")) .isPresent(); - assertThat( + Truth8.assertThat( protoType.findExtension( "dev.cel.testing.testdata.proto2.Proto2ExtensionScopedMessage.nested_message_inside_ext")) .isPresent(); @@ -173,11 +177,11 @@ public void findType_scopedMessageWithExtensions() { public void findType_withRepeatedEnumField() { Optional celType = proto3Provider.findType("dev.cel.testing.testdata.proto3.TestAllTypes"); - assertThat(celType).isPresent(); + Truth8.assertThat(celType).isPresent(); assertThat(celType.get()).isInstanceOf(ProtoMessageType.class); ProtoMessageType protoType = (ProtoMessageType) celType.get(); assertThat(protoType.name()).isEqualTo("dev.cel.testing.testdata.proto3.TestAllTypes"); - assertThat(protoType.findField("repeated_nested_enum")).isPresent(); + Truth8.assertThat(protoType.findField("repeated_nested_enum")).isPresent(); CelType fieldType = protoType.findField("repeated_nested_enum").get().type(); assertThat(fieldType.kind()).isEqualTo(CelKind.LIST); @@ -187,7 +191,8 @@ public void findType_withRepeatedEnumField() { .isEqualTo("dev.cel.testing.testdata.proto3.TestAllTypes.NestedEnum"); assertThat(elemType.kind()).isEqualTo(CelKind.INT); assertThat(elemType).isInstanceOf(EnumType.class); - assertThat(proto3Provider.findType("dev.cel.testing.testdata.proto3.TestAllTypes.NestedEnum")) + Truth8.assertThat( + proto3Provider.findType("dev.cel.testing.testdata.proto3.TestAllTypes.NestedEnum")) .hasValue(elemType); } @@ -197,7 +202,7 @@ public void findType_withOneofField() { proto3Provider.findType("dev.cel.testing.testdata.proto3.TestAllTypes"); ProtoMessageType protoType = (ProtoMessageType) celType.get(); assertThat(protoType.name()).isEqualTo("dev.cel.testing.testdata.proto3.TestAllTypes"); - assertThat(protoType.findField("single_nested_message").map(f -> f.type().name())) + Truth8.assertThat(protoType.findField("single_nested_message").map(f -> f.type().name())) .hasValue("dev.cel.testing.testdata.proto3.TestAllTypes.NestedMessage"); } @@ -223,33 +228,35 @@ public void findType_withWellKnownTypes() { Optional celType = proto3Provider.findType("dev.cel.testing.testdata.proto3.TestAllTypes"); ProtoMessageType protoType = (ProtoMessageType) celType.get(); - assertThat(protoType.findField("single_any").map(f -> f.type())).hasValue(SimpleType.ANY); - assertThat(protoType.findField("single_duration").map(f -> f.type())) + Truth8.assertThat(protoType.findField("single_any").map(f -> f.type())) + .hasValue(SimpleType.ANY); + Truth8.assertThat(protoType.findField("single_duration").map(f -> f.type())) .hasValue(SimpleType.DURATION); - assertThat(protoType.findField("single_timestamp").map(f -> f.type())) + Truth8.assertThat(protoType.findField("single_timestamp").map(f -> f.type())) .hasValue(SimpleType.TIMESTAMP); - assertThat(protoType.findField("single_value").map(f -> f.type())).hasValue(SimpleType.DYN); - assertThat(protoType.findField("single_list_value").map(f -> f.type())) + Truth8.assertThat(protoType.findField("single_value").map(f -> f.type())) + .hasValue(SimpleType.DYN); + Truth8.assertThat(protoType.findField("single_list_value").map(f -> f.type())) .hasValue(ListType.create(SimpleType.DYN)); - assertThat(protoType.findField("single_struct").map(f -> f.type())) + Truth8.assertThat(protoType.findField("single_struct").map(f -> f.type())) .hasValue(MapType.create(SimpleType.STRING, SimpleType.DYN)); - assertThat(protoType.findField("single_bool_wrapper").map(f -> f.type())) + Truth8.assertThat(protoType.findField("single_bool_wrapper").map(f -> f.type())) .hasValue(NullableType.create(SimpleType.BOOL)); - assertThat(protoType.findField("single_bytes_wrapper").map(f -> f.type())) + Truth8.assertThat(protoType.findField("single_bytes_wrapper").map(f -> f.type())) .hasValue(NullableType.create(SimpleType.BYTES)); - assertThat(protoType.findField("single_int32_wrapper").map(f -> f.type())) + Truth8.assertThat(protoType.findField("single_int32_wrapper").map(f -> f.type())) .hasValue(NullableType.create(SimpleType.INT)); - assertThat(protoType.findField("single_int64_wrapper").map(f -> f.type())) + Truth8.assertThat(protoType.findField("single_int64_wrapper").map(f -> f.type())) .hasValue(NullableType.create(SimpleType.INT)); - assertThat(protoType.findField("single_double_wrapper").map(f -> f.type())) + Truth8.assertThat(protoType.findField("single_double_wrapper").map(f -> f.type())) .hasValue(NullableType.create(SimpleType.DOUBLE)); - assertThat(protoType.findField("single_float_wrapper").map(f -> f.type())) + Truth8.assertThat(protoType.findField("single_float_wrapper").map(f -> f.type())) .hasValue(NullableType.create(SimpleType.DOUBLE)); - assertThat(protoType.findField("single_string_wrapper").map(f -> f.type())) + Truth8.assertThat(protoType.findField("single_string_wrapper").map(f -> f.type())) .hasValue(NullableType.create(SimpleType.STRING)); - assertThat(protoType.findField("single_uint32_wrapper").map(f -> f.type())) + Truth8.assertThat(protoType.findField("single_uint32_wrapper").map(f -> f.type())) .hasValue(NullableType.create(SimpleType.UINT)); - assertThat(protoType.findField("single_uint64_wrapper").map(f -> f.type())) + Truth8.assertThat(protoType.findField("single_uint64_wrapper").map(f -> f.type())) .hasValue(NullableType.create(SimpleType.UINT)); } diff --git a/common/src/test/java/dev/cel/common/types/ProtoMessageTypeTest.java b/common/src/test/java/dev/cel/common/types/ProtoMessageTypeTest.java index 5790be414..5e0c3a83c 100644 --- a/common/src/test/java/dev/cel/common/types/ProtoMessageTypeTest.java +++ b/common/src/test/java/dev/cel/common/types/ProtoMessageTypeTest.java @@ -15,10 +15,10 @@ package dev.cel.common.types; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; +import com.google.common.truth.Truth8; import java.util.Optional; import org.junit.Before; import org.junit.Test; @@ -53,7 +53,7 @@ public void setUp() { @Test public void findField() { for (String fieldName : FIELD_MAP.keySet()) { - assertThat(testMessage.findField(fieldName)) + Truth8.assertThat(testMessage.findField(fieldName)) .hasValue(StructType.Field.of(fieldName, FIELD_MAP.get(fieldName))); } } @@ -61,8 +61,8 @@ public void findField() { @Test public void withVisibleFields() { ProtoMessageType maskedMessage = testMessage.withVisibleFields(ImmutableSet.of("bool_value")); - assertThat(maskedMessage.findField("int_value")).isEmpty(); - assertThat(maskedMessage.findField("bool_value")).isPresent(); + Truth8.assertThat(maskedMessage.findField("int_value")).isEmpty(); + Truth8.assertThat(maskedMessage.findField("bool_value")).isPresent(); assertThat(maskedMessage.fields()).hasSize(1); assertThat(testMessage.fields()).hasSize(4); } @@ -70,7 +70,7 @@ public void withVisibleFields() { @Test public void findExtension() { for (String extName : EXTENSION_MAP.keySet()) { - assertThat(testMessage.findExtension(extName)) + Truth8.assertThat(testMessage.findExtension(extName)) .hasValue( ProtoMessageType.Extension.of(extName, EXTENSION_MAP.get(extName), testMessage)); } diff --git a/common/src/test/java/dev/cel/common/values/OptionalValueTest.java b/common/src/test/java/dev/cel/common/values/OptionalValueTest.java index 953513100..c42b6522d 100644 --- a/common/src/test/java/dev/cel/common/values/OptionalValueTest.java +++ b/common/src/test/java/dev/cel/common/values/OptionalValueTest.java @@ -15,10 +15,10 @@ package dev.cel.common.values; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import static org.junit.Assert.assertThrows; import com.google.common.collect.ImmutableMap; +import com.google.common.truth.Truth8; import com.google.testing.junit.testparameterinjector.TestParameterInjector; import com.google.testing.junit.testparameterinjector.TestParameters; import dev.cel.common.types.CelType; @@ -133,7 +133,7 @@ public void findField_struct_success(String field, boolean expectedResult) { @Test public void findField_onEmptyOptional() { - assertThat(OptionalValue.EMPTY.find(StringValue.create("bogus"))).isEmpty(); + Truth8.assertThat(OptionalValue.EMPTY.find(StringValue.create("bogus"))).isEmpty(); } @Test diff --git a/common/src/test/java/dev/cel/common/values/ProtoMessageValueTest.java b/common/src/test/java/dev/cel/common/values/ProtoMessageValueTest.java index 9b0f5b8ef..c1e518a9e 100644 --- a/common/src/test/java/dev/cel/common/values/ProtoMessageValueTest.java +++ b/common/src/test/java/dev/cel/common/values/ProtoMessageValueTest.java @@ -15,12 +15,12 @@ package dev.cel.common.values; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import static org.junit.Assert.assertThrows; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.primitives.UnsignedLong; +import com.google.common.truth.Truth8; import com.google.protobuf.Any; import com.google.protobuf.ByteString; import com.google.protobuf.DynamicMessage; @@ -97,9 +97,9 @@ public void findField_fieldIsSet_fieldExists() { ProtoMessageValue.create( testAllTypes, DefaultDescriptorPool.INSTANCE, PROTO_CEL_VALUE_CONVERTER); - assertThat(protoMessageValue.find(StringValue.create("single_bool"))).isPresent(); - assertThat(protoMessageValue.find(StringValue.create("single_int64"))).isPresent(); - assertThat(protoMessageValue.find(StringValue.create("repeated_int64"))).isPresent(); + Truth8.assertThat(protoMessageValue.find(StringValue.create("single_bool"))).isPresent(); + Truth8.assertThat(protoMessageValue.find(StringValue.create("single_int64"))).isPresent(); + Truth8.assertThat(protoMessageValue.find(StringValue.create("repeated_int64"))).isPresent(); } @Test @@ -110,9 +110,9 @@ public void findField_fieldIsUnset_fieldDoesNotExist() { DefaultDescriptorPool.INSTANCE, PROTO_CEL_VALUE_CONVERTER); - assertThat(protoMessageValue.find(StringValue.create("single_int32"))).isEmpty(); - assertThat(protoMessageValue.find(StringValue.create("single_uint64"))).isEmpty(); - assertThat(protoMessageValue.find(StringValue.create("repeated_int32"))).isEmpty(); + Truth8.assertThat(protoMessageValue.find(StringValue.create("single_int32"))).isEmpty(); + Truth8.assertThat(protoMessageValue.find(StringValue.create("single_uint64"))).isEmpty(); + Truth8.assertThat(protoMessageValue.find(StringValue.create("repeated_int32"))).isEmpty(); } @Test @@ -151,7 +151,7 @@ public void findField_extensionField_success() { ProtoMessageValue protoMessageValue = ProtoMessageValue.create(proto2Message, descriptorPool, protoCelValueConverter); - assertThat( + Truth8.assertThat( protoMessageValue.find(StringValue.create("dev.cel.testing.testdata.proto2.int32_ext"))) .isPresent(); } diff --git a/extensions/src/test/java/dev/cel/extensions/CelOptionalLibraryTest.java b/extensions/src/test/java/dev/cel/extensions/CelOptionalLibraryTest.java index 1b367dbda..2f8376693 100644 --- a/extensions/src/test/java/dev/cel/extensions/CelOptionalLibraryTest.java +++ b/extensions/src/test/java/dev/cel/extensions/CelOptionalLibraryTest.java @@ -15,12 +15,12 @@ package dev.cel.extensions; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import static org.junit.Assert.assertThrows; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.primitives.UnsignedLong; +import com.google.common.truth.Truth8; import com.google.protobuf.ByteString; import com.google.protobuf.DoubleValue; import com.google.protobuf.NullValue; @@ -144,7 +144,7 @@ public void optionalType_adaptsIntegerToLong_success() throws Exception { Optional result = (Optional) cel.createProgram(ast).eval(ImmutableMap.of("a", Optional.of(5))); - assertThat(result).hasValue(5L); + Truth8.assertThat(result).hasValue(5L); } @Test @@ -155,7 +155,7 @@ public void optionalType_adaptsFloatToLong_success() throws Exception { Optional result = (Optional) cel.createProgram(ast).eval(ImmutableMap.of("a", Optional.of(5.5f))); - assertThat(result).hasValue(5.5d); + Truth8.assertThat(result).hasValue(5.5d); } @Test @@ -504,7 +504,7 @@ public void optionalFieldSelection_onMap_returnsOptionalValue() throws Exception Optional result = (Optional) cel.createProgram(ast).eval(); - assertThat(result).hasValue(2L); + Truth8.assertThat(result).hasValue(2L); } @Test @@ -520,7 +520,7 @@ public void optionalFieldSelection_onProtoMessage_returnsOptionalEmpty() throws (Optional) cel.createProgram(ast).eval(ImmutableMap.of("msg", TestAllTypes.getDefaultInstance())); - assertThat(result).isEmpty(); + Truth8.assertThat(result).isEmpty(); } @Test @@ -537,7 +537,7 @@ public void optionalFieldSelection_onProtoMessage_returnsOptionalValue() throws cel.createProgram(ast) .eval(ImmutableMap.of("msg", TestAllTypes.newBuilder().setSingleInt32(5).build())); - assertThat(result).hasValue(5L); + Truth8.assertThat(result).hasValue(5L); } @Test @@ -568,7 +568,7 @@ public void optionalFieldSelection_onProtoMessage_chainedSuccess() throws Except "dashed-index", TestAllTypes.newBuilder().setSingleInt32(5).build())))); - assertThat(result).hasValue(5L); + Truth8.assertThat(result).hasValue(5L); } @Test @@ -1236,7 +1236,7 @@ public void optionalMapMacro_receiverIsEmpty_returnsOptionalEmpty() throws Excep Optional result = (Optional) cel.createProgram(ast).eval(ImmutableMap.of("x", Optional.empty())); - assertThat(result).isEmpty(); + Truth8.assertThat(result).isEmpty(); } @Test @@ -1251,7 +1251,7 @@ public void optionalMapMacro_receiverHasValue_returnsOptionalValue() throws Exce Optional result = (Optional) cel.createProgram(ast).eval(ImmutableMap.of("x", Optional.of(42L))); - assertThat(result).hasValue(43L); + Truth8.assertThat(result).hasValue(43L); } @Test @@ -1281,7 +1281,7 @@ public void optionalFlatMapMacro_receiverIsEmpty_returnsOptionalEmpty() throws E Optional result = (Optional) cel.createProgram(ast).eval(ImmutableMap.of("x", Optional.empty())); - assertThat(result).isEmpty(); + Truth8.assertThat(result).isEmpty(); } @Test @@ -1296,7 +1296,7 @@ public void optionalFlatMapMacro_receiverHasValue_returnsOptionalValue() throws Optional result = (Optional) cel.createProgram(ast).eval(ImmutableMap.of("x", Optional.of(42L))); - assertThat(result).hasValue(43L); + Truth8.assertThat(result).hasValue(43L); } @Test @@ -1313,7 +1313,7 @@ public void optionalFlatMapMacro_withOptionalOfNonZeroValue_optionalEmptyWhenVal Optional result = (Optional) cel.createProgram(ast).eval(ImmutableMap.of("x", Optional.of(1L))); - assertThat(result).isEmpty(); + Truth8.assertThat(result).isEmpty(); } @Test @@ -1330,7 +1330,7 @@ public void optionalFlatMapMacro_withOptionalOfNonZeroValue_optionalValueWhenVal Optional result = (Optional) cel.createProgram(ast).eval(ImmutableMap.of("x", Optional.of(1L))); - assertThat(result).hasValue(2L); + Truth8.assertThat(result).hasValue(2L); } @Test diff --git a/parser/src/test/java/dev/cel/parser/CelMacroExprFactoryTest.java b/parser/src/test/java/dev/cel/parser/CelMacroExprFactoryTest.java index 68ac5e662..7898239fc 100644 --- a/parser/src/test/java/dev/cel/parser/CelMacroExprFactoryTest.java +++ b/parser/src/test/java/dev/cel/parser/CelMacroExprFactoryTest.java @@ -15,9 +15,9 @@ package dev.cel.parser; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import com.google.common.primitives.UnsignedLong; +import com.google.common.truth.Truth8; import com.google.protobuf.ByteString; import dev.cel.common.CelIssue; import dev.cel.common.CelSourceLocation; @@ -578,7 +578,7 @@ public void newGlobalCall_returnsGlobalCall() { CelExpr expr = exprFactory.newGlobalCall("foo", argument); assertThat(expr.id()).isEqualTo(2L); assertThat(expr.exprKind().getKind()).isEqualTo(Kind.CALL); - assertThat(expr.call().target()).isEmpty(); + Truth8.assertThat(expr.call().target()).isEmpty(); assertThat(expr.call().function()).isEqualTo("foo"); assertThat(expr.call().args()).containsExactly(argument); } @@ -591,7 +591,7 @@ public void newReceiverCall_returnsReceiverCall() { CelExpr expr = exprFactory.newReceiverCall("foo", target, argument); assertThat(expr.id()).isEqualTo(3L); assertThat(expr.exprKind().getKind()).isEqualTo(Kind.CALL); - assertThat(expr.call().target()).hasValue(target); + Truth8.assertThat(expr.call().target()).hasValue(target); assertThat(expr.call().function()).isEqualTo("foo"); assertThat(expr.call().args()).containsExactly(argument); } diff --git a/parser/src/test/java/dev/cel/parser/CelParserImplTest.java b/parser/src/test/java/dev/cel/parser/CelParserImplTest.java index 97bb8573b..287942492 100644 --- a/parser/src/test/java/dev/cel/parser/CelParserImplTest.java +++ b/parser/src/test/java/dev/cel/parser/CelParserImplTest.java @@ -15,9 +15,9 @@ package dev.cel.parser; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import static org.junit.Assert.assertThrows; +import com.google.common.truth.Truth8; import com.google.testing.junit.testparameterinjector.TestParameter; import com.google.testing.junit.testparameterinjector.TestParameterInjector; import com.google.testing.junit.testparameterinjector.TestParameters; @@ -42,15 +42,20 @@ public void build_withMacros_containsAllMacros() { CelParserImpl parser = (CelParserImpl) CelParserImpl.newBuilder().setStandardMacros(CelStandardMacro.STANDARD_MACROS).build(); - assertThat(parser.findMacro("has:1:false")).hasValue(CelStandardMacro.HAS.getDefinition()); - assertThat(parser.findMacro("all:2:true")).hasValue(CelStandardMacro.ALL.getDefinition()); - assertThat(parser.findMacro("exists:2:true")).hasValue(CelStandardMacro.EXISTS.getDefinition()); - assertThat(parser.findMacro("exists_one:2:true")) + Truth8.assertThat(parser.findMacro("has:1:false")) + .hasValue(CelStandardMacro.HAS.getDefinition()); + Truth8.assertThat(parser.findMacro("all:2:true")) + .hasValue(CelStandardMacro.ALL.getDefinition()); + Truth8.assertThat(parser.findMacro("exists:2:true")) + .hasValue(CelStandardMacro.EXISTS.getDefinition()); + Truth8.assertThat(parser.findMacro("exists_one:2:true")) .hasValue(CelStandardMacro.EXISTS_ONE.getDefinition()); - assertThat(parser.findMacro("map:2:true")).hasValue(CelStandardMacro.MAP.getDefinition()); - assertThat(parser.findMacro("map:3:true")) + Truth8.assertThat(parser.findMacro("map:2:true")) + .hasValue(CelStandardMacro.MAP.getDefinition()); + Truth8.assertThat(parser.findMacro("map:3:true")) .hasValue(CelStandardMacro.MAP_FILTER.getDefinition()); - assertThat(parser.findMacro("filter:2:true")).hasValue(CelStandardMacro.FILTER.getDefinition()); + Truth8.assertThat(parser.findMacro("filter:2:true")) + .hasValue(CelStandardMacro.FILTER.getDefinition()); } @Test @@ -58,15 +63,20 @@ public void build_withStandardMacros_containsAllMacros() { CelParserImpl parser = (CelParserImpl) CelParserImpl.newBuilder().setStandardMacros(CelStandardMacro.STANDARD_MACROS).build(); - assertThat(parser.findMacro("has:1:false")).hasValue(CelStandardMacro.HAS.getDefinition()); - assertThat(parser.findMacro("all:2:true")).hasValue(CelStandardMacro.ALL.getDefinition()); - assertThat(parser.findMacro("exists:2:true")).hasValue(CelStandardMacro.EXISTS.getDefinition()); - assertThat(parser.findMacro("exists_one:2:true")) + Truth8.assertThat(parser.findMacro("has:1:false")) + .hasValue(CelStandardMacro.HAS.getDefinition()); + Truth8.assertThat(parser.findMacro("all:2:true")) + .hasValue(CelStandardMacro.ALL.getDefinition()); + Truth8.assertThat(parser.findMacro("exists:2:true")) + .hasValue(CelStandardMacro.EXISTS.getDefinition()); + Truth8.assertThat(parser.findMacro("exists_one:2:true")) .hasValue(CelStandardMacro.EXISTS_ONE.getDefinition()); - assertThat(parser.findMacro("map:2:true")).hasValue(CelStandardMacro.MAP.getDefinition()); - assertThat(parser.findMacro("map:3:true")) + Truth8.assertThat(parser.findMacro("map:2:true")) + .hasValue(CelStandardMacro.MAP.getDefinition()); + Truth8.assertThat(parser.findMacro("map:3:true")) .hasValue(CelStandardMacro.MAP_FILTER.getDefinition()); - assertThat(parser.findMacro("filter:2:true")).hasValue(CelStandardMacro.FILTER.getDefinition()); + Truth8.assertThat(parser.findMacro("filter:2:true")) + .hasValue(CelStandardMacro.FILTER.getDefinition()); } @Test @@ -81,30 +91,37 @@ public void build_withStandardMacrosAndCustomMacros_containsAllMacros() { .addMacros(customMacro) .build(); - assertThat(parser.findMacro("has:1:false")).hasValue(CelStandardMacro.HAS.getDefinition()); - assertThat(parser.findMacro("all:2:true")).hasValue(CelStandardMacro.ALL.getDefinition()); - assertThat(parser.findMacro("exists:2:true")).hasValue(CelStandardMacro.EXISTS.getDefinition()); - assertThat(parser.findMacro("exists_one:2:true")) + Truth8.assertThat(parser.findMacro("has:1:false")) + .hasValue(CelStandardMacro.HAS.getDefinition()); + Truth8.assertThat(parser.findMacro("all:2:true")) + .hasValue(CelStandardMacro.ALL.getDefinition()); + Truth8.assertThat(parser.findMacro("exists:2:true")) + .hasValue(CelStandardMacro.EXISTS.getDefinition()); + Truth8.assertThat(parser.findMacro("exists_one:2:true")) .hasValue(CelStandardMacro.EXISTS_ONE.getDefinition()); - assertThat(parser.findMacro("map:2:true")).hasValue(CelStandardMacro.MAP.getDefinition()); - assertThat(parser.findMacro("map:3:true")) + Truth8.assertThat(parser.findMacro("map:2:true")) + .hasValue(CelStandardMacro.MAP.getDefinition()); + Truth8.assertThat(parser.findMacro("map:3:true")) .hasValue(CelStandardMacro.MAP_FILTER.getDefinition()); - assertThat(parser.findMacro("filter:2:true")).hasValue(CelStandardMacro.FILTER.getDefinition()); - assertThat(parser.findMacro("customMacro:1:true")).hasValue(customMacro); + Truth8.assertThat(parser.findMacro("filter:2:true")) + .hasValue(CelStandardMacro.FILTER.getDefinition()); + Truth8.assertThat(parser.findMacro("customMacro:1:true")).hasValue(customMacro); } @Test public void build_withMacro_containsMacro() { CelParserImpl parser = (CelParserImpl) CelParserImpl.newBuilder().setStandardMacros(CelStandardMacro.HAS).build(); - assertThat(parser.findMacro("has:1:false")).hasValue(CelStandardMacro.HAS.getDefinition()); + Truth8.assertThat(parser.findMacro("has:1:false")) + .hasValue(CelStandardMacro.HAS.getDefinition()); } @Test public void build_withStandardMacro_containsMacro() { CelParserImpl parser = (CelParserImpl) CelParserImpl.newBuilder().setStandardMacros(CelStandardMacro.HAS).build(); - assertThat(parser.findMacro("has:1:false")).hasValue(CelStandardMacro.HAS.getDefinition()); + Truth8.assertThat(parser.findMacro("has:1:false")) + .hasValue(CelStandardMacro.HAS.getDefinition()); } @Test @@ -116,8 +133,9 @@ public void build_withStandardMacro_secondCallReplaces() { .setStandardMacros(CelStandardMacro.HAS) .build(); - assertThat(parser.findMacro("has:1:false")).hasValue(CelStandardMacro.HAS.getDefinition()); - assertThat(parser.findMacro("all:2:true")).isEmpty(); + Truth8.assertThat(parser.findMacro("has:1:false")) + .hasValue(CelStandardMacro.HAS.getDefinition()); + Truth8.assertThat(parser.findMacro("all:2:true")).isEmpty(); } @Test @@ -137,7 +155,7 @@ public void build_standardMacroKeyConflictsWithCustomMacro_throws() { @Test public void build_containsNoMacros() { CelParserImpl parser = (CelParserImpl) CelParserImpl.newBuilder().build(); - assertThat(parser.findMacro("has:1:false")).isEmpty(); + Truth8.assertThat(parser.findMacro("has:1:false")).isEmpty(); } @Test @@ -157,7 +175,7 @@ public void setParserOptions(CelParserBuilder parserBuilder) { }) .build(); - assertThat(parser.findMacro("dummyMacro:*:true")).isPresent(); + Truth8.assertThat(parser.findMacro("dummyMacro:*:true")).isPresent(); } @Test diff --git a/runtime/src/test/java/dev/cel/runtime/UnknownContextTest.java b/runtime/src/test/java/dev/cel/runtime/UnknownContextTest.java index a48fcc8d9..8d0c35d9d 100644 --- a/runtime/src/test/java/dev/cel/runtime/UnknownContextTest.java +++ b/runtime/src/test/java/dev/cel/runtime/UnknownContextTest.java @@ -15,10 +15,10 @@ package dev.cel.runtime; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import com.google.common.truth.Truth8; import java.util.Optional; import org.junit.Test; import org.junit.runner.RunWith; @@ -33,7 +33,8 @@ public void create_variableResolverOnly() { CelAttributeResolver attributeResolver = context.createAttributeResolver(); - assertThat(attributeResolver.resolve(CelAttribute.fromQualifiedIdentifier("test"))).isEmpty(); + Truth8.assertThat(attributeResolver.resolve(CelAttribute.fromQualifiedIdentifier("test"))) + .isEmpty(); assertThat(context.variableResolver().resolve("test")).isEqualTo("test_value"); } @@ -48,16 +49,16 @@ public void create_attributeResolverResolvesUnknown() { CelAttributeResolver attributeResolver = context.createAttributeResolver(); - assertThat( + Truth8.assertThat( attributeResolver.resolve( CelAttribute.fromQualifiedIdentifier("qualified.Identifier1"))) .hasValue( CelUnknownSet.create(CelAttribute.fromQualifiedIdentifier("qualified.Identifier1"))); - assertThat( + Truth8.assertThat( attributeResolver.resolve( CelAttribute.fromQualifiedIdentifier("qualified.Identifier2"))) .isEmpty(); - assertThat( + Truth8.assertThat( attributeResolver.resolve( CelAttribute.fromQualifiedIdentifier("qualified.Identifier2.field1"))) .hasValue( @@ -76,17 +77,17 @@ public void create_attributeResolverIdentifiesPartials() { CelAttributeResolver attributeResolver = context.createAttributeResolver(); - assertThat( + Truth8.assertThat( attributeResolver.maybePartialUnknown( CelAttribute.fromQualifiedIdentifier("qualified.Identifier1"))) .hasValue( CelUnknownSet.create(CelAttribute.fromQualifiedIdentifier("qualified.Identifier1"))); - assertThat( + Truth8.assertThat( attributeResolver.maybePartialUnknown( CelAttribute.fromQualifiedIdentifier("qualified.Identifier2"))) .hasValue( CelUnknownSet.create(CelAttribute.fromQualifiedIdentifier("qualified.Identifier2"))); - assertThat( + Truth8.assertThat( attributeResolver.maybePartialUnknown( CelAttribute.fromQualifiedIdentifier("qualified.Identifier2.field1"))) .hasValue( @@ -105,17 +106,17 @@ public void withResolvedAttributes_attributeResolverReturnsValue() { CelAttributeResolver attributeResolver = context.createAttributeResolver(); - assertThat( + Truth8.assertThat( attributeResolver.maybePartialUnknown( CelAttribute.fromQualifiedIdentifier("qualified.Identifier1"))) .hasValue( CelUnknownSet.create(CelAttribute.fromQualifiedIdentifier("qualified.Identifier1"))); - assertThat( + Truth8.assertThat( attributeResolver.maybePartialUnknown( CelAttribute.fromQualifiedIdentifier("qualified.Identifier2"))) .hasValue( CelUnknownSet.create(CelAttribute.fromQualifiedIdentifier("qualified.Identifier2"))); - assertThat( + Truth8.assertThat( attributeResolver.maybePartialUnknown( CelAttribute.fromQualifiedIdentifier("qualified.Identifier2.field1"))) .hasValue( @@ -135,7 +136,7 @@ public void withResolvedAttributes_attributeResolverResolves() { CelAttributeResolver attributeResolver = context.createAttributeResolver(); - assertThat( + Truth8.assertThat( attributeResolver.resolve(CelAttribute.fromQualifiedIdentifier("qualified.Identifier"))) .hasValue("value1"); } @@ -156,14 +157,14 @@ public void withResolvedAttributes_attributeResolverPartialsShadowed() { CelAttributeResolver attributeResolver = context.createAttributeResolver(); - assertThat( + Truth8.assertThat( attributeResolver.resolve(CelAttribute.fromQualifiedIdentifier("qualified.Identifier"))) .hasValue("value1"); - assertThat( + Truth8.assertThat( attributeResolver.maybePartialUnknown( CelAttribute.fromQualifiedIdentifier("qualified.Identifier.field1"))) .isEmpty(); - assertThat( + Truth8.assertThat( attributeResolver.maybePartialUnknown( CelAttribute.fromQualifiedIdentifier("qualified.Identifier.field2"))) .isEmpty(); From 9ae535cdfe8c39ab8488bfb210297bcc37b29b9e Mon Sep 17 00:00:00 2001 From: cpovirk Date: Tue, 30 Jan 2024 13:54:32 -0800 Subject: [PATCH 020/486] No public description PiperOrigin-RevId: 602831989 --- WORKSPACE | 10 +++++----- .../test/java/dev/cel/common/types/EnumTypeTest.java | 2 +- parser/src/test/java/dev/cel/parser/OperatorTest.java | 2 +- .../java/dev/cel/runtime/CelVariableResolverTest.java | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/WORKSPACE b/WORKSPACE index 74520223a..dd6291bf1 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -63,15 +63,15 @@ maven_install( "com.google.auto.value:auto-value-annotations:1.10.4", "com.google.code.findbugs:annotations:3.0.1", "com.google.errorprone:error_prone_annotations:2.23.0", - "com.google.guava:guava:32.1.3-jre", - "com.google.guava:guava-testlib:32.1.3-jre", + "com.google.guava:guava:33.0.0-jre", + "com.google.guava:guava-testlib:33.0.0-jre", "com.google.protobuf:protobuf-java:3.24.4", "com.google.protobuf:protobuf-java-util:3.24.4", "com.google.re2j:re2j:1.7", "com.google.testparameterinjector:test-parameter-injector:1.14", - "com.google.truth.extensions:truth-java8-extension:1.1.5", - "com.google.truth.extensions:truth-proto-extension:1.1.5", - "com.google.truth:truth:1.1.5", + "com.google.truth.extensions:truth-java8-extension:1.3.0", + "com.google.truth.extensions:truth-proto-extension:1.3.0", + "com.google.truth:truth:1.3.0", "org.antlr:antlr4-runtime:" + ANTLR4_VERSION, "org.jspecify:jspecify:0.2.0", "org.threeten:threeten-extra:1.7.2", diff --git a/common/src/test/java/dev/cel/common/types/EnumTypeTest.java b/common/src/test/java/dev/cel/common/types/EnumTypeTest.java index 3f59e4011..3fdc47148 100644 --- a/common/src/test/java/dev/cel/common/types/EnumTypeTest.java +++ b/common/src/test/java/dev/cel/common/types/EnumTypeTest.java @@ -14,7 +14,7 @@ package dev.cel.common.types; -import static com.google.common.truth.Truth8.assertThat; +import static com.google.common.truth.Truth.assertThat; import com.google.common.collect.ImmutableMap; import org.junit.Before; diff --git a/parser/src/test/java/dev/cel/parser/OperatorTest.java b/parser/src/test/java/dev/cel/parser/OperatorTest.java index 93346e631..8f1a0bb86 100644 --- a/parser/src/test/java/dev/cel/parser/OperatorTest.java +++ b/parser/src/test/java/dev/cel/parser/OperatorTest.java @@ -14,7 +14,7 @@ package dev.cel.parser; -import static com.google.common.truth.Truth8.assertThat; +import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; diff --git a/runtime/src/test/java/dev/cel/runtime/CelVariableResolverTest.java b/runtime/src/test/java/dev/cel/runtime/CelVariableResolverTest.java index 235ef1516..3d2515ad3 100644 --- a/runtime/src/test/java/dev/cel/runtime/CelVariableResolverTest.java +++ b/runtime/src/test/java/dev/cel/runtime/CelVariableResolverTest.java @@ -14,7 +14,7 @@ package dev.cel.runtime; -import static com.google.common.truth.Truth8.assertThat; +import static com.google.common.truth.Truth.assertThat; import static dev.cel.runtime.CelVariableResolver.hierarchicalVariableResolver; import com.google.common.collect.ImmutableMap; From aa0fb8cb55a2fb912d9e5f91e03eb57711b8325c Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Wed, 31 Jan 2024 15:58:31 -0800 Subject: [PATCH 021/486] Add serialization capability for tagged AST extensions PiperOrigin-RevId: 603185360 --- WORKSPACE | 6 +- .../common/CelProtoAbstractSyntaxTree.java | 75 +++++++++++ .../main/java/dev/cel/common/CelSource.java | 116 +++++++++++++++--- .../CelProtoAbstractSyntaxTreeTest.java | 10 ++ .../java/dev/cel/common/CelSourceTest.java | 24 ++++ 5 files changed, 212 insertions(+), 19 deletions(-) diff --git a/WORKSPACE b/WORKSPACE index dd6291bf1..351e82213 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -138,10 +138,10 @@ http_archive( # cel-spec api/expr canonical protos http_archive( name = "cel_spec", - sha256 = "6c2d9ec6dd5e2afbc41423dcaeca9fdd73edcd76554a897caee5b9a2b0e20491", - strip_prefix = "cel-spec-0.11.0", + sha256 = "3579c97b13548714f9059ef6f30c5264d439efef4b438e76e7180709efd93a6b", + strip_prefix = "cel-spec-0.14.0", urls = [ - "https://github.com/google/cel-spec/archive/refs/tags/v0.11.0.tar.gz", + "https://github.com/google/cel-spec/archive/refs/tags/v0.14.0.tar.gz", ], ) diff --git a/common/src/main/java/dev/cel/common/CelProtoAbstractSyntaxTree.java b/common/src/main/java/dev/cel/common/CelProtoAbstractSyntaxTree.java index fa0719e87..ef69c174b 100644 --- a/common/src/main/java/dev/cel/common/CelProtoAbstractSyntaxTree.java +++ b/common/src/main/java/dev/cel/common/CelProtoAbstractSyntaxTree.java @@ -15,16 +15,22 @@ package dev.cel.common; import static com.google.common.base.Preconditions.checkState; +import static com.google.common.collect.ImmutableList.toImmutableList; import static com.google.common.collect.ImmutableMap.toImmutableMap; import dev.cel.expr.CheckedExpr; import dev.cel.expr.Expr; import dev.cel.expr.ParsedExpr; import dev.cel.expr.SourceInfo; +import dev.cel.expr.SourceInfo.Extension; +import dev.cel.expr.SourceInfo.Extension.Component; +import dev.cel.expr.SourceInfo.Extension.Version; import dev.cel.expr.Type; +import com.google.common.collect.ImmutableList; import com.google.errorprone.annotations.CheckReturnValue; import dev.cel.common.ast.CelExprConverter; import dev.cel.common.types.CelTypes; +import java.util.Collection; import java.util.Map.Entry; /** @@ -49,6 +55,9 @@ private CelProtoAbstractSyntaxTree(CheckedExpr checkedExpr) { .addAllMacroCalls( CelExprConverter.exprMacroCallsToCelExprMacroCalls( checkedExpr.getSourceInfo().getMacroCallsMap())) + .addAllExtensions( + fromExprExtensionsToCelExtensions( + checkedExpr.getSourceInfo().getExtensionsList())) .setDescription(checkedExpr.getSourceInfo().getLocation()) .build(), checkedExpr.getReferenceMapMap().entrySet().stream() @@ -69,6 +78,8 @@ private CelProtoAbstractSyntaxTree(CelAbstractSyntaxTree ast) { SourceInfo.newBuilder() .setLocation(ast.getSource().getDescription()) .addAllLineOffsets(ast.getSource().getLineOffsets()) + .addAllExtensions( + fromCelExtensionsToExprExtensions(ast.getSource().getExtensions())) .putAllMacroCalls( ast.getSource().getMacroCalls().entrySet().stream() .collect( @@ -173,5 +184,69 @@ public ParsedExpr toParsedExpr() { public Type getProtoResultType() { return CelTypes.celTypeToType(ast.getResultType()); } + + private static ImmutableList fromCelExtensionsToExprExtensions( + Collection extensions) { + return extensions.stream() + .map( + celSourceExtension -> + Extension.newBuilder() + .setId(celSourceExtension.id()) + .setVersion( + Version.newBuilder() + .setMajor(celSourceExtension.version().major()) + .setMinor(celSourceExtension.version().minor())) + .addAllAffectedComponents( + celSourceExtension.affectedComponents().stream() + .map( + component -> { + switch (component) { + case COMPONENT_UNSPECIFIED: + return Component.COMPONENT_UNSPECIFIED; + case COMPONENT_PARSER: + return Component.COMPONENT_PARSER; + case COMPONENT_TYPE_CHECKER: + return Component.COMPONENT_TYPE_CHECKER; + case COMPONENT_RUNTIME: + return Component.COMPONENT_RUNTIME; + } + throw new AssertionError( + "Unexpected component kind: " + component); + }) + .collect(toImmutableList())) + .build()) + .collect(toImmutableList()); + } + + private static ImmutableList fromExprExtensionsToCelExtensions( + Collection extensions) { + return extensions.stream() + .map( + exprExtension -> + CelSource.Extension.create( + exprExtension.getId(), + CelSource.Extension.Version.of( + exprExtension.getVersion().getMajor(), + exprExtension.getVersion().getMinor()), + exprExtension.getAffectedComponentsList().stream() + .map( + component -> { + switch (component) { + case COMPONENT_UNSPECIFIED: + return CelSource.Extension.Component.COMPONENT_UNSPECIFIED; + case COMPONENT_PARSER: + return CelSource.Extension.Component.COMPONENT_PARSER; + case COMPONENT_TYPE_CHECKER: + return CelSource.Extension.Component.COMPONENT_TYPE_CHECKER; + case COMPONENT_RUNTIME: + return CelSource.Extension.Component.COMPONENT_RUNTIME; + case UNRECOGNIZED: + // fall-through + } + throw new AssertionError("Unexpected component kind: " + component); + }) + .collect(toImmutableList()))) + .collect(toImmutableList()); + } } // LINT.ThenChange(CelProtoV1Alpha1AbstractSyntaxTree.java) diff --git a/common/src/main/java/dev/cel/common/CelSource.java b/common/src/main/java/dev/cel/common/CelSource.java index 88ab19c65..3f4c0d2d7 100644 --- a/common/src/main/java/dev/cel/common/CelSource.java +++ b/common/src/main/java/dev/cel/common/CelSource.java @@ -17,6 +17,7 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; +import com.google.auto.value.AutoValue; import com.google.common.base.Splitter; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; @@ -26,6 +27,7 @@ import dev.cel.common.ast.CelExpr; import dev.cel.common.internal.CelCodePointArray; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -34,7 +36,6 @@ /** Represents the source content of an expression and related metadata. */ @Immutable public final class CelSource { - private static final Splitter LINE_SPLITTER = Splitter.on('\n'); private final CelCodePointArray codePoints; @@ -42,13 +43,15 @@ public final class CelSource { private final ImmutableList lineOffsets; private final ImmutableMap positions; private final ImmutableMap macroCalls; + private final ImmutableList extensions; private CelSource(Builder builder) { - codePoints = checkNotNull(builder.codePoints); - description = checkNotNull(builder.description); - positions = checkNotNull(builder.positions.buildOrThrow()); - lineOffsets = checkNotNull(ImmutableList.copyOf(builder.lineOffsets)); - macroCalls = checkNotNull(ImmutableMap.copyOf(builder.macroCalls)); + this.codePoints = checkNotNull(builder.codePoints); + this.description = checkNotNull(builder.description); + this.positions = checkNotNull(builder.positions.buildOrThrow()); + this.lineOffsets = checkNotNull(ImmutableList.copyOf(builder.lineOffsets)); + this.macroCalls = checkNotNull(ImmutableMap.copyOf(builder.macroCalls)); + this.extensions = checkNotNull(builder.extensions.build()); } public CelCodePointArray getContent() { @@ -77,6 +80,10 @@ public ImmutableMap getMacroCalls() { return macroCalls; } + public ImmutableList getExtensions() { + return extensions; + } + /** See {@link #getLocationOffset(int, int)}. */ public Optional getLocationOffset(CelSourceLocation location) { checkNotNull(location); @@ -201,6 +208,7 @@ public static final class Builder { private final List lineOffsets; private final ImmutableMap.Builder positions; private final Map macroCalls; + private final ImmutableList.Builder extensions; private String description; @@ -213,7 +221,8 @@ private Builder(CelCodePointArray codePoints, List lineOffsets) { this.lineOffsets = checkNotNull(lineOffsets); this.positions = ImmutableMap.builder(); this.macroCalls = new HashMap<>(); - description = ""; + this.extensions = ImmutableList.builder(); + this.description = ""; } @CanIgnoreReturnValue @@ -229,15 +238,6 @@ public Builder addLineOffsets(int lineOffset) { return this; } - @CanIgnoreReturnValue - public Builder addLineOffsets(int... lineOffsets) { - // Purposefully not using Arrays.asList to avoid int boxing/unboxing. - for (int index = 0; index != lineOffsets.length; index++) { - addLineOffsets(lineOffsets[index]); - } - return this; - } - @CanIgnoreReturnValue public Builder addAllLineOffsets(Iterable lineOffsets) { for (int lineOffset : lineOffsets) { @@ -277,6 +277,18 @@ public Builder clearMacroCall(long exprId) { return this; } + @CanIgnoreReturnValue + public Builder addAllExtensions(Iterable extensions) { + checkNotNull(extensions); + this.extensions.addAll(extensions); + return this; + } + + @CanIgnoreReturnValue + public Builder addAllExtensions(Extension... extensions) { + return addAllExtensions(Arrays.asList(extensions)); + } + /** See {@link #getLocationOffset(int, int)}. */ public Optional getLocationOffset(CelSourceLocation location) { checkNotNull(location); @@ -333,4 +345,76 @@ private LineAndOffset(int line, int offset) { int line; int offset; } + + /** + * Tag for an extension that were used while parsing or type checking the source expression. For + * example, optimizations that require special runtime support may be specified. These are used to + * check feature support between components in separate implementations. This can be used to + * either skip redundant work or report an error if the extension is unsupported. + */ + @AutoValue + @Immutable + abstract static class Extension { + + /** Identifier for the extension. Example: constant_folding */ + abstract String id(); + + /** + * Version info. May be skipped if it isn't meaningful for the extension. (for example + * constant_folding might always be v0.0). + */ + abstract Version version(); + + /** + * If set, the listed components must understand the extension for the expression to evaluate + * correctly. + */ + abstract ImmutableList affectedComponents(); + + @AutoValue + @Immutable + abstract static class Version { + + /** + * Major version changes indicate different required support level from the required + * components. + */ + abstract long major(); + + /** + * Minor version changes must not change the observed behavior from existing implementations, + * but may be provided informational. + */ + abstract long minor(); + + /** Create a new instance of Version with the provided major and minor values. */ + static Version of(long major, long minor) { + return new AutoValue_CelSource_Extension_Version(major, minor); + } + } + + /** CEL component specifier. */ + enum Component { + /** Unspecified, default. */ + COMPONENT_UNSPECIFIED, + /** Parser. Converts a CEL string to an AST. */ + COMPONENT_PARSER, + /** Type checker. Checks that references in an AST are defined and types agree. */ + COMPONENT_TYPE_CHECKER, + /** Runtime. Evaluates a parsed and optionally checked CEL AST against a context. */ + COMPONENT_RUNTIME; + } + + @CheckReturnValue + static Extension create(String id, Version version, Iterable components) { + checkNotNull(version); + checkNotNull(components); + return new AutoValue_CelSource_Extension(id, version, ImmutableList.copyOf(components)); + } + + @CheckReturnValue + static Extension create(String id, Version version, Component... components) { + return create(id, version, Arrays.asList(components)); + } + } } diff --git a/common/src/test/java/dev/cel/common/CelProtoAbstractSyntaxTreeTest.java b/common/src/test/java/dev/cel/common/CelProtoAbstractSyntaxTreeTest.java index 8ab329f6d..1d6170f56 100644 --- a/common/src/test/java/dev/cel/common/CelProtoAbstractSyntaxTreeTest.java +++ b/common/src/test/java/dev/cel/common/CelProtoAbstractSyntaxTreeTest.java @@ -25,6 +25,9 @@ import dev.cel.expr.ParsedExpr; import dev.cel.expr.Reference; import dev.cel.expr.SourceInfo; +import dev.cel.expr.SourceInfo.Extension; +import dev.cel.expr.SourceInfo.Extension.Component; +import dev.cel.expr.SourceInfo.Extension.Version; import dev.cel.common.types.CelTypes; import java.util.Arrays; import org.junit.Test; @@ -57,6 +60,13 @@ public class CelProtoAbstractSyntaxTreeTest { .setLocation("test/location.cel") .putPositions(1L, 0) .addLineOffsets(4) + .addExtensions( + Extension.newBuilder() + .setId("extension_id") + .addAffectedComponents(Component.COMPONENT_PARSER) + .addAffectedComponents(Component.COMPONENT_TYPE_CHECKER) + .addAffectedComponents(Component.COMPONENT_RUNTIME) + .setVersion(Version.newBuilder().setMajor(5).setMinor(3))) .putMacroCalls( 2, Expr.newBuilder() diff --git a/common/src/test/java/dev/cel/common/CelSourceTest.java b/common/src/test/java/dev/cel/common/CelSourceTest.java index e7b2aaf0c..e77db1da6 100644 --- a/common/src/test/java/dev/cel/common/CelSourceTest.java +++ b/common/src/test/java/dev/cel/common/CelSourceTest.java @@ -19,6 +19,9 @@ import static org.junit.Assert.assertThrows; import com.google.common.truth.Truth8; +import dev.cel.common.CelSource.Extension; +import dev.cel.common.CelSource.Extension.Component; +import dev.cel.common.CelSource.Extension.Version; import dev.cel.common.internal.BasicCodePointArray; import dev.cel.common.internal.CodePointStream; import dev.cel.common.internal.Latin1CodePointArray; @@ -157,4 +160,25 @@ public void fromString_handlesMultiLineSupplemental() throws Exception { assertThat(charStream.LA(-1)).isEqualTo(IntStream.EOF); assertThat(source.getLineOffsets()).containsExactly(6, 13).inOrder(); } + + @Test + public void source_withExtension() { + CelSource celSource = + CelSource.newBuilder("") + .addAllExtensions( + Extension.create( + "extension_id", + Version.of(5, 3), + Component.COMPONENT_PARSER, + Component.COMPONENT_TYPE_CHECKER)) + .build(); + + Extension extension = celSource.getExtensions().get(0); + assertThat(extension.id()).isEqualTo("extension_id"); + assertThat(extension.version().major()).isEqualTo(5L); + assertThat(extension.version().minor()).isEqualTo(3L); + assertThat(extension.affectedComponents()) + .containsExactly(Component.COMPONENT_PARSER, Component.COMPONENT_TYPE_CHECKER); + assertThat(celSource.getExtensions()).hasSize(1); + } } From 6f55a674d7fdbe44f57251b332efa35a203bf3ad Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Mon, 5 Feb 2024 10:54:43 -0800 Subject: [PATCH 022/486] Move cel.bind memoization into ScopedResolver PiperOrigin-RevId: 604368929 --- .../extensions/CelBindingsExtensionsTest.java | 3 ++- .../dev/cel/runtime/DefaultInterpreter.java | 16 +++---------- .../cel/runtime/RuntimeUnknownResolver.java | 23 ++++++++++++++++--- 3 files changed, 25 insertions(+), 17 deletions(-) diff --git a/extensions/src/test/java/dev/cel/extensions/CelBindingsExtensionsTest.java b/extensions/src/test/java/dev/cel/extensions/CelBindingsExtensionsTest.java index a11a6a93b..218435d98 100644 --- a/extensions/src/test/java/dev/cel/extensions/CelBindingsExtensionsTest.java +++ b/extensions/src/test/java/dev/cel/extensions/CelBindingsExtensionsTest.java @@ -62,7 +62,8 @@ private enum BindingTestCase { + " \"aaaa:aaaa\""), BIND_WITH_EXISTS_TRUE( "cel.bind(valid_elems, [1, 2, 3], [3, 4, 5].exists(e, e in valid_elems))"), - BIND_WITH_EXISTS_FALSE("cel.bind(valid_elems, [1, 2, 3], ![4, 5].exists(e, e in valid_elems))"); + BIND_WITH_EXISTS_FALSE("cel.bind(valid_elems, [1, 2, 3], ![4, 5].exists(e, e in valid_elems))"), + BIND_WITH_MAP("[1,2,3].map(x, cel.bind(y, x + x, [y, y])) == [[2, 2], [4, 4], [6, 6]]"); private final String source; diff --git a/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java b/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java index f21cd18bf..f27882eda 100644 --- a/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java +++ b/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java @@ -275,11 +275,6 @@ private IntermediateResult resolveIdent(ExecutionFrame frame, CelExpr expr, Stri return IntermediateResult.create(typeValue); } - IntermediateResult cachedResult = frame.lookupLazilyEvaluatedResult(name).orElse(null); - if (cachedResult != null) { - return cachedResult; - } - IntermediateResult rawResult = frame.resolveSimpleName(name, expr.id()); Object value = rawResult.value(); boolean isLazyExpression = value instanceof LazyExpression; @@ -885,7 +880,6 @@ private static class ExecutionFrame { private final CelEvaluationListener evaluationListener; private final int maxIterations; private final ArrayDeque resolvers; - private final Map lazyEvalResultCache; private RuntimeUnknownResolver currentResolver; private int iterations; @@ -898,7 +892,6 @@ private ExecutionFrame( this.resolvers.add(resolver); this.currentResolver = resolver; this.maxIterations = maxIterations; - this.lazyEvalResultCache = new HashMap<>(); } private CelEvaluationListener getEvaluationListener() { @@ -929,12 +922,9 @@ private Optional resolveAttribute(CelAttribute attr) { return currentResolver.resolveAttribute(attr); } - private Optional lookupLazilyEvaluatedResult(String name) { - return Optional.ofNullable(lazyEvalResultCache.get(name)); - } - - private void cacheLazilyEvaluatedResult(String name, IntermediateResult result) { - lazyEvalResultCache.put(name, result); + private void cacheLazilyEvaluatedResult( + String name, DefaultInterpreter.IntermediateResult result) { + currentResolver.cacheLazilyEvaluatedResult(name, result); } private void pushScope(ImmutableMap scope) { diff --git a/runtime/src/main/java/dev/cel/runtime/RuntimeUnknownResolver.java b/runtime/src/main/java/dev/cel/runtime/RuntimeUnknownResolver.java index e68270cad..1c1be9b94 100644 --- a/runtime/src/main/java/dev/cel/runtime/RuntimeUnknownResolver.java +++ b/runtime/src/main/java/dev/cel/runtime/RuntimeUnknownResolver.java @@ -16,6 +16,7 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue; import dev.cel.common.annotations.Internal; +import java.util.HashMap; import java.util.Map; import java.util.Optional; @@ -33,6 +34,7 @@ public class RuntimeUnknownResolver { /** The underlying resolver for known values. */ private final GlobalResolver resolver; + /** Resolver for unknown and resolved attributes. */ private final CelAttributeResolver attributeResolver; @@ -112,6 +114,10 @@ DefaultInterpreter.IntermediateResult resolveSimpleName(String name, Long exprId attr, InterpreterUtil.valueOrUnknown(result, exprId)); } + void cacheLazilyEvaluatedResult(String name, DefaultInterpreter.IntermediateResult result) { + // no-op. Caching is handled in ScopedResolver. + } + /** * Attempt to resolve an attribute bound to a context variable. This is used to shadow lazily * resolved values behind field accesses and index operations. @@ -127,6 +133,7 @@ ScopedResolver withScope(Map vars static final class ScopedResolver extends RuntimeUnknownResolver { private final RuntimeUnknownResolver parent; private final Map shadowedVars; + private final Map lazyEvalResultCache; private ScopedResolver( RuntimeUnknownResolver parent, @@ -134,16 +141,26 @@ private ScopedResolver( super(parent.resolver, parent.attributeResolver, parent.attributeTrackingEnabled); this.parent = parent; this.shadowedVars = shadowedVars; + this.lazyEvalResultCache = new HashMap<>(); } @Override DefaultInterpreter.IntermediateResult resolveSimpleName(String name, Long exprId) { - DefaultInterpreter.IntermediateResult shadowed = shadowedVars.get(name); - if (shadowed != null) { - return shadowed; + DefaultInterpreter.IntermediateResult result = lazyEvalResultCache.get(name); + if (result != null) { + return result; + } + result = shadowedVars.get(name); + if (result != null) { + return result; } return parent.resolveSimpleName(name, exprId); } + + @Override + void cacheLazilyEvaluatedResult(String name, DefaultInterpreter.IntermediateResult result) { + lazyEvalResultCache.put(name, result); + } } /** Null implementation for attribute resolution. */ From 5957b550630347f9b3a586eeb24c29f29b0e7157 Mon Sep 17 00:00:00 2001 From: cpovirk Date: Tue, 6 Feb 2024 11:26:22 -0800 Subject: [PATCH 023/486] Update to [Truth 1.4.0](https://github.com/google/truth/releases/tag/v1.4.0). This makes available the rest of the Truth APIs that were recently added in Google's monorepo. It may be worth also updating to the _following_ version of Truth after it's released, but the purpose of that release will mostly be to deprecate `Truth8`. So, if you just avoid using `Truth8` now (starting by approving any migration CLs that I send your way), then there will be little need for that upgrade. Or, more to the point: I don't expect to keep sending you weekly upgrade CLs after this one :) PiperOrigin-RevId: 604710681 --- WORKSPACE | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/WORKSPACE b/WORKSPACE index 351e82213..d2cd47952 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -69,9 +69,9 @@ maven_install( "com.google.protobuf:protobuf-java-util:3.24.4", "com.google.re2j:re2j:1.7", "com.google.testparameterinjector:test-parameter-injector:1.14", - "com.google.truth.extensions:truth-java8-extension:1.3.0", - "com.google.truth.extensions:truth-proto-extension:1.3.0", - "com.google.truth:truth:1.3.0", + "com.google.truth.extensions:truth-java8-extension:1.4.0", + "com.google.truth.extensions:truth-proto-extension:1.4.0", + "com.google.truth:truth:1.4.0", "org.antlr:antlr4-runtime:" + ANTLR4_VERSION, "org.jspecify:jspecify:0.2.0", "org.threeten:threeten-extra:1.7.2", From 8f51c976db53931e9fd3230a885ace815bf18ae4 Mon Sep 17 00:00:00 2001 From: cpovirk Date: Tue, 6 Feb 2024 13:03:52 -0800 Subject: [PATCH 024/486] Migrate usages of `Truth8.assertThat` to equivalent usages of `Truth.assertThat`. The `Truth8` methods will be deprecated (or hidden) in the future. Callers should move to `Truth`. Some (but not all) of the CLs in this batch require Truth [1.4.0](https://github.com/google/truth/releases/tag/v1.4.0). I submitted a CL earlier today to (I hope) perform that upgrade for your project. PiperOrigin-RevId: 604739382 --- .../dev/cel/checker/CelIdentDeclTest.java | 7 +- .../ProtoTypeMaskTypeProviderTest.java | 13 +- .../dev/cel/checker/TypeInferencerTest.java | 103 ++++++++-------- .../cel/common/CelAbstractSyntaxTreeTest.java | 25 ++-- .../java/dev/cel/common/CelSourceTest.java | 5 +- .../cel/common/ast/CelExprVisitorTest.java | 3 +- .../dev/cel/common/ast/CelReferenceTest.java | 7 +- .../internal/CombinedDescriptorPoolTest.java | 12 +- .../DefaultInstanceMessageFactoryTest.java | 7 +- .../internal/DefaultMessageFactoryTest.java | 7 +- .../dev/cel/common/internal/ErrorsTest.java | 9 +- .../cel/common/internal/ProtoAdapterTest.java | 32 +++-- .../navigation/CelNavigableAstTest.java | 3 +- .../navigation/CelNavigableExprTest.java | 7 +- .../CelNavigableExprVisitorTest.java | 5 +- .../types/ProtoMessageTypeProviderTest.java | 116 ++++++++---------- .../common/types/ProtoMessageTypeTest.java | 9 +- .../cel/common/values/OptionalValueTest.java | 3 +- .../common/values/ProtoMessageValueTest.java | 15 ++- .../extensions/CelOptionalLibraryTest.java | 25 ++-- .../cel/parser/CelMacroExprFactoryTest.java | 5 +- .../dev/cel/parser/CelParserImplTest.java | 75 +++++------ .../dev/cel/runtime/UnknownContextTest.java | 30 +++-- 23 files changed, 234 insertions(+), 289 deletions(-) diff --git a/checker/src/test/java/dev/cel/checker/CelIdentDeclTest.java b/checker/src/test/java/dev/cel/checker/CelIdentDeclTest.java index 1d131eb8f..6dd221ae1 100644 --- a/checker/src/test/java/dev/cel/checker/CelIdentDeclTest.java +++ b/checker/src/test/java/dev/cel/checker/CelIdentDeclTest.java @@ -22,7 +22,6 @@ import dev.cel.expr.Decl.IdentDecl; import dev.cel.expr.Type; import dev.cel.expr.Type.PrimitiveType; -import com.google.common.truth.Truth8; import dev.cel.common.ast.CelConstant; import dev.cel.common.types.SimpleType; import org.junit.Test; @@ -45,7 +44,7 @@ public void celIdentBuilder_success() { assertThat(stringIdent.name()).isEqualTo("ident"); assertThat(stringIdent.type()).isEqualTo(SimpleType.STRING); assertThat(stringIdent.doc()).isEqualTo("doc"); - Truth8.assertThat(stringIdent.constant()).hasValue(CelConstant.ofValue("str")); + assertThat(stringIdent.constant()).hasValue(CelConstant.ofValue("str")); } @Test @@ -58,7 +57,7 @@ public void celIdentBuilder_clearConstant() { builder.clearConstant(); - Truth8.assertThat(builder.build().constant()).isEmpty(); + assertThat(builder.build().constant()).isEmpty(); } @Test @@ -68,7 +67,7 @@ public void newIdentDeclaration_success() { assertThat(intIdent.name()).isEqualTo("ident"); assertThat(intIdent.type()).isEqualTo(SimpleType.INT); assertThat(intIdent.doc()).isEmpty(); - Truth8.assertThat(intIdent.constant()).isEmpty(); + assertThat(intIdent.constant()).isEmpty(); } @Test diff --git a/checker/src/test/java/dev/cel/checker/ProtoTypeMaskTypeProviderTest.java b/checker/src/test/java/dev/cel/checker/ProtoTypeMaskTypeProviderTest.java index 79269e47a..31d0fb221 100644 --- a/checker/src/test/java/dev/cel/checker/ProtoTypeMaskTypeProviderTest.java +++ b/checker/src/test/java/dev/cel/checker/ProtoTypeMaskTypeProviderTest.java @@ -21,7 +21,6 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; -import com.google.common.truth.Truth8; import com.google.protobuf.FieldMask; import com.google.rpc.context.AttributeContext; import dev.cel.common.types.CelType; @@ -64,7 +63,7 @@ public void lookupFieldNames_undeclaredMessageType() { CelTypeProvider celTypeProvider = new ProtoMessageTypeProvider(); ProtoTypeMaskTypeProvider protoTypeMaskProvider = new ProtoTypeMaskTypeProvider(celTypeProvider, ImmutableList.of()); - Truth8.assertThat(protoTypeMaskProvider.findType(ATTRIBUTE_CONTEXT_TYPE)).isEmpty(); + assertThat(protoTypeMaskProvider.findType(ATTRIBUTE_CONTEXT_TYPE)).isEmpty(); } @Test @@ -206,7 +205,7 @@ public void lookupFieldType() { .addPaths("request.auth.*") .build()))); ProtoMessageType ctxType = assertTypeFound(protoTypeMaskProvider, ATTRIBUTE_CONTEXT_TYPE); - Truth8.assertThat(ctxType.findField("resource")).isPresent(); + assertThat(ctxType.findField("resource")).isPresent(); assertTypeHasFieldWithType(ctxType, "resource", RESOURCE_TYPE); assertTypeHasFieldWithType(ctxType, "request", REQUEST_TYPE); @@ -238,7 +237,7 @@ public void lookupFieldType_notExposedField() { "google.rpc.context.AttributeContext", FieldMask.newBuilder().addPaths("resource.name").build()))); ProtoMessageType resourceType = assertTypeFound(protoTypeMaskProvider, RESOURCE_TYPE); - Truth8.assertThat(resourceType.findField("type")).isEmpty(); + assertThat(resourceType.findField("type")).isEmpty(); } @Test @@ -252,12 +251,12 @@ public void lookupType_notExposed() { ProtoTypeMask.of( "google.rpc.context.AttributeContext", FieldMask.newBuilder().addPaths("resource.name").build()))); - Truth8.assertThat(protoTypeMaskProvider.findType(REQUEST_TYPE)).isPresent(); + assertThat(protoTypeMaskProvider.findType(REQUEST_TYPE)).isPresent(); } private ProtoMessageType assertTypeFound(CelTypeProvider celTypeProvider, String typeName) { Optional foundType = celTypeProvider.findType(typeName); - Truth8.assertThat(foundType).isPresent(); + assertThat(foundType).isPresent(); CelType celType = foundType.get(); assertThat(celType).isInstanceOf(ProtoMessageType.class); return (ProtoMessageType) celType; @@ -271,7 +270,7 @@ private void assertTypeHasFields(ProtoMessageType protoType, ImmutableSet result = inferencer.unify(mapInst, mapParamFresh); - Truth8.assertThat(result).isPresent(); + assertThat(result).isPresent(); assertThat(result.get().substitutions()) .containsExactly( mapParamFresh.keyType().name(), @@ -86,8 +85,8 @@ public void unify_success_parameterizedMapReversedArgs() { MapType mapInst = MapType.create(SimpleType.STRING, ListType.create(TypeParamType.create("V"))); MapType mapParamFresh = (MapType) mapParam.withFreshTypeParamVariables(typeVarGenerator); Optional result = inferencer.unify(mapParamFresh, mapInst); - Truth8.assertThat(result).isPresent(); - Truth8.assertThat(result.get().unifiedType()).hasValue(mapInst); + assertThat(result).isPresent(); + assertThat(result.get().unifiedType()).hasValue(mapInst); assertThat(result.get().substitutions()) .containsExactly( mapParamFresh.keyType().name(), @@ -103,12 +102,12 @@ public void unify_success_jsonEqualsDoubleOneByOne() { TypeParamType equalsArg = TypeParamType.create("T"); CelType equalsArgFresh = equalsArg.withFreshTypeParamVariables(typeVarGenerator); Optional firstArg = inferencer.unify(JsonType.JSON, equalsArgFresh); - Truth8.assertThat(firstArg).isPresent(); - Truth8.assertThat(firstArg.get().unifiedType()).hasValue(JsonType.JSON); + assertThat(firstArg).isPresent(); + assertThat(firstArg.get().unifiedType()).hasValue(JsonType.JSON); inferencer.recordSubstitutions(firstArg.get().substitutions()); Optional secondArg = inferencer.unify(SimpleType.DOUBLE, equalsArgFresh); - Truth8.assertThat(secondArg).isPresent(); - Truth8.assertThat(secondArg.get().unifiedType()).hasValue(JsonType.JSON); + assertThat(secondArg).isPresent(); + assertThat(secondArg.get().unifiedType()).hasValue(JsonType.JSON); inferencer.recordSubstitutions(secondArg.get().substitutions()); assertThat(inferencer.specialize(equalsArgFresh)).isEqualTo(JsonType.JSON); } @@ -118,12 +117,12 @@ public void unify_success_jsonEqualsDoubleOneByOneDifferentInferencer() { TypeParamType equalsArg = TypeParamType.create("T"); CelType equalsArgFresh = equalsArg.withFreshTypeParamVariables(typeVarGenerator); Optional firstArg = inferencer.unify(JsonType.JSON, equalsArgFresh); - Truth8.assertThat(firstArg).isPresent(); - Truth8.assertThat(firstArg.get().unifiedType()).hasValue(JsonType.JSON); + assertThat(firstArg).isPresent(); + assertThat(firstArg.get().unifiedType()).hasValue(JsonType.JSON); TypeInferencer inferencer2 = new TypeInferencer(UNION_TYPES, firstArg.get().substitutions()); Optional secondArg = inferencer2.unify(SimpleType.DOUBLE, equalsArgFresh); - Truth8.assertThat(secondArg).isPresent(); - Truth8.assertThat(secondArg.get().unifiedType()).hasValue(JsonType.JSON); + assertThat(secondArg).isPresent(); + assertThat(secondArg.get().unifiedType()).hasValue(JsonType.JSON); inferencer2.recordSubstitutions(secondArg.get().substitutions()); assertThat(inferencer2.specialize(equalsArgFresh)).isEqualTo(JsonType.JSON); } @@ -131,15 +130,15 @@ public void unify_success_jsonEqualsDoubleOneByOneDifferentInferencer() { @Test public void unify_success_jsonToDouble() { Optional result = inferencer.unify(JsonType.JSON, SimpleType.DOUBLE); - Truth8.assertThat(result).isPresent(); - Truth8.assertThat(result.get().unifiedType()).hasValue(JsonType.JSON); + assertThat(result).isPresent(); + assertThat(result.get().unifiedType()).hasValue(JsonType.JSON); } @Test public void unify_success_doubleToJson() { Optional result = inferencer.unify(SimpleType.DOUBLE, JsonType.JSON); - Truth8.assertThat(result).isPresent(); - Truth8.assertThat(result.get().unifiedType()).hasValue(JsonType.JSON); + assertThat(result).isPresent(); + assertThat(result.get().unifiedType()).hasValue(JsonType.JSON); } @Test @@ -147,14 +146,14 @@ public void unify_false_nestedTypeParamReference() { TypeParamType typeParamArg = TypeParamType.create("T"); ListType listType = ListType.create(typeParamArg); Optional result = inferencer.unify(typeParamArg, listType); - Truth8.assertThat(result).isEmpty(); + assertThat(result).isEmpty(); } @Test public void unify_success_dynOrErrorYieldsError() { Optional result = inferencer.unify(SimpleType.DYN, SimpleType.ERROR); - Truth8.assertThat(result).isPresent(); - Truth8.assertThat(result.get().unifiedType()).hasValue(SimpleType.ERROR); + assertThat(result).isPresent(); + assertThat(result.get().unifiedType()).hasValue(SimpleType.ERROR); } @Test @@ -162,8 +161,8 @@ public void unify_success_doubleNullToNullableDoubleWithTypeParam() { CelType outputType = TypeParamType.create("O").withFreshTypeParamVariables(typeVarGenerator); Optional result = inferencer.unify(ImmutableList.of(SimpleType.DOUBLE, SimpleType.NULL_TYPE), outputType); - Truth8.assertThat(result).isPresent(); - Truth8.assertThat(result.get().unifiedType()).hasValue(NullableType.create(SimpleType.DOUBLE)); + assertThat(result).isPresent(); + assertThat(result.get().unifiedType()).hasValue(NullableType.create(SimpleType.DOUBLE)); } @Test @@ -171,8 +170,8 @@ public void unify_success_doubleNullToNullableDoubleWithConcreteType() { CelType outputType = NullableType.create(SimpleType.DOUBLE); Optional result = inferencer.unify(ImmutableList.of(SimpleType.DOUBLE, SimpleType.NULL_TYPE), outputType); - Truth8.assertThat(result).isPresent(); - Truth8.assertThat(result.get().unifiedType()).hasValue(outputType); + assertThat(result).isPresent(); + assertThat(result.get().unifiedType()).hasValue(outputType); } @Test @@ -182,8 +181,8 @@ public void unify_success_doubleNullStringToJson() { inferencer.unify( ImmutableList.of(SimpleType.DOUBLE, SimpleType.NULL_TYPE, SimpleType.STRING), outputType); - Truth8.assertThat(result).isPresent(); - Truth8.assertThat(result.get().unifiedType()).hasValue(JsonType.JSON); + assertThat(result).isPresent(); + assertThat(result.get().unifiedType()).hasValue(JsonType.JSON); } @Test @@ -194,8 +193,8 @@ public void unify_success_doubleNullStringToDyn() { inferencer.unify( ImmutableList.of(SimpleType.DOUBLE, SimpleType.NULL_TYPE, SimpleType.STRING), outputType); - Truth8.assertThat(result).isPresent(); - Truth8.assertThat(result.get().unifiedType()).hasValue(SimpleType.DYN); + assertThat(result).isPresent(); + assertThat(result.get().unifiedType()).hasValue(SimpleType.DYN); } @Test @@ -206,7 +205,7 @@ public void unify_false_doubleNullStringNoJsonNoTopType() { inferencer.unify( ImmutableList.of(SimpleType.DOUBLE, SimpleType.NULL_TYPE, SimpleType.STRING), outputType); - Truth8.assertThat(result).isEmpty(); + assertThat(result).isEmpty(); } @Test @@ -216,8 +215,8 @@ public void unify_success_abstractTypeListToJsonParam() { CelType outputType = TypeParamType.create("O").withFreshTypeParamVariables(typeVarGenerator); Optional result = inferencer.unify(ImmutableList.of(setListDouble, setString), outputType); - Truth8.assertThat(result).isPresent(); - Truth8.assertThat(result.get().unifiedType()).hasValue(OpaqueType.create("set", JsonType.JSON)); + assertThat(result).isPresent(); + assertThat(result.get().unifiedType()).hasValue(OpaqueType.create("set", JsonType.JSON)); } @Test @@ -229,8 +228,8 @@ public void unify_success_abstractTypeMapToMapJsonParam() { CelType outputType = TypeParamType.create("O").withFreshTypeParamVariables(typeVarGenerator); Optional result = inferencer.unify(ImmutableList.of(setListDouble, setString), outputType); - Truth8.assertThat(result).isPresent(); - Truth8.assertThat(result.get().unifiedType()) + assertThat(result).isPresent(); + assertThat(result.get().unifiedType()) .hasValue(OpaqueType.create("set", MapType.create(SimpleType.STRING, JsonType.JSON))); } @@ -242,8 +241,8 @@ public void unify_success_abstractTypeMapToJsonParam() { CelType outputType = TypeParamType.create("0").withFreshTypeParamVariables(typeVarGenerator); Optional result = inferencer.unify(ImmutableList.of(setListDouble, setString), outputType); - Truth8.assertThat(result).isPresent(); - Truth8.assertThat(result.get().unifiedType()).hasValue(OpaqueType.create("set", JsonType.JSON)); + assertThat(result).isPresent(); + assertThat(result.get().unifiedType()).hasValue(OpaqueType.create("set", JsonType.JSON)); } @Test @@ -258,9 +257,8 @@ public void unify_success_opaqueTypeMapToDynParam() { // to enter into the type resolution. Optional result = inferencer.unify(ImmutableList.of(setListDouble, setString), outputType); - Truth8.assertThat(result).isPresent(); - Truth8.assertThat(result.get().unifiedType()) - .hasValue(OpaqueType.create("set", SimpleType.DYN)); + assertThat(result).isPresent(); + assertThat(result.get().unifiedType()).hasValue(OpaqueType.create("set", SimpleType.DYN)); } @Test @@ -270,9 +268,8 @@ public void unify_success_jsonIntSetsToDynSet() { CelType outputType = TypeParamType.create("O").withFreshTypeParamVariables(typeVarGenerator); Optional result = inferencer.unify(ImmutableList.of(setJson, setInt), outputType); - Truth8.assertThat(result).isPresent(); - Truth8.assertThat(result.get().unifiedType()) - .hasValue(OpaqueType.create("set", SimpleType.DYN)); + assertThat(result).isPresent(); + assertThat(result.get().unifiedType()).hasValue(OpaqueType.create("set", SimpleType.DYN)); } @Test @@ -283,35 +280,35 @@ public void unify_success_nullableStruct() { CelType outputType = TypeParamType.create("O").withFreshTypeParamVariables(typeVarGenerator); Optional result = inferencer.unify(ImmutableList.of(nullableStructType, structType), outputType); - Truth8.assertThat(result).isPresent(); - Truth8.assertThat(result.get().unifiedType()).hasValue(nullableStructType); + assertThat(result).isPresent(); + assertThat(result.get().unifiedType()).hasValue(nullableStructType); } @Test public void unify_false_differentKinds() { OpaqueType vectorType = OpaqueType.create("vector", SimpleType.STRING); - Truth8.assertThat(inferencer.unify(JsonType.JSON, vectorType)).isEmpty(); + assertThat(inferencer.unify(JsonType.JSON, vectorType)).isEmpty(); } @Test public void unify_false_sameKindDifferentTypeName() { OpaqueType setType = OpaqueType.create("set", SimpleType.STRING); OpaqueType vectorType = OpaqueType.create("vector", SimpleType.STRING); - Truth8.assertThat(inferencer.unify(setType, vectorType)).isEmpty(); + assertThat(inferencer.unify(setType, vectorType)).isEmpty(); } @Test public void unify_false_sameTypeDifferentParameterTypes() { OpaqueType setType = OpaqueType.create("set", SimpleType.INT); OpaqueType vectorType = OpaqueType.create("set", SimpleType.STRING); - Truth8.assertThat(inferencer.unify(setType, vectorType)).isEmpty(); + assertThat(inferencer.unify(setType, vectorType)).isEmpty(); } @Test public void unify_false_sameTypeDifferentParameterCounts() { OpaqueType setType = OpaqueType.create("set", SimpleType.INT); OpaqueType vectorType = OpaqueType.create("set", SimpleType.INT, SimpleType.INT); - Truth8.assertThat(inferencer.unify(setType, vectorType)).isEmpty(); + assertThat(inferencer.unify(setType, vectorType)).isEmpty(); } @Test @@ -323,7 +320,7 @@ public void isAssignable_success_jsonSelect() { inferencer.isAssignable( ImmutableList.of(mapInst, SimpleType.STRING), ImmutableList.of(mapParamFresh, mapParamFresh.keyType())); - Truth8.assertThat(result).isPresent(); + assertThat(result).isPresent(); assertThat(result.get()) .containsExactly( mapParamFresh.keyType().name(), @@ -342,7 +339,7 @@ public void isAssignable_success_jsonEqualsDoubleAsList() { inferencer.isAssignable( ImmutableList.of(JsonType.JSON, SimpleType.DOUBLE), ImmutableList.of(equalsArgFresh, equalsArgFresh)); - Truth8.assertThat(result).isPresent(); + assertThat(result).isPresent(); inferencer.recordSubstitutions(result.get()); assertThat(inferencer.specialize(equalsArgFresh)).isEqualTo(JsonType.JSON); } @@ -355,7 +352,7 @@ public void isAssignable_success_doubleEqualsJsonAsList() { inferencer.isAssignable( ImmutableList.of(SimpleType.DOUBLE, JsonType.JSON), ImmutableList.of(equalsArgFresh, equalsArgFresh)); - Truth8.assertThat(result).isPresent(); + assertThat(result).isPresent(); inferencer.recordSubstitutions(result.get()); assertThat(inferencer.specialize(equalsArgFresh)).isEqualTo(JsonType.JSON); } @@ -368,7 +365,7 @@ public void isAssignable_false_doubleEqualsString() { inferencer.isAssignable( ImmutableList.of(SimpleType.DOUBLE, SimpleType.STRING), ImmutableList.of(equalsArgFresh, equalsArgFresh)); - Truth8.assertThat(result).isEmpty(); + assertThat(result).isEmpty(); } @Test @@ -377,7 +374,7 @@ public void isAssignable_false_sameTypeDifferentParameterCounts() { OpaqueType setType2 = OpaqueType.create("set", SimpleType.STRING, SimpleType.INT); Optional> result = inferencer.isAssignable(setType.parameters(), setType2.parameters()); - Truth8.assertThat(result).isEmpty(); + assertThat(result).isEmpty(); } @Test @@ -389,8 +386,8 @@ public void finalize_success_typeFinalize() { CelType typeOfTypeWithFreshVars = typeOfType.withFreshTypeParamVariables(typeVarGenerator); Optional result = inferencer.unify(typeOfStructType, typeOfTypeWithFreshVars); - Truth8.assertThat(result).isPresent(); - Truth8.assertThat(result.get().unifiedType()).hasValue(typeOfStructType); + assertThat(result).isPresent(); + assertThat(result.get().unifiedType()).hasValue(typeOfStructType); inferencer.recordSubstitutions(result.get().substitutions()); assertThat(inferencer.finalize(typeOfTypeWithFreshVars, SimpleType.DYN)) .isEqualTo(typeOfStructType); diff --git a/common/src/test/java/dev/cel/common/CelAbstractSyntaxTreeTest.java b/common/src/test/java/dev/cel/common/CelAbstractSyntaxTreeTest.java index 960ba6642..78c16c165 100644 --- a/common/src/test/java/dev/cel/common/CelAbstractSyntaxTreeTest.java +++ b/common/src/test/java/dev/cel/common/CelAbstractSyntaxTreeTest.java @@ -26,7 +26,6 @@ import dev.cel.expr.SourceInfo; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; -import com.google.common.truth.Truth8; import dev.cel.common.ast.CelConstant; import dev.cel.common.ast.CelExpr; import dev.cel.common.types.CelTypes; @@ -107,9 +106,9 @@ public void getResultType_isStaticWhenCheckedExpr() { @Test public void findEnumValue_findsConstantInCheckedExpr() { CelAbstractSyntaxTree ast = CHECKED_ENUM_AST; - Truth8.assertThat(ast.findEnumValue(1)).isEmpty(); - Truth8.assertThat(ast.findEnumValue(2)).hasValue(CelConstant.ofValue(2)); - Truth8.assertThat(ast.findEnumValue(3)).isEmpty(); + assertThat(ast.findEnumValue(1)).isEmpty(); + assertThat(ast.findEnumValue(2)).hasValue(CelConstant.ofValue(2)); + assertThat(ast.findEnumValue(3)).isEmpty(); } @Test @@ -118,17 +117,17 @@ public void findEnumValue_doesNotFindConstantInParsedExpr() { CelAbstractSyntaxTree.newParsedAst( CHECKED_ENUM_AST.getExpr(), CHECKED_ENUM_AST.getSource()); - Truth8.assertThat(ast.findEnumValue(1)).isEmpty(); - Truth8.assertThat(ast.findEnumValue(2)).isEmpty(); - Truth8.assertThat(ast.findEnumValue(3)).isEmpty(); + assertThat(ast.findEnumValue(1)).isEmpty(); + assertThat(ast.findEnumValue(2)).isEmpty(); + assertThat(ast.findEnumValue(3)).isEmpty(); } @Test public void findOverloadIDs_findsOverloadsInCheckedExpr() { CelAbstractSyntaxTree ast = CHECKED_ENUM_AST; - Truth8.assertThat(ast.findOverloadIDs(1)).isEmpty(); - Truth8.assertThat(ast.findOverloadIDs(2)).isEmpty(); - Truth8.assertThat(ast.findOverloadIDs(3)).hasValue(ImmutableList.of("not_equals")); + assertThat(ast.findOverloadIDs(1)).isEmpty(); + assertThat(ast.findOverloadIDs(2)).isEmpty(); + assertThat(ast.findOverloadIDs(3)).hasValue(ImmutableList.of("not_equals")); } @Test @@ -137,9 +136,9 @@ public void findOverloadIDs_doesNotFindsOverloadsInParsedExpr() { CelAbstractSyntaxTree.newParsedAst( CHECKED_ENUM_AST.getExpr(), CHECKED_ENUM_AST.getSource()); - Truth8.assertThat(ast.findOverloadIDs(1)).isEmpty(); - Truth8.assertThat(ast.findOverloadIDs(2)).isEmpty(); - Truth8.assertThat(ast.findOverloadIDs(3)).isEmpty(); + assertThat(ast.findOverloadIDs(1)).isEmpty(); + assertThat(ast.findOverloadIDs(2)).isEmpty(); + assertThat(ast.findOverloadIDs(3)).isEmpty(); } @Test diff --git a/common/src/test/java/dev/cel/common/CelSourceTest.java b/common/src/test/java/dev/cel/common/CelSourceTest.java index e77db1da6..74e350a35 100644 --- a/common/src/test/java/dev/cel/common/CelSourceTest.java +++ b/common/src/test/java/dev/cel/common/CelSourceTest.java @@ -18,7 +18,6 @@ import static org.antlr.v4.runtime.IntStream.UNKNOWN_SOURCE_NAME; import static org.junit.Assert.assertThrows; -import com.google.common.truth.Truth8; import dev.cel.common.CelSource.Extension; import dev.cel.common.CelSource.Extension.Component; import dev.cel.common.CelSource.Extension.Version; @@ -47,13 +46,13 @@ public final class CelSourceTest { @Test public void getLocationOffset_correctStartingLocation() throws Exception { CelSource source = CelSource.newBuilder(LATIN_1_EXPR).build(); - Truth8.assertThat(source.getLocationOffset(CelSourceLocation.of(1, 0))).hasValue(0); + assertThat(source.getLocationOffset(CelSourceLocation.of(1, 0))).hasValue(0); } @Test public void getOffsetLocation_correctStartingLocation() throws Exception { CelSource source = CelSource.newBuilder(LATIN_1_EXPR).build(); - Truth8.assertThat(source.getOffsetLocation(0)).hasValue(CelSourceLocation.of(1, 0)); + assertThat(source.getOffsetLocation(0)).hasValue(CelSourceLocation.of(1, 0)); } @Test diff --git a/common/src/test/java/dev/cel/common/ast/CelExprVisitorTest.java b/common/src/test/java/dev/cel/common/ast/CelExprVisitorTest.java index 5443266bf..1926eb31e 100644 --- a/common/src/test/java/dev/cel/common/ast/CelExprVisitorTest.java +++ b/common/src/test/java/dev/cel/common/ast/CelExprVisitorTest.java @@ -19,7 +19,6 @@ import com.google.auto.value.AutoValue; import com.google.common.collect.ImmutableList; -import com.google.common.truth.Truth8; import dev.cel.common.CelAbstractSyntaxTree; import dev.cel.common.ast.CelExpr.CelCall; import dev.cel.common.ast.CelExpr.CelComprehension; @@ -346,7 +345,7 @@ public void visitComprehension() throws Exception { .isEqualTo(Operator.LOGICAL_AND.getFunction()); assertThat(comprehension.loopStep().call().args()).hasSize(2); assertThat(visitedReference.createList().get().elements()).isEqualTo(iterRangeElements); - Truth8.assertThat(visitedReference.identifier()) + assertThat(visitedReference.identifier()) .hasValue(CelIdent.newBuilder().setName("__result__").build()); assertThat(visitedReference.arguments()).hasSize(10); } diff --git a/common/src/test/java/dev/cel/common/ast/CelReferenceTest.java b/common/src/test/java/dev/cel/common/ast/CelReferenceTest.java index 79395c55a..dbe6613be 100644 --- a/common/src/test/java/dev/cel/common/ast/CelReferenceTest.java +++ b/common/src/test/java/dev/cel/common/ast/CelReferenceTest.java @@ -18,7 +18,6 @@ import static org.junit.Assert.assertThrows; import com.google.common.collect.ImmutableList; -import com.google.common.truth.Truth8; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -32,7 +31,7 @@ public void constructCelReference_withEmptyArguments() { assertThat(reference.name()).isEqualTo("refName"); assertThat(reference.overloadIds()).isEmpty(); - Truth8.assertThat(reference.value()).isEmpty(); + assertThat(reference.value()).isEmpty(); } @Test @@ -42,7 +41,7 @@ public void constructCelReference_withOverloadIds() { assertThat(reference.name()).isEqualTo("refName"); assertThat(reference.overloadIds()).containsExactly("a", "b", "c"); - Truth8.assertThat(reference.value()).isEmpty(); + assertThat(reference.value()).isEmpty(); } @Test @@ -52,7 +51,7 @@ public void constructCelReference_withValue() { assertThat(reference.name()).isEqualTo("refName"); assertThat(reference.overloadIds()).isEmpty(); - Truth8.assertThat(reference.value()).hasValue(CelConstant.ofValue(10)); + assertThat(reference.value()).hasValue(CelConstant.ofValue(10)); } @Test diff --git a/common/src/test/java/dev/cel/common/internal/CombinedDescriptorPoolTest.java b/common/src/test/java/dev/cel/common/internal/CombinedDescriptorPoolTest.java index d232ac246..a56bb2ed5 100644 --- a/common/src/test/java/dev/cel/common/internal/CombinedDescriptorPoolTest.java +++ b/common/src/test/java/dev/cel/common/internal/CombinedDescriptorPoolTest.java @@ -17,7 +17,6 @@ import static com.google.common.truth.Truth.assertThat; import com.google.common.collect.ImmutableList; -import com.google.common.truth.Truth8; import com.google.protobuf.Descriptors.FieldDescriptor; import com.google.protobuf.ExtensionRegistry; import com.google.protobuf.Value; @@ -43,11 +42,10 @@ public void findDescriptor_descriptorReturnedFromBothPool() { CombinedDescriptorPool.create( ImmutableList.of(DefaultDescriptorPool.INSTANCE, dynamicDescriptorPool)); - Truth8.assertThat(combinedDescriptorPool.findDescriptor(Value.getDescriptor().getFullName())) + assertThat(combinedDescriptorPool.findDescriptor(Value.getDescriptor().getFullName())) .hasValue( Value.getDescriptor()); // Retrieved from default descriptor pool (well-known-type) - Truth8.assertThat( - combinedDescriptorPool.findDescriptor(TestAllTypes.getDescriptor().getFullName())) + assertThat(combinedDescriptorPool.findDescriptor(TestAllTypes.getDescriptor().getFullName())) .hasValue(TestAllTypes.getDescriptor()); // Retrieved from the dynamic descriptor pool. } @@ -61,7 +59,7 @@ public void findDescriptor_returnsEmpty() { CombinedDescriptorPool.create( ImmutableList.of(DefaultDescriptorPool.INSTANCE, descriptorPool)); - Truth8.assertThat(combinedDescriptorPool.findDescriptor("bogus")).isEmpty(); + assertThat(combinedDescriptorPool.findDescriptor("bogus")).isEmpty(); } @Test @@ -78,7 +76,7 @@ public void findExtensionDescriptor_success() { combinedDescriptorPool.findExtensionDescriptor( Proto2Message.getDescriptor(), "dev.cel.testing.testdata.proto2.test_all_types_ext"); - Truth8.assertThat(fieldDescriptor).isPresent(); + assertThat(fieldDescriptor).isPresent(); assertThat(fieldDescriptor.get().isExtension()).isTrue(); assertThat(fieldDescriptor.get().getFullName()) .isEqualTo("dev.cel.testing.testdata.proto2.test_all_types_ext"); @@ -94,7 +92,7 @@ public void findExtensionDescriptor_returnsEmpty() { CombinedDescriptorPool.create( ImmutableList.of(DefaultDescriptorPool.INSTANCE, dynamicDescriptorPool)); - Truth8.assertThat( + assertThat( combinedDescriptorPool.findExtensionDescriptor(TestAllTypes.getDescriptor(), "bogus")) .isEmpty(); } diff --git a/common/src/test/java/dev/cel/common/internal/DefaultInstanceMessageFactoryTest.java b/common/src/test/java/dev/cel/common/internal/DefaultInstanceMessageFactoryTest.java index 0f24aafd0..a167190f9 100644 --- a/common/src/test/java/dev/cel/common/internal/DefaultInstanceMessageFactoryTest.java +++ b/common/src/test/java/dev/cel/common/internal/DefaultInstanceMessageFactoryTest.java @@ -19,7 +19,6 @@ import static java.util.Arrays.stream; import com.google.common.collect.ImmutableList; -import com.google.common.truth.Truth8; import com.google.common.util.concurrent.MoreExecutors; import com.google.protobuf.Descriptors.Descriptor; import com.google.protobuf.Message; @@ -95,7 +94,7 @@ public void getPrototype_success(@TestParameter PrototypeDescriptorTestCase test Optional defaultMessage = DefaultInstanceMessageFactory.getInstance().getPrototype(descriptor); - Truth8.assertThat(defaultMessage).hasValue(testCase.defaultInstance); + assertThat(defaultMessage).hasValue(testCase.defaultInstance); } @Test @@ -107,8 +106,8 @@ public void getPrototype_cached_success(@TestParameter PrototypeDescriptorTestCa Optional defaultMessage2 = DefaultInstanceMessageFactory.getInstance().getPrototype(descriptor); - Truth8.assertThat(defaultMessage).hasValue(testCase.defaultInstance); - Truth8.assertThat(defaultMessage2).hasValue(testCase.defaultInstance); + assertThat(defaultMessage).hasValue(testCase.defaultInstance); + assertThat(defaultMessage2).hasValue(testCase.defaultInstance); } @Test diff --git a/common/src/test/java/dev/cel/common/internal/DefaultMessageFactoryTest.java b/common/src/test/java/dev/cel/common/internal/DefaultMessageFactoryTest.java index 8d75652ee..aef6140bf 100644 --- a/common/src/test/java/dev/cel/common/internal/DefaultMessageFactoryTest.java +++ b/common/src/test/java/dev/cel/common/internal/DefaultMessageFactoryTest.java @@ -21,7 +21,6 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.io.Resources; -import com.google.common.truth.Truth8; import com.google.protobuf.DescriptorProtos.FileDescriptorSet; import com.google.protobuf.Descriptors.FileDescriptor; import com.google.protobuf.DynamicMessage; @@ -70,7 +69,7 @@ public void newBuilder_withDescriptor_producesNewMessageBuilder() { public void newBuilder_unknownMessage_returnsEmpty() { DefaultMessageFactory messageFactory = DefaultMessageFactory.INSTANCE; - Truth8.assertThat(messageFactory.newBuilder("unknown_message")).isEmpty(); + assertThat(messageFactory.newBuilder("unknown_message")).isEmpty(); } @Test @@ -85,7 +84,7 @@ public void newBuilder_unequalDescriptorForSameMessage_returnsDynamicMessage() t DefaultMessageFactory messageFactory = DefaultMessageFactory.create(DefaultDescriptorPool.create(celDescriptors)); - Truth8.assertThat(messageFactory.newBuilder("google.api.expr.Value")).isPresent(); + assertThat(messageFactory.newBuilder("google.api.expr.Value")).isPresent(); assertThat(messageFactory.newBuilder("google.api.expr.Value").get()) .isInstanceOf(DynamicMessage.Builder.class); } @@ -114,6 +113,6 @@ public void combinedMessageFactoryTest() { assertThat(messageFactory.newBuilder("test").get().build()) .isEqualTo(TestAllTypes.getDefaultInstance()); - Truth8.assertThat(messageFactory.newBuilder("bogus")).isEmpty(); + assertThat(messageFactory.newBuilder("bogus")).isEmpty(); } } diff --git a/common/src/test/java/dev/cel/common/internal/ErrorsTest.java b/common/src/test/java/dev/cel/common/internal/ErrorsTest.java index 0bdfed17c..ad46f7737 100644 --- a/common/src/test/java/dev/cel/common/internal/ErrorsTest.java +++ b/common/src/test/java/dev/cel/common/internal/ErrorsTest.java @@ -16,7 +16,6 @@ import static com.google.common.truth.Truth.assertThat; -import com.google.common.truth.Truth8; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -61,9 +60,9 @@ public void getPositionLocation() { @Test public void getSnippet() { Errors errors = new Errors("test", "hello\nworld\n"); - Truth8.assertThat(errors.getSnippet(1)).hasValue("hello"); - Truth8.assertThat(errors.getSnippet(2)).hasValue("world"); - Truth8.assertThat(errors.getSnippet(3)).hasValue(""); - Truth8.assertThat(errors.getSnippet(4)).isEmpty(); + assertThat(errors.getSnippet(1)).hasValue("hello"); + assertThat(errors.getSnippet(2)).hasValue("world"); + assertThat(errors.getSnippet(3)).hasValue(""); + assertThat(errors.getSnippet(4)).isEmpty(); } } diff --git a/common/src/test/java/dev/cel/common/internal/ProtoAdapterTest.java b/common/src/test/java/dev/cel/common/internal/ProtoAdapterTest.java index 118bd393d..151f79f49 100644 --- a/common/src/test/java/dev/cel/common/internal/ProtoAdapterTest.java +++ b/common/src/test/java/dev/cel/common/internal/ProtoAdapterTest.java @@ -19,7 +19,6 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.primitives.UnsignedLong; -import com.google.common.truth.Truth8; import com.google.protobuf.Any; import com.google.protobuf.BoolValue; import com.google.protobuf.ByteString; @@ -162,8 +161,7 @@ public static List data() { public void adaptValueToProto_bidirectionalConversion() { DynamicProto dynamicProto = DynamicProto.create(DefaultMessageFactory.INSTANCE); ProtoAdapter protoAdapter = new ProtoAdapter(dynamicProto, options.enableUnsignedLongs()); - Truth8.assertThat( - protoAdapter.adaptValueToProto(value, proto.getDescriptorForType().getFullName())) + assertThat(protoAdapter.adaptValueToProto(value, proto.getDescriptorForType().getFullName())) .hasValue(proto); assertThat(protoAdapter.adaptProtoToValue(proto)).isEqualTo(value); } @@ -182,7 +180,7 @@ public void adaptAnyValue_hermeticTypes_bidirectionalConversion() { ? Optional.of(Expr.newBuilder()) : Optional.empty()), LEGACY.enableUnsignedLongs()); - Truth8.assertThat(protoAdapter.adaptValueToProto(expr, Any.getDescriptor().getFullName())) + assertThat(protoAdapter.adaptValueToProto(expr, Any.getDescriptor().getFullName())) .hasValue(Any.pack(expr)); assertThat(protoAdapter.adaptProtoToValue(Any.pack(expr))).isEqualTo(expr); } @@ -193,7 +191,7 @@ public static class AsymmetricConversionTest { @Test public void adaptValueToProto_asymmetricNullConversion() { ProtoAdapter protoAdapter = new ProtoAdapter(DYNAMIC_PROTO, LEGACY.enableUnsignedLongs()); - Truth8.assertThat(protoAdapter.adaptValueToProto(null, Any.getDescriptor().getFullName())) + assertThat(protoAdapter.adaptValueToProto(null, Any.getDescriptor().getFullName())) .hasValue(Any.pack(Value.newBuilder().setNullValue(NullValue.NULL_VALUE).build())); assertThat( protoAdapter.adaptProtoToValue( @@ -204,7 +202,7 @@ public void adaptValueToProto_asymmetricNullConversion() { @Test public void adaptValueToProto_asymmetricFloatConversion() { ProtoAdapter protoAdapter = new ProtoAdapter(DYNAMIC_PROTO, LEGACY.enableUnsignedLongs()); - Truth8.assertThat(protoAdapter.adaptValueToProto(1.5F, Any.getDescriptor().getFullName())) + assertThat(protoAdapter.adaptValueToProto(1.5F, Any.getDescriptor().getFullName())) .hasValue(Any.pack(FloatValue.of(1.5F))); assertThat(protoAdapter.adaptProtoToValue(Any.pack(FloatValue.of(1.5F)))).isEqualTo(1.5D); } @@ -212,8 +210,7 @@ public void adaptValueToProto_asymmetricFloatConversion() { @Test public void adaptValueToProto_asymmetricDoubleFloatConversion() { ProtoAdapter protoAdapter = new ProtoAdapter(DYNAMIC_PROTO, LEGACY.enableUnsignedLongs()); - Truth8.assertThat( - protoAdapter.adaptValueToProto(1.5D, FloatValue.getDescriptor().getFullName())) + assertThat(protoAdapter.adaptValueToProto(1.5D, FloatValue.getDescriptor().getFullName())) .hasValue(FloatValue.of(1.5F)); assertThat(protoAdapter.adaptProtoToValue(FloatValue.of(1.5F))).isEqualTo(1.5D); } @@ -221,28 +218,27 @@ public void adaptValueToProto_asymmetricDoubleFloatConversion() { @Test public void adaptValueToProto_asymmetricFloatDoubleConversion() { ProtoAdapter protoAdapter = new ProtoAdapter(DYNAMIC_PROTO, LEGACY.enableUnsignedLongs()); - Truth8.assertThat( - protoAdapter.adaptValueToProto(1.5F, DoubleValue.getDescriptor().getFullName())) + assertThat(protoAdapter.adaptValueToProto(1.5F, DoubleValue.getDescriptor().getFullName())) .hasValue(DoubleValue.of(1.5D)); } @Test public void adaptValueToProto_asymmetricJsonConversion() { ProtoAdapter protoAdapter = new ProtoAdapter(DYNAMIC_PROTO, CURRENT.enableUnsignedLongs()); - Truth8.assertThat( + assertThat( protoAdapter.adaptValueToProto( UnsignedLong.valueOf(1L), Value.getDescriptor().getFullName())) .hasValue(Value.newBuilder().setNumberValue(1).build()); - Truth8.assertThat( + assertThat( protoAdapter.adaptValueToProto( UnsignedLong.fromLongBits(-1L), Value.getDescriptor().getFullName())) .hasValue(Value.newBuilder().setStringValue(Long.toUnsignedString(-1L)).build()); - Truth8.assertThat(protoAdapter.adaptValueToProto(1L, Value.getDescriptor().getFullName())) + assertThat(protoAdapter.adaptValueToProto(1L, Value.getDescriptor().getFullName())) .hasValue(Value.newBuilder().setNumberValue(1).build()); - Truth8.assertThat( + assertThat( protoAdapter.adaptValueToProto(Long.MAX_VALUE, Value.getDescriptor().getFullName())) .hasValue(Value.newBuilder().setStringValue(Long.toString(Long.MAX_VALUE)).build()); - Truth8.assertThat( + assertThat( protoAdapter.adaptValueToProto( ByteString.copyFromUtf8("foo"), Value.getDescriptor().getFullName())) .hasValue(Value.newBuilder().setStringValue("Zm9v").build()); @@ -251,7 +247,7 @@ public void adaptValueToProto_asymmetricJsonConversion() { @Test public void adaptValueToProto_unsupportedJsonConversion() { ProtoAdapter protoAdapter = new ProtoAdapter(DYNAMIC_PROTO, LEGACY.enableUnsignedLongs()); - Truth8.assertThat( + assertThat( protoAdapter.adaptValueToProto( ImmutableMap.of(1, 1), Any.getDescriptor().getFullName())) .isEmpty(); @@ -260,7 +256,7 @@ public void adaptValueToProto_unsupportedJsonConversion() { @Test public void adaptValueToProto_unsupportedJsonListConversion() { ProtoAdapter protoAdapter = new ProtoAdapter(DYNAMIC_PROTO, LEGACY.enableUnsignedLongs()); - Truth8.assertThat( + assertThat( protoAdapter.adaptValueToProto( ImmutableMap.of(1, 1), ListValue.getDescriptor().getFullName())) .isEmpty(); @@ -269,7 +265,7 @@ public void adaptValueToProto_unsupportedJsonListConversion() { @Test public void adaptValueToProto_unsupportedConversion() { ProtoAdapter protoAdapter = new ProtoAdapter(DYNAMIC_PROTO, LEGACY.enableUnsignedLongs()); - Truth8.assertThat(protoAdapter.adaptValueToProto("Hello", Expr.getDescriptor().getFullName())) + assertThat(protoAdapter.adaptValueToProto("Hello", Expr.getDescriptor().getFullName())) .isEmpty(); } diff --git a/common/src/test/java/dev/cel/common/navigation/CelNavigableAstTest.java b/common/src/test/java/dev/cel/common/navigation/CelNavigableAstTest.java index 2c595f0d1..40f772810 100644 --- a/common/src/test/java/dev/cel/common/navigation/CelNavigableAstTest.java +++ b/common/src/test/java/dev/cel/common/navigation/CelNavigableAstTest.java @@ -16,7 +16,6 @@ import static com.google.common.truth.Truth.assertThat; -import com.google.common.truth.Truth8; import dev.cel.common.CelAbstractSyntaxTree; import dev.cel.common.ast.CelConstant; import dev.cel.common.ast.CelExpr; @@ -39,7 +38,7 @@ public void construct_success() throws Exception { assertThat(navigableAst.getAst()).isEqualTo(ast); assertThat(navigableAst.getRoot().expr()) .isEqualTo(CelExpr.ofConstantExpr(1, CelConstant.ofValue("Hello World"))); - Truth8.assertThat(navigableAst.getRoot().parent()).isEmpty(); + assertThat(navigableAst.getRoot().parent()).isEmpty(); assertThat(navigableAst.getRoot().depth()).isEqualTo(0); } } diff --git a/common/src/test/java/dev/cel/common/navigation/CelNavigableExprTest.java b/common/src/test/java/dev/cel/common/navigation/CelNavigableExprTest.java index b76da7a21..261524df0 100644 --- a/common/src/test/java/dev/cel/common/navigation/CelNavigableExprTest.java +++ b/common/src/test/java/dev/cel/common/navigation/CelNavigableExprTest.java @@ -16,7 +16,6 @@ import static com.google.common.truth.Truth.assertThat; -import com.google.common.truth.Truth8; import dev.cel.common.ast.CelConstant; import dev.cel.common.ast.CelExpr; import org.junit.Test; @@ -34,7 +33,7 @@ public void construct_withoutParent_success() { assertThat(navigableExpr.expr()).isEqualTo(constExpr); assertThat(navigableExpr.depth()).isEqualTo(2); - Truth8.assertThat(navigableExpr.parent()).isEmpty(); + assertThat(navigableExpr.parent()).isEmpty(); } @Test @@ -47,9 +46,9 @@ public void construct_withParent_success() { assertThat(parentExpr.expr()).isEqualTo(identExpr); assertThat(parentExpr.depth()).isEqualTo(1); - Truth8.assertThat(parentExpr.parent()).isEmpty(); + assertThat(parentExpr.parent()).isEmpty(); assertThat(navigableExpr.expr()).isEqualTo(constExpr); assertThat(navigableExpr.depth()).isEqualTo(2); - Truth8.assertThat(navigableExpr.parent()).hasValue(parentExpr); + assertThat(navigableExpr.parent()).hasValue(parentExpr); } } diff --git a/common/src/test/java/dev/cel/common/navigation/CelNavigableExprVisitorTest.java b/common/src/test/java/dev/cel/common/navigation/CelNavigableExprVisitorTest.java index 9aeefa6a4..f3739ca53 100644 --- a/common/src/test/java/dev/cel/common/navigation/CelNavigableExprVisitorTest.java +++ b/common/src/test/java/dev/cel/common/navigation/CelNavigableExprVisitorTest.java @@ -22,7 +22,6 @@ import com.google.common.collect.ImmutableList; import com.google.common.primitives.UnsignedLong; -import com.google.common.truth.Truth8; import com.google.testing.junit.testparameterinjector.TestParameterInjector; import com.google.testing.junit.testparameterinjector.TestParameters; import dev.cel.common.CelAbstractSyntaxTree; @@ -273,7 +272,7 @@ public void stringFormatCall_filterList_success() throws Exception { assertThat(allConstants).hasSize(1); CelNavigableExpr listExpr = allConstants.get(0); assertThat(listExpr.getKind()).isEqualTo(Kind.CREATE_LIST); - Truth8.assertThat(listExpr.parent()).isPresent(); + assertThat(listExpr.parent()).isPresent(); CelNavigableExpr stringFormatExpr = listExpr.parent().get(); assertThat(stringFormatExpr.getKind()).isEqualTo(Kind.CALL); CelCall call = listExpr.parent().get().expr().exprKind().call(); @@ -676,7 +675,7 @@ public void comprehension_allNodes_parentsPopulated() throws Exception { CelExpr.ofComprehension( 13, "i", iterRange, "__result__", accuInit, loopCondition, loopStep, result); assertThat(allNodes).hasSize(11); - Truth8.assertThat(allNodes.get(0).parent()).isEmpty(); // comprehension + assertThat(allNodes.get(0).parent()).isEmpty(); // comprehension assertThat(allNodes.get(1).parent().get().expr()).isEqualTo(comprehension); // iter_range assertThat(allNodes.get(2).parent().get().expr()) .isEqualTo(iterRange); // const_expr within iter_range diff --git a/common/src/test/java/dev/cel/common/types/ProtoMessageTypeProviderTest.java b/common/src/test/java/dev/cel/common/types/ProtoMessageTypeProviderTest.java index cb6f03d30..f07a67b71 100644 --- a/common/src/test/java/dev/cel/common/types/ProtoMessageTypeProviderTest.java +++ b/common/src/test/java/dev/cel/common/types/ProtoMessageTypeProviderTest.java @@ -19,7 +19,6 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; -import com.google.common.truth.Truth8; import dev.cel.common.types.CelTypeProvider.CombinedCelTypeProvider; import dev.cel.testing.testdata.proto2.MessagesProto2; import dev.cel.testing.testdata.proto2.MessagesProto2Extensions; @@ -49,7 +48,7 @@ public void types_emptyTypeSet() { @Test public void findType_emptyTypeSet() { - Truth8.assertThat(emptyProvider.findType("any")).isEmpty(); + assertThat(emptyProvider.findType("any")).isEmpty(); } @Test @@ -67,82 +66,78 @@ public void types_allGlobalAndNestedDeclarations() { public void findType_globalEnumWithAllNamesAndNumbers() { Optional celType = proto3Provider.findType("dev.cel.testing.testdata.proto3.GlobalEnum"); - Truth8.assertThat(celType).isPresent(); + assertThat(celType).isPresent(); assertThat(celType.get()).isInstanceOf(EnumType.class); EnumType enumType = (EnumType) celType.get(); assertThat(enumType.name()).isEqualTo("dev.cel.testing.testdata.proto3.GlobalEnum"); - Truth8.assertThat(enumType.findNameByNumber(0)).hasValue("GOO"); - Truth8.assertThat(enumType.findNameByNumber(1)).hasValue("GAR"); - Truth8.assertThat(enumType.findNameByNumber(2)).hasValue("GAZ"); - Truth8.assertThat(enumType.findNameByNumber(3)).isEmpty(); + assertThat(enumType.findNameByNumber(0)).hasValue("GOO"); + assertThat(enumType.findNameByNumber(1)).hasValue("GAR"); + assertThat(enumType.findNameByNumber(2)).hasValue("GAZ"); + assertThat(enumType.findNameByNumber(3)).isEmpty(); } @Test public void findType_nestedEnumWithAllNamesAndNumbers() { Optional celType = proto3Provider.findType("dev.cel.testing.testdata.proto3.TestAllTypes.NestedEnum"); - Truth8.assertThat(celType).isPresent(); + assertThat(celType).isPresent(); assertThat(celType.get()).isInstanceOf(EnumType.class); EnumType enumType = (EnumType) celType.get(); assertThat(enumType.name()) .isEqualTo("dev.cel.testing.testdata.proto3.TestAllTypes.NestedEnum"); - Truth8.assertThat(enumType.findNumberByName("FOO")).hasValue(0); - Truth8.assertThat(enumType.findNumberByName("BAR")).hasValue(1); - Truth8.assertThat(enumType.findNumberByName("BAZ")).hasValue(2); - Truth8.assertThat(enumType.findNumberByName("MISSING")).isEmpty(); + assertThat(enumType.findNumberByName("FOO")).hasValue(0); + assertThat(enumType.findNumberByName("BAR")).hasValue(1); + assertThat(enumType.findNumberByName("BAZ")).hasValue(2); + assertThat(enumType.findNumberByName("MISSING")).isEmpty(); } @Test public void findType_globalMessageTypeNoExtensions() { Optional celType = proto3Provider.findType("dev.cel.testing.testdata.proto3.NestedTestAllTypes"); - Truth8.assertThat(celType).isPresent(); + assertThat(celType).isPresent(); assertThat(celType.get()).isInstanceOf(ProtoMessageType.class); ProtoMessageType protoType = (ProtoMessageType) celType.get(); assertThat(protoType.name()).isEqualTo("dev.cel.testing.testdata.proto3.NestedTestAllTypes"); - Truth8.assertThat(protoType.findField("payload")).isPresent(); - Truth8.assertThat(protoType.findField("child")).isPresent(); - Truth8.assertThat(protoType.findField("missing")).isEmpty(); + assertThat(protoType.findField("payload")).isPresent(); + assertThat(protoType.findField("child")).isPresent(); + assertThat(protoType.findField("missing")).isEmpty(); assertThat(protoType.fields()).hasSize(2); - Truth8.assertThat(protoType.findExtension("dev.cel.testing.testdata.proto3.any")).isEmpty(); + assertThat(protoType.findExtension("dev.cel.testing.testdata.proto3.any")).isEmpty(); } @Test public void findType_globalMessageWithExtensions() { Optional celType = proto2Provider.findType("dev.cel.testing.testdata.proto2.Proto2Message"); - Truth8.assertThat(celType).isPresent(); + assertThat(celType).isPresent(); assertThat(celType.get()).isInstanceOf(ProtoMessageType.class); ProtoMessageType protoType = (ProtoMessageType) celType.get(); assertThat(protoType.name()).isEqualTo("dev.cel.testing.testdata.proto2.Proto2Message"); - Truth8.assertThat(protoType.findField("single_int32")).isPresent(); - Truth8.assertThat(protoType.findField("single_enum")).isPresent(); - Truth8.assertThat(protoType.findField("single_nested_test_all_types")).isPresent(); - Truth8.assertThat(protoType.findField("nestedgroup")).isPresent(); - Truth8.assertThat(protoType.findField("nested_ext")).isEmpty(); + assertThat(protoType.findField("single_int32")).isPresent(); + assertThat(protoType.findField("single_enum")).isPresent(); + assertThat(protoType.findField("single_nested_test_all_types")).isPresent(); + assertThat(protoType.findField("nestedgroup")).isPresent(); + assertThat(protoType.findField("nested_ext")).isEmpty(); - Truth8.assertThat(protoType.findExtension("dev.cel.testing.testdata.proto2.nested_ext")) + assertThat(protoType.findExtension("dev.cel.testing.testdata.proto2.nested_ext")).isPresent(); + assertThat(protoType.findExtension("dev.cel.testing.testdata.proto2.int32_ext")).isPresent(); + assertThat(protoType.findExtension("dev.cel.testing.testdata.proto2.test_all_types_ext")) .isPresent(); - Truth8.assertThat(protoType.findExtension("dev.cel.testing.testdata.proto2.int32_ext")) + assertThat(protoType.findExtension("dev.cel.testing.testdata.proto2.nested_enum_ext")) .isPresent(); - Truth8.assertThat(protoType.findExtension("dev.cel.testing.testdata.proto2.test_all_types_ext")) - .isPresent(); - Truth8.assertThat(protoType.findExtension("dev.cel.testing.testdata.proto2.nested_enum_ext")) - .isPresent(); - Truth8.assertThat( + assertThat( protoType.findExtension("dev.cel.testing.testdata.proto2.repeated_string_holder_ext")) .isPresent(); - Truth8.assertThat( - protoType.findExtension("dev.cel.testing.testdata.proto2.Proto2Message.int32_ext")) + assertThat(protoType.findExtension("dev.cel.testing.testdata.proto2.Proto2Message.int32_ext")) .isEmpty(); Optional holderType = proto2Provider.findType("dev.cel.testing.testdata.proto2.StringHolder"); - Truth8.assertThat(holderType).isPresent(); + assertThat(holderType).isPresent(); ProtoMessageType stringHolderType = (ProtoMessageType) holderType.get(); - Truth8.assertThat( - stringHolderType.findExtension("dev.cel.testing.testdata.proto2.nested_enum_ext")) + assertThat(stringHolderType.findExtension("dev.cel.testing.testdata.proto2.nested_enum_ext")) .isEmpty(); } @@ -150,24 +145,24 @@ public void findType_globalMessageWithExtensions() { public void findType_scopedMessageWithExtensions() { Optional celType = proto2Provider.findType("dev.cel.testing.testdata.proto2.Proto2Message"); - Truth8.assertThat(celType).isPresent(); + assertThat(celType).isPresent(); assertThat(celType.get()).isInstanceOf(ProtoMessageType.class); ProtoMessageType protoType = (ProtoMessageType) celType.get(); - Truth8.assertThat( + assertThat( protoType.findExtension( "dev.cel.testing.testdata.proto2.Proto2ExtensionScopedMessage.message_scoped_nested_ext")) .isPresent(); - Truth8.assertThat( + assertThat( protoType.findExtension( "dev.cel.testing.testdata.proto2.Proto2ExtensionScopedMessage.int64_ext")) .isPresent(); - Truth8.assertThat( + assertThat( protoType.findExtension( "dev.cel.testing.testdata.proto2.Proto2ExtensionScopedMessage.string_ext")) .isPresent(); - Truth8.assertThat( + assertThat( protoType.findExtension( "dev.cel.testing.testdata.proto2.Proto2ExtensionScopedMessage.nested_message_inside_ext")) .isPresent(); @@ -177,11 +172,11 @@ public void findType_scopedMessageWithExtensions() { public void findType_withRepeatedEnumField() { Optional celType = proto3Provider.findType("dev.cel.testing.testdata.proto3.TestAllTypes"); - Truth8.assertThat(celType).isPresent(); + assertThat(celType).isPresent(); assertThat(celType.get()).isInstanceOf(ProtoMessageType.class); ProtoMessageType protoType = (ProtoMessageType) celType.get(); assertThat(protoType.name()).isEqualTo("dev.cel.testing.testdata.proto3.TestAllTypes"); - Truth8.assertThat(protoType.findField("repeated_nested_enum")).isPresent(); + assertThat(protoType.findField("repeated_nested_enum")).isPresent(); CelType fieldType = protoType.findField("repeated_nested_enum").get().type(); assertThat(fieldType.kind()).isEqualTo(CelKind.LIST); @@ -191,8 +186,7 @@ public void findType_withRepeatedEnumField() { .isEqualTo("dev.cel.testing.testdata.proto3.TestAllTypes.NestedEnum"); assertThat(elemType.kind()).isEqualTo(CelKind.INT); assertThat(elemType).isInstanceOf(EnumType.class); - Truth8.assertThat( - proto3Provider.findType("dev.cel.testing.testdata.proto3.TestAllTypes.NestedEnum")) + assertThat(proto3Provider.findType("dev.cel.testing.testdata.proto3.TestAllTypes.NestedEnum")) .hasValue(elemType); } @@ -202,7 +196,7 @@ public void findType_withOneofField() { proto3Provider.findType("dev.cel.testing.testdata.proto3.TestAllTypes"); ProtoMessageType protoType = (ProtoMessageType) celType.get(); assertThat(protoType.name()).isEqualTo("dev.cel.testing.testdata.proto3.TestAllTypes"); - Truth8.assertThat(protoType.findField("single_nested_message").map(f -> f.type().name())) + assertThat(protoType.findField("single_nested_message").map(f -> f.type().name())) .hasValue("dev.cel.testing.testdata.proto3.TestAllTypes.NestedMessage"); } @@ -228,35 +222,33 @@ public void findType_withWellKnownTypes() { Optional celType = proto3Provider.findType("dev.cel.testing.testdata.proto3.TestAllTypes"); ProtoMessageType protoType = (ProtoMessageType) celType.get(); - Truth8.assertThat(protoType.findField("single_any").map(f -> f.type())) - .hasValue(SimpleType.ANY); - Truth8.assertThat(protoType.findField("single_duration").map(f -> f.type())) + assertThat(protoType.findField("single_any").map(f -> f.type())).hasValue(SimpleType.ANY); + assertThat(protoType.findField("single_duration").map(f -> f.type())) .hasValue(SimpleType.DURATION); - Truth8.assertThat(protoType.findField("single_timestamp").map(f -> f.type())) + assertThat(protoType.findField("single_timestamp").map(f -> f.type())) .hasValue(SimpleType.TIMESTAMP); - Truth8.assertThat(protoType.findField("single_value").map(f -> f.type())) - .hasValue(SimpleType.DYN); - Truth8.assertThat(protoType.findField("single_list_value").map(f -> f.type())) + assertThat(protoType.findField("single_value").map(f -> f.type())).hasValue(SimpleType.DYN); + assertThat(protoType.findField("single_list_value").map(f -> f.type())) .hasValue(ListType.create(SimpleType.DYN)); - Truth8.assertThat(protoType.findField("single_struct").map(f -> f.type())) + assertThat(protoType.findField("single_struct").map(f -> f.type())) .hasValue(MapType.create(SimpleType.STRING, SimpleType.DYN)); - Truth8.assertThat(protoType.findField("single_bool_wrapper").map(f -> f.type())) + assertThat(protoType.findField("single_bool_wrapper").map(f -> f.type())) .hasValue(NullableType.create(SimpleType.BOOL)); - Truth8.assertThat(protoType.findField("single_bytes_wrapper").map(f -> f.type())) + assertThat(protoType.findField("single_bytes_wrapper").map(f -> f.type())) .hasValue(NullableType.create(SimpleType.BYTES)); - Truth8.assertThat(protoType.findField("single_int32_wrapper").map(f -> f.type())) + assertThat(protoType.findField("single_int32_wrapper").map(f -> f.type())) .hasValue(NullableType.create(SimpleType.INT)); - Truth8.assertThat(protoType.findField("single_int64_wrapper").map(f -> f.type())) + assertThat(protoType.findField("single_int64_wrapper").map(f -> f.type())) .hasValue(NullableType.create(SimpleType.INT)); - Truth8.assertThat(protoType.findField("single_double_wrapper").map(f -> f.type())) + assertThat(protoType.findField("single_double_wrapper").map(f -> f.type())) .hasValue(NullableType.create(SimpleType.DOUBLE)); - Truth8.assertThat(protoType.findField("single_float_wrapper").map(f -> f.type())) + assertThat(protoType.findField("single_float_wrapper").map(f -> f.type())) .hasValue(NullableType.create(SimpleType.DOUBLE)); - Truth8.assertThat(protoType.findField("single_string_wrapper").map(f -> f.type())) + assertThat(protoType.findField("single_string_wrapper").map(f -> f.type())) .hasValue(NullableType.create(SimpleType.STRING)); - Truth8.assertThat(protoType.findField("single_uint32_wrapper").map(f -> f.type())) + assertThat(protoType.findField("single_uint32_wrapper").map(f -> f.type())) .hasValue(NullableType.create(SimpleType.UINT)); - Truth8.assertThat(protoType.findField("single_uint64_wrapper").map(f -> f.type())) + assertThat(protoType.findField("single_uint64_wrapper").map(f -> f.type())) .hasValue(NullableType.create(SimpleType.UINT)); } diff --git a/common/src/test/java/dev/cel/common/types/ProtoMessageTypeTest.java b/common/src/test/java/dev/cel/common/types/ProtoMessageTypeTest.java index 5e0c3a83c..3feab06fd 100644 --- a/common/src/test/java/dev/cel/common/types/ProtoMessageTypeTest.java +++ b/common/src/test/java/dev/cel/common/types/ProtoMessageTypeTest.java @@ -18,7 +18,6 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; -import com.google.common.truth.Truth8; import java.util.Optional; import org.junit.Before; import org.junit.Test; @@ -53,7 +52,7 @@ public void setUp() { @Test public void findField() { for (String fieldName : FIELD_MAP.keySet()) { - Truth8.assertThat(testMessage.findField(fieldName)) + assertThat(testMessage.findField(fieldName)) .hasValue(StructType.Field.of(fieldName, FIELD_MAP.get(fieldName))); } } @@ -61,8 +60,8 @@ public void findField() { @Test public void withVisibleFields() { ProtoMessageType maskedMessage = testMessage.withVisibleFields(ImmutableSet.of("bool_value")); - Truth8.assertThat(maskedMessage.findField("int_value")).isEmpty(); - Truth8.assertThat(maskedMessage.findField("bool_value")).isPresent(); + assertThat(maskedMessage.findField("int_value")).isEmpty(); + assertThat(maskedMessage.findField("bool_value")).isPresent(); assertThat(maskedMessage.fields()).hasSize(1); assertThat(testMessage.fields()).hasSize(4); } @@ -70,7 +69,7 @@ public void withVisibleFields() { @Test public void findExtension() { for (String extName : EXTENSION_MAP.keySet()) { - Truth8.assertThat(testMessage.findExtension(extName)) + assertThat(testMessage.findExtension(extName)) .hasValue( ProtoMessageType.Extension.of(extName, EXTENSION_MAP.get(extName), testMessage)); } diff --git a/common/src/test/java/dev/cel/common/values/OptionalValueTest.java b/common/src/test/java/dev/cel/common/values/OptionalValueTest.java index c42b6522d..6a991a6a9 100644 --- a/common/src/test/java/dev/cel/common/values/OptionalValueTest.java +++ b/common/src/test/java/dev/cel/common/values/OptionalValueTest.java @@ -18,7 +18,6 @@ import static org.junit.Assert.assertThrows; import com.google.common.collect.ImmutableMap; -import com.google.common.truth.Truth8; import com.google.testing.junit.testparameterinjector.TestParameterInjector; import com.google.testing.junit.testparameterinjector.TestParameters; import dev.cel.common.types.CelType; @@ -133,7 +132,7 @@ public void findField_struct_success(String field, boolean expectedResult) { @Test public void findField_onEmptyOptional() { - Truth8.assertThat(OptionalValue.EMPTY.find(StringValue.create("bogus"))).isEmpty(); + assertThat(OptionalValue.EMPTY.find(StringValue.create("bogus"))).isEmpty(); } @Test diff --git a/common/src/test/java/dev/cel/common/values/ProtoMessageValueTest.java b/common/src/test/java/dev/cel/common/values/ProtoMessageValueTest.java index c1e518a9e..32f89e7a1 100644 --- a/common/src/test/java/dev/cel/common/values/ProtoMessageValueTest.java +++ b/common/src/test/java/dev/cel/common/values/ProtoMessageValueTest.java @@ -20,7 +20,6 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.primitives.UnsignedLong; -import com.google.common.truth.Truth8; import com.google.protobuf.Any; import com.google.protobuf.ByteString; import com.google.protobuf.DynamicMessage; @@ -97,9 +96,9 @@ public void findField_fieldIsSet_fieldExists() { ProtoMessageValue.create( testAllTypes, DefaultDescriptorPool.INSTANCE, PROTO_CEL_VALUE_CONVERTER); - Truth8.assertThat(protoMessageValue.find(StringValue.create("single_bool"))).isPresent(); - Truth8.assertThat(protoMessageValue.find(StringValue.create("single_int64"))).isPresent(); - Truth8.assertThat(protoMessageValue.find(StringValue.create("repeated_int64"))).isPresent(); + assertThat(protoMessageValue.find(StringValue.create("single_bool"))).isPresent(); + assertThat(protoMessageValue.find(StringValue.create("single_int64"))).isPresent(); + assertThat(protoMessageValue.find(StringValue.create("repeated_int64"))).isPresent(); } @Test @@ -110,9 +109,9 @@ public void findField_fieldIsUnset_fieldDoesNotExist() { DefaultDescriptorPool.INSTANCE, PROTO_CEL_VALUE_CONVERTER); - Truth8.assertThat(protoMessageValue.find(StringValue.create("single_int32"))).isEmpty(); - Truth8.assertThat(protoMessageValue.find(StringValue.create("single_uint64"))).isEmpty(); - Truth8.assertThat(protoMessageValue.find(StringValue.create("repeated_int32"))).isEmpty(); + assertThat(protoMessageValue.find(StringValue.create("single_int32"))).isEmpty(); + assertThat(protoMessageValue.find(StringValue.create("single_uint64"))).isEmpty(); + assertThat(protoMessageValue.find(StringValue.create("repeated_int32"))).isEmpty(); } @Test @@ -151,7 +150,7 @@ public void findField_extensionField_success() { ProtoMessageValue protoMessageValue = ProtoMessageValue.create(proto2Message, descriptorPool, protoCelValueConverter); - Truth8.assertThat( + assertThat( protoMessageValue.find(StringValue.create("dev.cel.testing.testdata.proto2.int32_ext"))) .isPresent(); } diff --git a/extensions/src/test/java/dev/cel/extensions/CelOptionalLibraryTest.java b/extensions/src/test/java/dev/cel/extensions/CelOptionalLibraryTest.java index 2f8376693..8cb7a11f7 100644 --- a/extensions/src/test/java/dev/cel/extensions/CelOptionalLibraryTest.java +++ b/extensions/src/test/java/dev/cel/extensions/CelOptionalLibraryTest.java @@ -20,7 +20,6 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.primitives.UnsignedLong; -import com.google.common.truth.Truth8; import com.google.protobuf.ByteString; import com.google.protobuf.DoubleValue; import com.google.protobuf.NullValue; @@ -144,7 +143,7 @@ public void optionalType_adaptsIntegerToLong_success() throws Exception { Optional result = (Optional) cel.createProgram(ast).eval(ImmutableMap.of("a", Optional.of(5))); - Truth8.assertThat(result).hasValue(5L); + assertThat(result).hasValue(5L); } @Test @@ -155,7 +154,7 @@ public void optionalType_adaptsFloatToLong_success() throws Exception { Optional result = (Optional) cel.createProgram(ast).eval(ImmutableMap.of("a", Optional.of(5.5f))); - Truth8.assertThat(result).hasValue(5.5d); + assertThat(result).hasValue(5.5d); } @Test @@ -504,7 +503,7 @@ public void optionalFieldSelection_onMap_returnsOptionalValue() throws Exception Optional result = (Optional) cel.createProgram(ast).eval(); - Truth8.assertThat(result).hasValue(2L); + assertThat(result).hasValue(2L); } @Test @@ -520,7 +519,7 @@ public void optionalFieldSelection_onProtoMessage_returnsOptionalEmpty() throws (Optional) cel.createProgram(ast).eval(ImmutableMap.of("msg", TestAllTypes.getDefaultInstance())); - Truth8.assertThat(result).isEmpty(); + assertThat(result).isEmpty(); } @Test @@ -537,7 +536,7 @@ public void optionalFieldSelection_onProtoMessage_returnsOptionalValue() throws cel.createProgram(ast) .eval(ImmutableMap.of("msg", TestAllTypes.newBuilder().setSingleInt32(5).build())); - Truth8.assertThat(result).hasValue(5L); + assertThat(result).hasValue(5L); } @Test @@ -568,7 +567,7 @@ public void optionalFieldSelection_onProtoMessage_chainedSuccess() throws Except "dashed-index", TestAllTypes.newBuilder().setSingleInt32(5).build())))); - Truth8.assertThat(result).hasValue(5L); + assertThat(result).hasValue(5L); } @Test @@ -1236,7 +1235,7 @@ public void optionalMapMacro_receiverIsEmpty_returnsOptionalEmpty() throws Excep Optional result = (Optional) cel.createProgram(ast).eval(ImmutableMap.of("x", Optional.empty())); - Truth8.assertThat(result).isEmpty(); + assertThat(result).isEmpty(); } @Test @@ -1251,7 +1250,7 @@ public void optionalMapMacro_receiverHasValue_returnsOptionalValue() throws Exce Optional result = (Optional) cel.createProgram(ast).eval(ImmutableMap.of("x", Optional.of(42L))); - Truth8.assertThat(result).hasValue(43L); + assertThat(result).hasValue(43L); } @Test @@ -1281,7 +1280,7 @@ public void optionalFlatMapMacro_receiverIsEmpty_returnsOptionalEmpty() throws E Optional result = (Optional) cel.createProgram(ast).eval(ImmutableMap.of("x", Optional.empty())); - Truth8.assertThat(result).isEmpty(); + assertThat(result).isEmpty(); } @Test @@ -1296,7 +1295,7 @@ public void optionalFlatMapMacro_receiverHasValue_returnsOptionalValue() throws Optional result = (Optional) cel.createProgram(ast).eval(ImmutableMap.of("x", Optional.of(42L))); - Truth8.assertThat(result).hasValue(43L); + assertThat(result).hasValue(43L); } @Test @@ -1313,7 +1312,7 @@ public void optionalFlatMapMacro_withOptionalOfNonZeroValue_optionalEmptyWhenVal Optional result = (Optional) cel.createProgram(ast).eval(ImmutableMap.of("x", Optional.of(1L))); - Truth8.assertThat(result).isEmpty(); + assertThat(result).isEmpty(); } @Test @@ -1330,7 +1329,7 @@ public void optionalFlatMapMacro_withOptionalOfNonZeroValue_optionalValueWhenVal Optional result = (Optional) cel.createProgram(ast).eval(ImmutableMap.of("x", Optional.of(1L))); - Truth8.assertThat(result).hasValue(2L); + assertThat(result).hasValue(2L); } @Test diff --git a/parser/src/test/java/dev/cel/parser/CelMacroExprFactoryTest.java b/parser/src/test/java/dev/cel/parser/CelMacroExprFactoryTest.java index 7898239fc..0a66f26da 100644 --- a/parser/src/test/java/dev/cel/parser/CelMacroExprFactoryTest.java +++ b/parser/src/test/java/dev/cel/parser/CelMacroExprFactoryTest.java @@ -17,7 +17,6 @@ import static com.google.common.truth.Truth.assertThat; import com.google.common.primitives.UnsignedLong; -import com.google.common.truth.Truth8; import com.google.protobuf.ByteString; import dev.cel.common.CelIssue; import dev.cel.common.CelSourceLocation; @@ -578,7 +577,7 @@ public void newGlobalCall_returnsGlobalCall() { CelExpr expr = exprFactory.newGlobalCall("foo", argument); assertThat(expr.id()).isEqualTo(2L); assertThat(expr.exprKind().getKind()).isEqualTo(Kind.CALL); - Truth8.assertThat(expr.call().target()).isEmpty(); + assertThat(expr.call().target()).isEmpty(); assertThat(expr.call().function()).isEqualTo("foo"); assertThat(expr.call().args()).containsExactly(argument); } @@ -591,7 +590,7 @@ public void newReceiverCall_returnsReceiverCall() { CelExpr expr = exprFactory.newReceiverCall("foo", target, argument); assertThat(expr.id()).isEqualTo(3L); assertThat(expr.exprKind().getKind()).isEqualTo(Kind.CALL); - Truth8.assertThat(expr.call().target()).hasValue(target); + assertThat(expr.call().target()).hasValue(target); assertThat(expr.call().function()).isEqualTo("foo"); assertThat(expr.call().args()).containsExactly(argument); } diff --git a/parser/src/test/java/dev/cel/parser/CelParserImplTest.java b/parser/src/test/java/dev/cel/parser/CelParserImplTest.java index 287942492..7c01c3611 100644 --- a/parser/src/test/java/dev/cel/parser/CelParserImplTest.java +++ b/parser/src/test/java/dev/cel/parser/CelParserImplTest.java @@ -17,7 +17,6 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertThrows; -import com.google.common.truth.Truth8; import com.google.testing.junit.testparameterinjector.TestParameter; import com.google.testing.junit.testparameterinjector.TestParameterInjector; import com.google.testing.junit.testparameterinjector.TestParameters; @@ -42,20 +41,15 @@ public void build_withMacros_containsAllMacros() { CelParserImpl parser = (CelParserImpl) CelParserImpl.newBuilder().setStandardMacros(CelStandardMacro.STANDARD_MACROS).build(); - Truth8.assertThat(parser.findMacro("has:1:false")) - .hasValue(CelStandardMacro.HAS.getDefinition()); - Truth8.assertThat(parser.findMacro("all:2:true")) - .hasValue(CelStandardMacro.ALL.getDefinition()); - Truth8.assertThat(parser.findMacro("exists:2:true")) - .hasValue(CelStandardMacro.EXISTS.getDefinition()); - Truth8.assertThat(parser.findMacro("exists_one:2:true")) + assertThat(parser.findMacro("has:1:false")).hasValue(CelStandardMacro.HAS.getDefinition()); + assertThat(parser.findMacro("all:2:true")).hasValue(CelStandardMacro.ALL.getDefinition()); + assertThat(parser.findMacro("exists:2:true")).hasValue(CelStandardMacro.EXISTS.getDefinition()); + assertThat(parser.findMacro("exists_one:2:true")) .hasValue(CelStandardMacro.EXISTS_ONE.getDefinition()); - Truth8.assertThat(parser.findMacro("map:2:true")) - .hasValue(CelStandardMacro.MAP.getDefinition()); - Truth8.assertThat(parser.findMacro("map:3:true")) + assertThat(parser.findMacro("map:2:true")).hasValue(CelStandardMacro.MAP.getDefinition()); + assertThat(parser.findMacro("map:3:true")) .hasValue(CelStandardMacro.MAP_FILTER.getDefinition()); - Truth8.assertThat(parser.findMacro("filter:2:true")) - .hasValue(CelStandardMacro.FILTER.getDefinition()); + assertThat(parser.findMacro("filter:2:true")).hasValue(CelStandardMacro.FILTER.getDefinition()); } @Test @@ -63,20 +57,15 @@ public void build_withStandardMacros_containsAllMacros() { CelParserImpl parser = (CelParserImpl) CelParserImpl.newBuilder().setStandardMacros(CelStandardMacro.STANDARD_MACROS).build(); - Truth8.assertThat(parser.findMacro("has:1:false")) - .hasValue(CelStandardMacro.HAS.getDefinition()); - Truth8.assertThat(parser.findMacro("all:2:true")) - .hasValue(CelStandardMacro.ALL.getDefinition()); - Truth8.assertThat(parser.findMacro("exists:2:true")) - .hasValue(CelStandardMacro.EXISTS.getDefinition()); - Truth8.assertThat(parser.findMacro("exists_one:2:true")) + assertThat(parser.findMacro("has:1:false")).hasValue(CelStandardMacro.HAS.getDefinition()); + assertThat(parser.findMacro("all:2:true")).hasValue(CelStandardMacro.ALL.getDefinition()); + assertThat(parser.findMacro("exists:2:true")).hasValue(CelStandardMacro.EXISTS.getDefinition()); + assertThat(parser.findMacro("exists_one:2:true")) .hasValue(CelStandardMacro.EXISTS_ONE.getDefinition()); - Truth8.assertThat(parser.findMacro("map:2:true")) - .hasValue(CelStandardMacro.MAP.getDefinition()); - Truth8.assertThat(parser.findMacro("map:3:true")) + assertThat(parser.findMacro("map:2:true")).hasValue(CelStandardMacro.MAP.getDefinition()); + assertThat(parser.findMacro("map:3:true")) .hasValue(CelStandardMacro.MAP_FILTER.getDefinition()); - Truth8.assertThat(parser.findMacro("filter:2:true")) - .hasValue(CelStandardMacro.FILTER.getDefinition()); + assertThat(parser.findMacro("filter:2:true")).hasValue(CelStandardMacro.FILTER.getDefinition()); } @Test @@ -91,37 +80,30 @@ public void build_withStandardMacrosAndCustomMacros_containsAllMacros() { .addMacros(customMacro) .build(); - Truth8.assertThat(parser.findMacro("has:1:false")) - .hasValue(CelStandardMacro.HAS.getDefinition()); - Truth8.assertThat(parser.findMacro("all:2:true")) - .hasValue(CelStandardMacro.ALL.getDefinition()); - Truth8.assertThat(parser.findMacro("exists:2:true")) - .hasValue(CelStandardMacro.EXISTS.getDefinition()); - Truth8.assertThat(parser.findMacro("exists_one:2:true")) + assertThat(parser.findMacro("has:1:false")).hasValue(CelStandardMacro.HAS.getDefinition()); + assertThat(parser.findMacro("all:2:true")).hasValue(CelStandardMacro.ALL.getDefinition()); + assertThat(parser.findMacro("exists:2:true")).hasValue(CelStandardMacro.EXISTS.getDefinition()); + assertThat(parser.findMacro("exists_one:2:true")) .hasValue(CelStandardMacro.EXISTS_ONE.getDefinition()); - Truth8.assertThat(parser.findMacro("map:2:true")) - .hasValue(CelStandardMacro.MAP.getDefinition()); - Truth8.assertThat(parser.findMacro("map:3:true")) + assertThat(parser.findMacro("map:2:true")).hasValue(CelStandardMacro.MAP.getDefinition()); + assertThat(parser.findMacro("map:3:true")) .hasValue(CelStandardMacro.MAP_FILTER.getDefinition()); - Truth8.assertThat(parser.findMacro("filter:2:true")) - .hasValue(CelStandardMacro.FILTER.getDefinition()); - Truth8.assertThat(parser.findMacro("customMacro:1:true")).hasValue(customMacro); + assertThat(parser.findMacro("filter:2:true")).hasValue(CelStandardMacro.FILTER.getDefinition()); + assertThat(parser.findMacro("customMacro:1:true")).hasValue(customMacro); } @Test public void build_withMacro_containsMacro() { CelParserImpl parser = (CelParserImpl) CelParserImpl.newBuilder().setStandardMacros(CelStandardMacro.HAS).build(); - Truth8.assertThat(parser.findMacro("has:1:false")) - .hasValue(CelStandardMacro.HAS.getDefinition()); + assertThat(parser.findMacro("has:1:false")).hasValue(CelStandardMacro.HAS.getDefinition()); } @Test public void build_withStandardMacro_containsMacro() { CelParserImpl parser = (CelParserImpl) CelParserImpl.newBuilder().setStandardMacros(CelStandardMacro.HAS).build(); - Truth8.assertThat(parser.findMacro("has:1:false")) - .hasValue(CelStandardMacro.HAS.getDefinition()); + assertThat(parser.findMacro("has:1:false")).hasValue(CelStandardMacro.HAS.getDefinition()); } @Test @@ -133,9 +115,8 @@ public void build_withStandardMacro_secondCallReplaces() { .setStandardMacros(CelStandardMacro.HAS) .build(); - Truth8.assertThat(parser.findMacro("has:1:false")) - .hasValue(CelStandardMacro.HAS.getDefinition()); - Truth8.assertThat(parser.findMacro("all:2:true")).isEmpty(); + assertThat(parser.findMacro("has:1:false")).hasValue(CelStandardMacro.HAS.getDefinition()); + assertThat(parser.findMacro("all:2:true")).isEmpty(); } @Test @@ -155,7 +136,7 @@ public void build_standardMacroKeyConflictsWithCustomMacro_throws() { @Test public void build_containsNoMacros() { CelParserImpl parser = (CelParserImpl) CelParserImpl.newBuilder().build(); - Truth8.assertThat(parser.findMacro("has:1:false")).isEmpty(); + assertThat(parser.findMacro("has:1:false")).isEmpty(); } @Test @@ -175,7 +156,7 @@ public void setParserOptions(CelParserBuilder parserBuilder) { }) .build(); - Truth8.assertThat(parser.findMacro("dummyMacro:*:true")).isPresent(); + assertThat(parser.findMacro("dummyMacro:*:true")).isPresent(); } @Test diff --git a/runtime/src/test/java/dev/cel/runtime/UnknownContextTest.java b/runtime/src/test/java/dev/cel/runtime/UnknownContextTest.java index 8d0c35d9d..428fa6b26 100644 --- a/runtime/src/test/java/dev/cel/runtime/UnknownContextTest.java +++ b/runtime/src/test/java/dev/cel/runtime/UnknownContextTest.java @@ -18,7 +18,6 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; -import com.google.common.truth.Truth8; import java.util.Optional; import org.junit.Test; import org.junit.runner.RunWith; @@ -33,8 +32,7 @@ public void create_variableResolverOnly() { CelAttributeResolver attributeResolver = context.createAttributeResolver(); - Truth8.assertThat(attributeResolver.resolve(CelAttribute.fromQualifiedIdentifier("test"))) - .isEmpty(); + assertThat(attributeResolver.resolve(CelAttribute.fromQualifiedIdentifier("test"))).isEmpty(); assertThat(context.variableResolver().resolve("test")).isEqualTo("test_value"); } @@ -49,16 +47,16 @@ public void create_attributeResolverResolvesUnknown() { CelAttributeResolver attributeResolver = context.createAttributeResolver(); - Truth8.assertThat( + assertThat( attributeResolver.resolve( CelAttribute.fromQualifiedIdentifier("qualified.Identifier1"))) .hasValue( CelUnknownSet.create(CelAttribute.fromQualifiedIdentifier("qualified.Identifier1"))); - Truth8.assertThat( + assertThat( attributeResolver.resolve( CelAttribute.fromQualifiedIdentifier("qualified.Identifier2"))) .isEmpty(); - Truth8.assertThat( + assertThat( attributeResolver.resolve( CelAttribute.fromQualifiedIdentifier("qualified.Identifier2.field1"))) .hasValue( @@ -77,17 +75,17 @@ public void create_attributeResolverIdentifiesPartials() { CelAttributeResolver attributeResolver = context.createAttributeResolver(); - Truth8.assertThat( + assertThat( attributeResolver.maybePartialUnknown( CelAttribute.fromQualifiedIdentifier("qualified.Identifier1"))) .hasValue( CelUnknownSet.create(CelAttribute.fromQualifiedIdentifier("qualified.Identifier1"))); - Truth8.assertThat( + assertThat( attributeResolver.maybePartialUnknown( CelAttribute.fromQualifiedIdentifier("qualified.Identifier2"))) .hasValue( CelUnknownSet.create(CelAttribute.fromQualifiedIdentifier("qualified.Identifier2"))); - Truth8.assertThat( + assertThat( attributeResolver.maybePartialUnknown( CelAttribute.fromQualifiedIdentifier("qualified.Identifier2.field1"))) .hasValue( @@ -106,17 +104,17 @@ public void withResolvedAttributes_attributeResolverReturnsValue() { CelAttributeResolver attributeResolver = context.createAttributeResolver(); - Truth8.assertThat( + assertThat( attributeResolver.maybePartialUnknown( CelAttribute.fromQualifiedIdentifier("qualified.Identifier1"))) .hasValue( CelUnknownSet.create(CelAttribute.fromQualifiedIdentifier("qualified.Identifier1"))); - Truth8.assertThat( + assertThat( attributeResolver.maybePartialUnknown( CelAttribute.fromQualifiedIdentifier("qualified.Identifier2"))) .hasValue( CelUnknownSet.create(CelAttribute.fromQualifiedIdentifier("qualified.Identifier2"))); - Truth8.assertThat( + assertThat( attributeResolver.maybePartialUnknown( CelAttribute.fromQualifiedIdentifier("qualified.Identifier2.field1"))) .hasValue( @@ -136,7 +134,7 @@ public void withResolvedAttributes_attributeResolverResolves() { CelAttributeResolver attributeResolver = context.createAttributeResolver(); - Truth8.assertThat( + assertThat( attributeResolver.resolve(CelAttribute.fromQualifiedIdentifier("qualified.Identifier"))) .hasValue("value1"); } @@ -157,14 +155,14 @@ public void withResolvedAttributes_attributeResolverPartialsShadowed() { CelAttributeResolver attributeResolver = context.createAttributeResolver(); - Truth8.assertThat( + assertThat( attributeResolver.resolve(CelAttribute.fromQualifiedIdentifier("qualified.Identifier"))) .hasValue("value1"); - Truth8.assertThat( + assertThat( attributeResolver.maybePartialUnknown( CelAttribute.fromQualifiedIdentifier("qualified.Identifier.field1"))) .isEmpty(); - Truth8.assertThat( + assertThat( attributeResolver.maybePartialUnknown( CelAttribute.fromQualifiedIdentifier("qualified.Identifier.field2"))) .isEmpty(); From 00d77264c27db72a37085d12d5706a216f0d7dc1 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Thu, 8 Feb 2024 11:49:52 -0800 Subject: [PATCH 025/486] Add `.toBuilder` methods to constructed CEL environments PiperOrigin-RevId: 605383725 --- bundle/src/main/java/dev/cel/bundle/Cel.java | 4 +- .../main/java/dev/cel/bundle/CelFactory.java | 7 +- .../src/main/java/dev/cel/bundle/CelImpl.java | 38 +++++-- .../src/test/java/dev/cel/bundle/BUILD.bazel | 2 + .../test/java/dev/cel/bundle/CelImplTest.java | 25 +++++ .../main/java/dev/cel/checker/CelChecker.java | 2 + .../dev/cel/checker/CelCheckerLegacyImpl.java | 99 +++++++++++++--- .../src/main/java/dev/cel/checker/Env.java | 4 +- .../checker/ProtoTypeMaskTypeProvider.java | 6 +- .../src/test/java/dev/cel/checker/BUILD.bazel | 1 + .../cel/checker/CelCheckerLegacyImplTest.java | 106 ++++++++++++++++++ .../dev/cel/checker/CelCompilerImplTest.java | 45 ++++++++ .../dev/cel/checker/CelFunctionDeclTest.java | 10 +- .../ProtoTypeMaskTypeProviderTest.java | 31 +++-- .../java/dev/cel/common/CelFunctionDecl.java | 12 +- .../main/java/dev/cel/common/CelOptions.java | 1 - .../java/dev/cel/common/CelOverloadDecl.java | 2 +- .../java/dev/cel/compiler/CelCompiler.java | 2 + .../dev/cel/compiler/CelCompilerImpl.java | 15 +++ .../main/java/dev/cel/parser/CelParser.java | 2 + .../java/dev/cel/parser/CelParserImpl.java | 44 +++++++- .../dev/cel/parser/CelParserImplTest.java | 40 +++++++ .../main/java/dev/cel/runtime/CelRuntime.java | 2 + .../dev/cel/runtime/CelRuntimeLegacyImpl.java | 62 +++++++++- .../cel/runtime/CelRuntimeLegacyImplTest.java | 60 ++++++++++ 25 files changed, 557 insertions(+), 65 deletions(-) create mode 100644 checker/src/test/java/dev/cel/checker/CelCheckerLegacyImplTest.java create mode 100644 checker/src/test/java/dev/cel/checker/CelCompilerImplTest.java diff --git a/bundle/src/main/java/dev/cel/bundle/Cel.java b/bundle/src/main/java/dev/cel/bundle/Cel.java index 964b21a5c..677a4af2c 100644 --- a/bundle/src/main/java/dev/cel/bundle/Cel.java +++ b/bundle/src/main/java/dev/cel/bundle/Cel.java @@ -20,4 +20,6 @@ /** Cel interface for parse, type-check, and evaluation of CEL programs. */ @ThreadSafe -public interface Cel extends CelCompiler, CelRuntime {} +public interface Cel extends CelCompiler, CelRuntime { + CelBuilder toCelBuilder(); +} diff --git a/bundle/src/main/java/dev/cel/bundle/CelFactory.java b/bundle/src/main/java/dev/cel/bundle/CelFactory.java index c69c4a3a5..a2080bc25 100644 --- a/bundle/src/main/java/dev/cel/bundle/CelFactory.java +++ b/bundle/src/main/java/dev/cel/bundle/CelFactory.java @@ -17,8 +17,10 @@ import dev.cel.checker.CelCheckerLegacyImpl; import dev.cel.common.CelOptions; import dev.cel.compiler.CelCompiler; +import dev.cel.compiler.CelCompilerImpl; import dev.cel.parser.CelParserImpl; import dev.cel.runtime.CelRuntime; +import dev.cel.runtime.CelRuntimeLegacyImpl; /** Helper class to configure the entire CEL stack in a common interface. */ public final class CelFactory { @@ -33,7 +35,10 @@ private CelFactory() {} * evaluation are enabled by default. */ public static CelBuilder standardCelBuilder() { - return CelImpl.newBuilder(CelParserImpl.newBuilder(), CelCheckerLegacyImpl.newBuilder()) + return CelImpl.newBuilder( + CelCompilerImpl.newBuilder( + CelParserImpl.newBuilder(), CelCheckerLegacyImpl.newBuilder()), + CelRuntimeLegacyImpl.newBuilder()) .setOptions(CelOptions.current().build()) .setStandardEnvironmentEnabled(true); } diff --git a/bundle/src/main/java/dev/cel/bundle/CelImpl.java b/bundle/src/main/java/dev/cel/bundle/CelImpl.java index 20086b114..ad062d113 100644 --- a/bundle/src/main/java/dev/cel/bundle/CelImpl.java +++ b/bundle/src/main/java/dev/cel/bundle/CelImpl.java @@ -45,7 +45,6 @@ import dev.cel.common.values.CelValueProvider; import dev.cel.compiler.CelCompiler; import dev.cel.compiler.CelCompilerBuilder; -import dev.cel.compiler.CelCompilerImpl; import dev.cel.compiler.CelCompilerLibrary; import dev.cel.parser.CelMacro; import dev.cel.parser.CelParserBuilder; @@ -53,7 +52,6 @@ import dev.cel.runtime.CelEvaluationException; import dev.cel.runtime.CelRuntime; import dev.cel.runtime.CelRuntimeBuilder; -import dev.cel.runtime.CelRuntimeLegacyImpl; import dev.cel.runtime.CelRuntimeLibrary; import java.util.Arrays; import java.util.function.Function; @@ -102,6 +100,31 @@ public void accept(EnvVisitor envVisitor) { } } + @Override + public CelBuilder toCelBuilder() { + return newBuilder(toCompilerBuilder(), toRuntimeBuilder()); + } + + @Override + public CelParserBuilder toParserBuilder() { + return compiler.get().toParserBuilder(); + } + + @Override + public CelCheckerBuilder toCheckerBuilder() { + return compiler.get().toCheckerBuilder(); + } + + @Override + public CelCompilerBuilder toCompilerBuilder() { + return compiler.get().toCompilerBuilder(); + } + + @Override + public CelRuntimeBuilder toRuntimeBuilder() { + return runtime.get().toRuntimeBuilder(); + } + /** Combines a prebuilt {@link CelCompiler} and {@link CelRuntime} into {@link CelImpl}. */ static CelImpl combine(CelCompiler compiler, CelRuntime runtime) { return new CelImpl(Suppliers.memoize(() -> compiler), Suppliers.memoize(() -> runtime)); @@ -112,8 +135,9 @@ static CelImpl combine(CelCompiler compiler, CelRuntime runtime) { * *

By default, {@link CelOptions#DEFAULT} are enabled, as is the CEL standard environment. */ - static CelBuilder newBuilder(CelParserBuilder parserBuilder, CelCheckerBuilder checkerBuilder) { - return new CelImpl.Builder(parserBuilder, checkerBuilder); + static CelBuilder newBuilder( + CelCompilerBuilder compilerBuilder, CelRuntimeBuilder celRuntimeBuilder) { + return new CelImpl.Builder(compilerBuilder, celRuntimeBuilder); } /** Builder class for CelImpl instances. */ @@ -122,9 +146,9 @@ public static final class Builder implements CelBuilder { private final CelCompilerBuilder compilerBuilder; private final CelRuntimeBuilder runtimeBuilder; - private Builder(CelParserBuilder parserBuilder, CelCheckerBuilder checkerBuilder) { - this.compilerBuilder = CelCompilerImpl.newBuilder(parserBuilder, checkerBuilder); - this.runtimeBuilder = CelRuntimeLegacyImpl.newBuilder(); + private Builder(CelCompilerBuilder celCompilerBuilder, CelRuntimeBuilder celRuntimeBuilder) { + this.compilerBuilder = celCompilerBuilder; + this.runtimeBuilder = celRuntimeBuilder; } @Override diff --git a/bundle/src/test/java/dev/cel/bundle/BUILD.bazel b/bundle/src/test/java/dev/cel/bundle/BUILD.bazel index 68ecfa5b2..cccfc8eed 100644 --- a/bundle/src/test/java/dev/cel/bundle/BUILD.bazel +++ b/bundle/src/test/java/dev/cel/bundle/BUILD.bazel @@ -12,6 +12,7 @@ java_library( "//:auto_value", "//:java_truth", "//bundle:cel", + "//checker", "//checker:checker_legacy_environment", "//checker:proto_type_mask", "//common", @@ -31,6 +32,7 @@ java_library( "//common/types:type_providers", "//compiler", "//compiler:compiler_builder", + "//parser", "//parser:macro", "//runtime", "//runtime:unknown_attributes", diff --git a/bundle/src/test/java/dev/cel/bundle/CelImplTest.java b/bundle/src/test/java/dev/cel/bundle/CelImplTest.java index f844246c3..2b3cf30bb 100644 --- a/bundle/src/test/java/dev/cel/bundle/CelImplTest.java +++ b/bundle/src/test/java/dev/cel/bundle/CelImplTest.java @@ -50,6 +50,7 @@ import com.google.testing.junit.testparameterinjector.TestParameter; import com.google.testing.junit.testparameterinjector.TestParameterInjector; import com.google.testing.junit.testparameterinjector.TestParameters; +import dev.cel.checker.CelCheckerLegacyImpl; import dev.cel.checker.DescriptorTypeProvider; import dev.cel.checker.ProtoTypeMask; import dev.cel.checker.TypeProvider; @@ -77,6 +78,8 @@ import dev.cel.common.types.StructTypeReference; import dev.cel.compiler.CelCompiler; import dev.cel.compiler.CelCompilerFactory; +import dev.cel.compiler.CelCompilerImpl; +import dev.cel.parser.CelParserImpl; import dev.cel.parser.CelStandardMacro; import dev.cel.runtime.CelAttribute; import dev.cel.runtime.CelAttribute.Qualifier; @@ -86,6 +89,7 @@ import dev.cel.runtime.CelRuntime.CelFunctionBinding; import dev.cel.runtime.CelRuntime.Program; import dev.cel.runtime.CelRuntimeFactory; +import dev.cel.runtime.CelRuntimeLegacyImpl; import dev.cel.runtime.CelUnknownSet; import dev.cel.runtime.CelVariableResolver; import dev.cel.runtime.UnknownContext; @@ -1812,6 +1816,27 @@ public boolean isAssignableFrom(CelType other) { assertThat(result).isEqualTo("5"); } + @Test + public void toBuilder_isImmutable() { + CelBuilder celBuilder = CelFactory.standardCelBuilder(); + CelImpl celImpl = (CelImpl) celBuilder.build(); + + CelImpl.Builder newCelBuilder = (CelImpl.Builder) celImpl.toCelBuilder(); + CelParserImpl.Builder newParserBuilder = (CelParserImpl.Builder) celImpl.toParserBuilder(); + CelCheckerLegacyImpl.Builder newCheckerBuilder = + (CelCheckerLegacyImpl.Builder) celImpl.toCheckerBuilder(); + CelCompilerImpl.Builder newCompilerBuilder = + (CelCompilerImpl.Builder) celImpl.toCompilerBuilder(); + CelRuntimeLegacyImpl.Builder newRuntimeBuilder = + (CelRuntimeLegacyImpl.Builder) celImpl.toRuntimeBuilder(); + + assertThat(newCelBuilder).isNotEqualTo(celBuilder); + assertThat(newParserBuilder).isNotEqualTo(celImpl.toParserBuilder()); + assertThat(newCheckerBuilder).isNotEqualTo(celImpl.toCheckerBuilder()); + assertThat(newCompilerBuilder).isNotEqualTo(celImpl.toCompilerBuilder()); + assertThat(newRuntimeBuilder).isNotEqualTo(celImpl.toRuntimeBuilder()); + } + private static TypeProvider aliasingProvider(ImmutableMap typeAliases) { return new TypeProvider() { @Override diff --git a/checker/src/main/java/dev/cel/checker/CelChecker.java b/checker/src/main/java/dev/cel/checker/CelChecker.java index 5a6e9c28b..4022212cb 100644 --- a/checker/src/main/java/dev/cel/checker/CelChecker.java +++ b/checker/src/main/java/dev/cel/checker/CelChecker.java @@ -28,4 +28,6 @@ public interface CelChecker { *

Check validates the type-agreement of the parsed {@code CelAbstractSyntaxTree}. */ CelValidationResult check(CelAbstractSyntaxTree ast); + + CelCheckerBuilder toCheckerBuilder(); } diff --git a/checker/src/main/java/dev/cel/checker/CelCheckerLegacyImpl.java b/checker/src/main/java/dev/cel/checker/CelCheckerLegacyImpl.java index ccc9c2955..4ed263c11 100644 --- a/checker/src/main/java/dev/cel/checker/CelCheckerLegacyImpl.java +++ b/checker/src/main/java/dev/cel/checker/CelCheckerLegacyImpl.java @@ -20,6 +20,7 @@ import dev.cel.expr.Decl; import dev.cel.expr.Type; +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Optional; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; @@ -62,8 +63,8 @@ public final class CelCheckerLegacyImpl implements CelChecker, EnvVisitable { private final CelOptions celOptions; private final String container; - private final ImmutableList identDeclarations; - private final ImmutableList functionDeclarations; + private final ImmutableSet identDeclarations; + private final ImmutableSet functionDeclarations; private final Optional expectedResultType; @SuppressWarnings("Immutable") @@ -71,6 +72,10 @@ public final class CelCheckerLegacyImpl implements CelChecker, EnvVisitable { private final boolean standardEnvironmentEnabled; + // Builder is mutable by design. APIs must make defensive copies in and out of this class. + @SuppressWarnings("Immutable") + private final Builder checkerBuilder; + @Override public CelValidationResult check(CelAbstractSyntaxTree ast) { CelSource source = ast.getSource(); @@ -88,6 +93,11 @@ public CelValidationResult check(CelAbstractSyntaxTree ast) { return new CelValidationResult(checkedAst, ImmutableList.of()); } + @Override + public CelCheckerBuilder toCheckerBuilder() { + return new Builder(checkerBuilder); + } + @Override public void accept(EnvVisitor envVisitor) { Errors errors = new Errors("", ""); @@ -132,9 +142,9 @@ public static CelCheckerBuilder newBuilder() { /** Builder class for the legacy {@code CelChecker} implementation. */ public static final class Builder implements CelCheckerBuilder { - private final ImmutableList.Builder identDeclarations; - private final ImmutableList.Builder functionDeclarations; - private final ImmutableList.Builder protoTypeMasks; + private final ImmutableSet.Builder identDeclarations; + private final ImmutableSet.Builder functionDeclarations; + private final ImmutableSet.Builder protoTypeMasks; private final ImmutableSet.Builder messageTypes; private final ImmutableSet.Builder fileTypes; private final ImmutableSet.Builder celCheckerLibraries; @@ -316,6 +326,38 @@ public CelCheckerBuilder addLibraries(Iterable libr return this; } + // The following getters exist for asserting immutability for collections held by this builder, + // and shouldn't be exposed to the public. + @VisibleForTesting + ImmutableSet.Builder getFunctionDecls() { + return this.functionDeclarations; + } + + @VisibleForTesting + ImmutableSet.Builder getIdentDecls() { + return this.identDeclarations; + } + + @VisibleForTesting + ImmutableSet.Builder getProtoTypeMasks() { + return this.protoTypeMasks; + } + + @VisibleForTesting + ImmutableSet.Builder getMessageTypes() { + return this.messageTypes; + } + + @VisibleForTesting + ImmutableSet.Builder getFileTypes() { + return this.fileTypes; + } + + @VisibleForTesting + ImmutableSet.Builder getCheckerLibraries() { + return this.celCheckerLibraries; + } + @Override @CheckReturnValue public CelCheckerLegacyImpl build() { @@ -348,13 +390,13 @@ public CelCheckerLegacyImpl build() { // Configure the declaration set, and possibly alter the type provider if ProtoDecl values // are provided as they may prevent the use of certain field selection patterns against the // proto. - ImmutableList identDeclarationSet = identDeclarations.build(); - ImmutableList protoTypeMaskSet = protoTypeMasks.build(); + ImmutableSet identDeclarationSet = identDeclarations.build(); + ImmutableSet protoTypeMaskSet = protoTypeMasks.build(); if (!protoTypeMaskSet.isEmpty()) { ProtoTypeMaskTypeProvider protoTypeMaskTypeProvider = new ProtoTypeMaskTypeProvider(messageTypeProvider, protoTypeMaskSet); identDeclarationSet = - ImmutableList.builder() + ImmutableSet.builder() .addAll(identDeclarationSet) .addAll(protoTypeMaskTypeProvider.computeDeclsFromProtoTypeMasks()) .build(); @@ -375,29 +417,55 @@ public CelCheckerLegacyImpl build() { functionDeclarations.build(), Optional.fromNullable(expectedResultType), legacyProvider, - standardEnvironmentEnabled); + standardEnvironmentEnabled, + this); } private Builder() { this.celOptions = CelOptions.newBuilder().build(); - this.identDeclarations = ImmutableList.builder(); - this.functionDeclarations = ImmutableList.builder(); + this.identDeclarations = ImmutableSet.builder(); + this.functionDeclarations = ImmutableSet.builder(); this.fileTypes = ImmutableSet.builder(); this.messageTypes = ImmutableSet.builder(); - this.protoTypeMasks = ImmutableList.builder(); + this.protoTypeMasks = ImmutableSet.builder(); this.celCheckerLibraries = ImmutableSet.builder(); this.container = ""; } + + private Builder(Builder builder) { + // The following properties are either immutable or simple primitives, thus can be assigned + // directly. + this.celOptions = builder.celOptions; + this.celTypeProvider = builder.celTypeProvider; + this.container = builder.container; + this.customTypeProvider = builder.customTypeProvider; + this.expectedResultType = builder.expectedResultType; + this.standardEnvironmentEnabled = builder.standardEnvironmentEnabled; + // The following needs to be deep copied as they are collection builders + this.functionDeclarations = deepCopy(builder.functionDeclarations); + this.identDeclarations = deepCopy(builder.identDeclarations); + this.fileTypes = deepCopy(builder.fileTypes); + this.messageTypes = deepCopy(builder.messageTypes); + this.protoTypeMasks = deepCopy(builder.protoTypeMasks); + this.celCheckerLibraries = deepCopy(builder.celCheckerLibraries); + } + + private static ImmutableSet.Builder deepCopy(ImmutableSet.Builder builderToCopy) { + ImmutableSet.Builder newBuilder = ImmutableSet.builder(); + newBuilder.addAll(builderToCopy.build()); + return newBuilder; + } } private CelCheckerLegacyImpl( CelOptions celOptions, String container, - ImmutableList identDeclarations, - ImmutableList functionDeclarations, + ImmutableSet identDeclarations, + ImmutableSet functionDeclarations, Optional expectedResultType, TypeProvider typeProvider, - boolean standardEnvironmentEnabled) { + boolean standardEnvironmentEnabled, + Builder checkerBuilder) { this.celOptions = celOptions; this.container = container; this.identDeclarations = identDeclarations; @@ -405,6 +473,7 @@ private CelCheckerLegacyImpl( this.expectedResultType = expectedResultType; this.typeProvider = typeProvider; this.standardEnvironmentEnabled = standardEnvironmentEnabled; + this.checkerBuilder = new Builder(checkerBuilder); } private static ImmutableList errorsToIssues(Errors errors) { diff --git a/checker/src/main/java/dev/cel/checker/Env.java b/checker/src/main/java/dev/cel/checker/Env.java index 17d563dc8..8ce80f488 100644 --- a/checker/src/main/java/dev/cel/checker/Env.java +++ b/checker/src/main/java/dev/cel/checker/Env.java @@ -958,7 +958,7 @@ private static CelFunctionDecl sanitizeFunction(CelFunctionDecl func) { } CelFunctionDecl.Builder funcBuilder = func.toBuilder(); - ImmutableList.Builder overloadsBuilder = new ImmutableList.Builder<>(); + ImmutableSet.Builder overloadsBuilder = new ImmutableSet.Builder<>(); for (CelOverloadDecl overloadDecl : funcBuilder.overloads()) { CelOverloadDecl.Builder overloadBuilder = overloadDecl.toBuilder(); CelType resultType = overloadBuilder.build().resultType(); @@ -966,7 +966,7 @@ private static CelFunctionDecl sanitizeFunction(CelFunctionDecl func) { overloadBuilder.setResultType(getWellKnownType(resultType)); } - ImmutableList.Builder parameterTypeBuilder = ImmutableList.builder(); + ImmutableSet.Builder parameterTypeBuilder = ImmutableSet.builder(); for (CelType paramType : overloadBuilder.parameterTypes()) { if (isWellKnownType(paramType)) { parameterTypeBuilder.add(getWellKnownType(paramType)); diff --git a/checker/src/main/java/dev/cel/checker/ProtoTypeMaskTypeProvider.java b/checker/src/main/java/dev/cel/checker/ProtoTypeMaskTypeProvider.java index 07325db00..61511c38d 100644 --- a/checker/src/main/java/dev/cel/checker/ProtoTypeMaskTypeProvider.java +++ b/checker/src/main/java/dev/cel/checker/ProtoTypeMaskTypeProvider.java @@ -44,10 +44,10 @@ public final class ProtoTypeMaskTypeProvider implements CelTypeProvider { @SuppressWarnings("Immutable") private final ImmutableMap allTypes; - private final ImmutableList protoTypeMasks; + private final ImmutableSet protoTypeMasks; ProtoTypeMaskTypeProvider( - CelTypeProvider delegateProvider, ImmutableList protoTypeMasks) { + CelTypeProvider delegateProvider, ImmutableSet protoTypeMasks) { this.protoTypeMasks = protoTypeMasks; this.allTypes = computeVisibleFieldsMap(delegateProvider, protoTypeMasks); } @@ -89,7 +89,7 @@ ImmutableList computeDeclsFromProtoTypeMasks() { } private static ImmutableMap computeVisibleFieldsMap( - CelTypeProvider delegateProvider, ImmutableList protoTypeMasks) { + CelTypeProvider delegateProvider, ImmutableSet protoTypeMasks) { Map> fieldMap = new HashMap<>(); for (ProtoTypeMask typeMask : protoTypeMasks) { Optional rootType = delegateProvider.findType(typeMask.getTypeName()); diff --git a/checker/src/test/java/dev/cel/checker/BUILD.bazel b/checker/src/test/java/dev/cel/checker/BUILD.bazel index 1498a6b9b..338dcbb10 100644 --- a/checker/src/test/java/dev/cel/checker/BUILD.bazel +++ b/checker/src/test/java/dev/cel/checker/BUILD.bazel @@ -14,6 +14,7 @@ java_library( "//:auto_value", "//checker", "//checker:cel_ident_decl", + "//checker:checker_builder", "//checker:checker_legacy_environment", "//checker:proto_expr_visitor", "//checker:proto_type_mask", diff --git a/checker/src/test/java/dev/cel/checker/CelCheckerLegacyImplTest.java b/checker/src/test/java/dev/cel/checker/CelCheckerLegacyImplTest.java new file mode 100644 index 000000000..1f96367f3 --- /dev/null +++ b/checker/src/test/java/dev/cel/checker/CelCheckerLegacyImplTest.java @@ -0,0 +1,106 @@ +// Copyright 2024 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.checker; + +import static com.google.common.truth.Truth.assertThat; + +import dev.cel.common.CelFunctionDecl; +import dev.cel.common.CelOverloadDecl; +import dev.cel.common.CelVarDecl; +import dev.cel.common.types.SimpleType; +import dev.cel.compiler.CelCompilerFactory; +import dev.cel.testing.testdata.proto2.TestAllTypesProto.TestAllTypes; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class CelCheckerLegacyImplTest { + + @Test + public void toCheckerBuilder_isNewInstance() { + CelCheckerBuilder celCheckerBuilder = CelCompilerFactory.standardCelCheckerBuilder(); + CelCheckerLegacyImpl celChecker = (CelCheckerLegacyImpl) celCheckerBuilder.build(); + + CelCheckerLegacyImpl.Builder newCheckerBuilder = + (CelCheckerLegacyImpl.Builder) celChecker.toCheckerBuilder(); + + assertThat(newCheckerBuilder).isNotEqualTo(celCheckerBuilder); + } + + @Test + public void toCheckerBuilder_isImmutable() { + CelCheckerBuilder originalCheckerBuilder = CelCompilerFactory.standardCelCheckerBuilder(); + CelCheckerLegacyImpl celChecker = (CelCheckerLegacyImpl) originalCheckerBuilder.build(); + originalCheckerBuilder.addLibraries(new CelCheckerLibrary() {}); + + CelCheckerLegacyImpl.Builder newCheckerBuilder = + (CelCheckerLegacyImpl.Builder) celChecker.toCheckerBuilder(); + + assertThat(newCheckerBuilder.getCheckerLibraries().build()).isEmpty(); + } + + @Test + public void toCheckerBuilder_collectionProperties_copied() { + CelCheckerBuilder celCheckerBuilder = + CelCompilerFactory.standardCelCheckerBuilder() + .addFunctionDeclarations( + CelFunctionDecl.newFunctionDeclaration( + "test", CelOverloadDecl.newGlobalOverload("test_id", SimpleType.INT))) + .addVarDeclarations(CelVarDecl.newVarDeclaration("ident", SimpleType.INT)) + .addMessageTypes(TestAllTypes.getDescriptor()) + .addFileTypes(TestAllTypes.getDescriptor().getFile()) + .addProtoTypeMasks( + ProtoTypeMask.ofAllFields("dev.cel.testing.testdata.proto2.TestAllTypes")) + .addLibraries(new CelCheckerLibrary() {}); + CelCheckerLegacyImpl celChecker = (CelCheckerLegacyImpl) celCheckerBuilder.build(); + + CelCheckerLegacyImpl.Builder newCheckerBuilder = + (CelCheckerLegacyImpl.Builder) celChecker.toCheckerBuilder(); + + assertThat(newCheckerBuilder.getFunctionDecls().build()).hasSize(1); + assertThat(newCheckerBuilder.getIdentDecls().build()).hasSize(1); + assertThat(newCheckerBuilder.getProtoTypeMasks().build()).hasSize(1); + assertThat(newCheckerBuilder.getMessageTypes().build()).hasSize(1); + assertThat(newCheckerBuilder.getFileTypes().build()).hasSize(1); + assertThat(newCheckerBuilder.getCheckerLibraries().build()).hasSize(1); + } + + @Test + public void toCheckerBuilder_collectionProperties_areImmutable() { + CelCheckerBuilder celCheckerBuilder = CelCompilerFactory.standardCelCheckerBuilder(); + CelCheckerLegacyImpl celChecker = (CelCheckerLegacyImpl) celCheckerBuilder.build(); + CelCheckerLegacyImpl.Builder newCheckerBuilder = + (CelCheckerLegacyImpl.Builder) celChecker.toCheckerBuilder(); + + // Mutate the original builder containing collections + celCheckerBuilder.addFunctionDeclarations( + CelFunctionDecl.newFunctionDeclaration( + "test", CelOverloadDecl.newGlobalOverload("test_id", SimpleType.INT))); + celCheckerBuilder.addVarDeclarations(CelVarDecl.newVarDeclaration("ident", SimpleType.INT)); + celCheckerBuilder.addMessageTypes(TestAllTypes.getDescriptor()); + celCheckerBuilder.addFileTypes(TestAllTypes.getDescriptor().getFile()); + celCheckerBuilder.addProtoTypeMasks( + ProtoTypeMask.ofAllFields("dev.cel.testing.testdata.proto2.TestAllTypes")); + celCheckerBuilder.addLibraries(new CelCheckerLibrary() {}); + + assertThat(newCheckerBuilder.getFunctionDecls().build()).isEmpty(); + assertThat(newCheckerBuilder.getIdentDecls().build()).isEmpty(); + assertThat(newCheckerBuilder.getProtoTypeMasks().build()).isEmpty(); + assertThat(newCheckerBuilder.getMessageTypes().build()).isEmpty(); + assertThat(newCheckerBuilder.getFileTypes().build()).isEmpty(); + assertThat(newCheckerBuilder.getCheckerLibraries().build()).isEmpty(); + } +} diff --git a/checker/src/test/java/dev/cel/checker/CelCompilerImplTest.java b/checker/src/test/java/dev/cel/checker/CelCompilerImplTest.java new file mode 100644 index 000000000..b3abc4c6b --- /dev/null +++ b/checker/src/test/java/dev/cel/checker/CelCompilerImplTest.java @@ -0,0 +1,45 @@ +// Copyright 2024 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.checker; + +import static com.google.common.truth.Truth.assertThat; + +import dev.cel.common.CelFunctionDecl; +import dev.cel.common.CelOverloadDecl; +import dev.cel.common.types.SimpleType; +import dev.cel.compiler.CelCompilerBuilder; +import dev.cel.compiler.CelCompilerFactory; +import dev.cel.compiler.CelCompilerImpl; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class CelCompilerImplTest { + + @Test + public void toCompilerBuilder_isImmutable() { + CelCompilerBuilder celCompilerBuilder = CelCompilerFactory.standardCelCompilerBuilder(); + CelCompilerImpl celCompiler = (CelCompilerImpl) celCompilerBuilder.build(); + celCompilerBuilder.addFunctionDeclarations( + CelFunctionDecl.newFunctionDeclaration( + "test", CelOverloadDecl.newGlobalOverload("test_id", SimpleType.INT))); + + CelCompilerImpl.Builder newCompilerBuilder = + (CelCompilerImpl.Builder) celCompiler.toCompilerBuilder(); + + assertThat(newCompilerBuilder).isNotEqualTo(celCompilerBuilder); + } +} diff --git a/checker/src/test/java/dev/cel/checker/CelFunctionDeclTest.java b/checker/src/test/java/dev/cel/checker/CelFunctionDeclTest.java index fe386d8c7..662761f41 100644 --- a/checker/src/test/java/dev/cel/checker/CelFunctionDeclTest.java +++ b/checker/src/test/java/dev/cel/checker/CelFunctionDeclTest.java @@ -22,6 +22,7 @@ import dev.cel.common.CelFunctionDecl; import dev.cel.common.CelOverloadDecl; import dev.cel.common.types.SimpleType; +import java.util.Iterator; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -38,7 +39,7 @@ public void declareGlobalFunction_success() { assertThat(functionDecl.name()).isEqualTo("testGlobalFunction"); assertThat(functionDecl.overloads()).hasSize(1); - CelOverloadDecl overloadDecl = functionDecl.overloads().get(0); + CelOverloadDecl overloadDecl = functionDecl.overloads().iterator().next(); assertThat(overloadDecl.overloadId()).isEqualTo("overloadId"); assertThat(overloadDecl.isInstanceFunction()).isFalse(); assertThat(overloadDecl.resultType()).isEqualTo(SimpleType.BOOL); @@ -54,7 +55,7 @@ public void declareMemberFunction_success() { assertThat(functionDecl.name()).isEqualTo("testMemberFunction"); assertThat(functionDecl.overloads()).hasSize(1); - CelOverloadDecl overloadDecl = functionDecl.overloads().get(0); + CelOverloadDecl overloadDecl = functionDecl.overloads().iterator().next(); assertThat(overloadDecl.overloadId()).isEqualTo("overloadId"); assertThat(overloadDecl.isInstanceFunction()).isTrue(); assertThat(overloadDecl.resultType()).isEqualTo(SimpleType.TIMESTAMP); @@ -74,13 +75,14 @@ public void declareFunction_withBuilder_success() { assertThat(functionDecl.name()).isEqualTo("testFunction"); assertThat(functionDecl.overloads()).hasSize(2); - CelOverloadDecl memberOverloadDecl = functionDecl.overloads().get(0); + Iterator iterator = functionDecl.overloads().iterator(); + CelOverloadDecl memberOverloadDecl = iterator.next(); assertThat(memberOverloadDecl.overloadId()).isEqualTo("memberOverloadId"); assertThat(memberOverloadDecl.isInstanceFunction()).isTrue(); assertThat(memberOverloadDecl.resultType()).isEqualTo(SimpleType.INT); assertThat(memberOverloadDecl.parameterTypes()).containsExactly(SimpleType.UINT); - CelOverloadDecl globalOverloadDecl = functionDecl.overloads().get(1); + CelOverloadDecl globalOverloadDecl = iterator.next(); assertThat(globalOverloadDecl.overloadId()).isEqualTo("globalOverloadId"); assertThat(globalOverloadDecl.isInstanceFunction()).isFalse(); assertThat(globalOverloadDecl.resultType()).isEqualTo(SimpleType.STRING); diff --git a/checker/src/test/java/dev/cel/checker/ProtoTypeMaskTypeProviderTest.java b/checker/src/test/java/dev/cel/checker/ProtoTypeMaskTypeProviderTest.java index 31d0fb221..bf41c1e20 100644 --- a/checker/src/test/java/dev/cel/checker/ProtoTypeMaskTypeProviderTest.java +++ b/checker/src/test/java/dev/cel/checker/ProtoTypeMaskTypeProviderTest.java @@ -19,7 +19,6 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertThrows; -import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.protobuf.FieldMask; import com.google.rpc.context.AttributeContext; @@ -52,7 +51,7 @@ public void protoTypeMaskProvider_badFieldMask() { () -> new ProtoTypeMaskTypeProvider( celTypeProvider, - ImmutableList.of( + ImmutableSet.of( ProtoTypeMask.of( "google.rpc.context.AttributeContext", FieldMask.newBuilder().addPaths("missing").build())))); @@ -62,16 +61,16 @@ public void protoTypeMaskProvider_badFieldMask() { public void lookupFieldNames_undeclaredMessageType() { CelTypeProvider celTypeProvider = new ProtoMessageTypeProvider(); ProtoTypeMaskTypeProvider protoTypeMaskProvider = - new ProtoTypeMaskTypeProvider(celTypeProvider, ImmutableList.of()); + new ProtoTypeMaskTypeProvider(celTypeProvider, ImmutableSet.of()); assertThat(protoTypeMaskProvider.findType(ATTRIBUTE_CONTEXT_TYPE)).isEmpty(); } @Test public void lookupFieldNames_noProtoDecls() { CelTypeProvider celTypeProvider = - new ProtoMessageTypeProvider(ImmutableList.of(AttributeContext.getDescriptor())); + new ProtoMessageTypeProvider(ImmutableSet.of(AttributeContext.getDescriptor())); ProtoTypeMaskTypeProvider protoTypeMaskProvider = - new ProtoTypeMaskTypeProvider(celTypeProvider, ImmutableList.of()); + new ProtoTypeMaskTypeProvider(celTypeProvider, ImmutableSet.of()); ProtoMessageType protoType = assertTypeFound(protoTypeMaskProvider, ATTRIBUTE_CONTEXT_TYPE); assertThat(protoType.fields().stream().map(f -> f.name()).collect(toImmutableList())) .containsExactly( @@ -91,10 +90,10 @@ public void lookupFieldNames_noProtoDecls() { @Test public void lookupFieldNames_fullProtoDecl() { CelTypeProvider celTypeProvider = - new ProtoMessageTypeProvider(ImmutableList.of(AttributeContext.getDescriptor())); + new ProtoMessageTypeProvider(ImmutableSet.of(AttributeContext.getDescriptor())); ProtoTypeMaskTypeProvider protoTypeMaskProvider = new ProtoTypeMaskTypeProvider( - celTypeProvider, ImmutableList.of(ProtoTypeMask.ofAllFields(ATTRIBUTE_CONTEXT_TYPE))); + celTypeProvider, ImmutableSet.of(ProtoTypeMask.ofAllFields(ATTRIBUTE_CONTEXT_TYPE))); ProtoMessageType protoType = assertTypeFound(protoTypeMaskProvider, ATTRIBUTE_CONTEXT_TYPE); assertTypeHasFields( protoType, @@ -114,11 +113,11 @@ public void lookupFieldNames_fullProtoDecl() { @Test public void lookupFieldNames_partialProtoDecl() { CelTypeProvider celTypeProvider = - new ProtoMessageTypeProvider(ImmutableList.of(AttributeContext.getDescriptor())); + new ProtoMessageTypeProvider(ImmutableSet.of(AttributeContext.getDescriptor())); ProtoTypeMaskTypeProvider protoTypeMaskProvider = new ProtoTypeMaskTypeProvider( celTypeProvider, - ImmutableList.of( + ImmutableSet.of( ProtoTypeMask.of( "google.rpc.context.AttributeContext", FieldMask.newBuilder() @@ -169,7 +168,7 @@ public void computeDecls() { ProtoTypeMaskTypeProvider protoTypeMaskProvider = new ProtoTypeMaskTypeProvider( celTypeProvider, - ImmutableList.of( + ImmutableSet.of( ProtoTypeMask.of( "google.rpc.context.AttributeContext", FieldMask.newBuilder() @@ -191,11 +190,11 @@ public void computeDecls() { @Test public void lookupFieldType() { CelTypeProvider celTypeProvider = - new ProtoMessageTypeProvider(ImmutableList.of(AttributeContext.getDescriptor())); + new ProtoMessageTypeProvider(ImmutableSet.of(AttributeContext.getDescriptor())); ProtoTypeMaskTypeProvider protoTypeMaskProvider = new ProtoTypeMaskTypeProvider( celTypeProvider, - ImmutableList.of( + ImmutableSet.of( ProtoTypeMask.of( "google.rpc.context.AttributeContext", FieldMask.newBuilder() @@ -228,11 +227,11 @@ public void lookupFieldType() { @Test public void lookupFieldType_notExposedField() { CelTypeProvider celTypeProvider = - new ProtoMessageTypeProvider(ImmutableList.of(AttributeContext.getDescriptor())); + new ProtoMessageTypeProvider(ImmutableSet.of(AttributeContext.getDescriptor())); ProtoTypeMaskTypeProvider protoTypeMaskProvider = new ProtoTypeMaskTypeProvider( celTypeProvider, - ImmutableList.of( + ImmutableSet.of( ProtoTypeMask.of( "google.rpc.context.AttributeContext", FieldMask.newBuilder().addPaths("resource.name").build()))); @@ -243,11 +242,11 @@ public void lookupFieldType_notExposedField() { @Test public void lookupType_notExposed() { CelTypeProvider celTypeProvider = - new ProtoMessageTypeProvider(ImmutableList.of(AttributeContext.getDescriptor())); + new ProtoMessageTypeProvider(ImmutableSet.of(AttributeContext.getDescriptor())); ProtoTypeMaskTypeProvider protoTypeMaskProvider = new ProtoTypeMaskTypeProvider( celTypeProvider, - ImmutableList.of( + ImmutableSet.of( ProtoTypeMask.of( "google.rpc.context.AttributeContext", FieldMask.newBuilder().addPaths("resource.name").build()))); diff --git a/common/src/main/java/dev/cel/common/CelFunctionDecl.java b/common/src/main/java/dev/cel/common/CelFunctionDecl.java index 68b5ff406..12beb53d7 100644 --- a/common/src/main/java/dev/cel/common/CelFunctionDecl.java +++ b/common/src/main/java/dev/cel/common/CelFunctionDecl.java @@ -20,7 +20,7 @@ import dev.cel.expr.Decl; import dev.cel.expr.Decl.FunctionDecl; import com.google.auto.value.AutoValue; -import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.errorprone.annotations.CheckReturnValue; import com.google.errorprone.annotations.Immutable; @@ -36,7 +36,7 @@ public abstract class CelFunctionDecl { public abstract String name(); /** Required. List of function overloads. Must contain at least one overload. */ - public abstract ImmutableList overloads(); + public abstract ImmutableSet overloads(); /** Builder for configuring the {@link CelFunctionDecl}. */ @AutoValue.Builder @@ -46,12 +46,12 @@ public abstract static class Builder { /** Sets the function name {@link #name()} */ public abstract Builder setName(String name); - public abstract ImmutableList overloads(); + public abstract ImmutableSet overloads(); - public abstract ImmutableList.Builder overloadsBuilder(); + public abstract ImmutableSet.Builder overloadsBuilder(); @CanIgnoreReturnValue - public abstract Builder setOverloads(ImmutableList overloads); + public abstract Builder setOverloads(ImmutableSet overloads); /** Adds one or more function overloads */ @CanIgnoreReturnValue @@ -77,7 +77,7 @@ public Builder addOverloads(Iterable overloads) { /** Create a new builder to construct a {@code CelFunctionDecl} instance. */ public static Builder newBuilder() { - return new AutoValue_CelFunctionDecl.Builder().setOverloads(ImmutableList.of()); + return new AutoValue_CelFunctionDecl.Builder().setOverloads(ImmutableSet.of()); } /** Constructs a function declaration with any number of {@link CelOverloadDecl} */ diff --git a/common/src/main/java/dev/cel/common/CelOptions.java b/common/src/main/java/dev/cel/common/CelOptions.java index f4082f918..eaa812e2b 100644 --- a/common/src/main/java/dev/cel/common/CelOptions.java +++ b/common/src/main/java/dev/cel/common/CelOptions.java @@ -89,7 +89,6 @@ public abstract class CelOptions { public abstract boolean enableCelValue(); - public abstract int comprehensionMaxIterations(); public abstract Builder toBuilder(); diff --git a/common/src/main/java/dev/cel/common/CelOverloadDecl.java b/common/src/main/java/dev/cel/common/CelOverloadDecl.java index 247f86bc1..30bcac5a8 100644 --- a/common/src/main/java/dev/cel/common/CelOverloadDecl.java +++ b/common/src/main/java/dev/cel/common/CelOverloadDecl.java @@ -93,7 +93,7 @@ public abstract static class Builder { * Sets the parameter types {@link #parameterTypes()}. Note that this will override any * parameter types added via the accumulator methods {@link #addParameterTypes}. */ - public abstract Builder setParameterTypes(ImmutableList value); + public abstract Builder setParameterTypes(ImmutableSet value); public abstract CelType resultType(); diff --git a/compiler/src/main/java/dev/cel/compiler/CelCompiler.java b/compiler/src/main/java/dev/cel/compiler/CelCompiler.java index dd4d5dd10..602646ab4 100644 --- a/compiler/src/main/java/dev/cel/compiler/CelCompiler.java +++ b/compiler/src/main/java/dev/cel/compiler/CelCompiler.java @@ -57,4 +57,6 @@ default CelValidationResult compile(String expression, String description) { throw new IllegalStateException("this method must only be called when !hasError()", ex); } } + + CelCompilerBuilder toCompilerBuilder(); } diff --git a/compiler/src/main/java/dev/cel/compiler/CelCompilerImpl.java b/compiler/src/main/java/dev/cel/compiler/CelCompilerImpl.java index 5a99054a6..ac81f5d0c 100644 --- a/compiler/src/main/java/dev/cel/compiler/CelCompilerImpl.java +++ b/compiler/src/main/java/dev/cel/compiler/CelCompilerImpl.java @@ -81,6 +81,21 @@ public void accept(EnvVisitor envVisitor) { } } + @Override + public CelCompilerBuilder toCompilerBuilder() { + return newBuilder(toParserBuilder(), toCheckerBuilder()); + } + + @Override + public CelCheckerBuilder toCheckerBuilder() { + return checker.toCheckerBuilder(); + } + + @Override + public CelParserBuilder toParserBuilder() { + return parser.toParserBuilder(); + } + /** Combines a prebuilt {@link CelParser} and {@link CelChecker} into {@link CelCompilerImpl}. */ static CelCompilerImpl combine(CelParser parser, CelChecker checker) { return new CelCompilerImpl(parser, checker); diff --git a/parser/src/main/java/dev/cel/parser/CelParser.java b/parser/src/main/java/dev/cel/parser/CelParser.java index 53879d11b..da1b7ba2a 100644 --- a/parser/src/main/java/dev/cel/parser/CelParser.java +++ b/parser/src/main/java/dev/cel/parser/CelParser.java @@ -52,4 +52,6 @@ default CelValidationResult parse(String expression) { */ @CheckReturnValue CelValidationResult parse(CelSource source); + + CelParserBuilder toParserBuilder(); } diff --git a/parser/src/main/java/dev/cel/parser/CelParserImpl.java b/parser/src/main/java/dev/cel/parser/CelParserImpl.java index 5d9944397..f630f7137 100644 --- a/parser/src/main/java/dev/cel/parser/CelParserImpl.java +++ b/parser/src/main/java/dev/cel/parser/CelParserImpl.java @@ -16,6 +16,7 @@ import static com.google.common.base.Preconditions.checkNotNull; +import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; @@ -50,6 +51,10 @@ public final class CelParserImpl implements CelParser { // Specific options for limits on parsing power. private final CelOptions options; + // Builder is mutable by design. APIs must make defensive copies in and out of this class. + @SuppressWarnings("Immutable") + private final Builder parserBuilder; + /** Creates a new {@link Builder}. */ public static CelParserBuilder newBuilder() { return new Builder().setOptions(CelOptions.DEFAULT); @@ -65,6 +70,11 @@ public CelValidationResult parse(CelSource source) { return Parser.parse(this, source, getOptions()); } + @Override + public CelParserBuilder toParserBuilder() { + return new Builder(parserBuilder); + } + Optional findMacro(String key) { return Optional.ofNullable(macros.get(key)); } @@ -136,6 +146,23 @@ public CelOptions getOptions() { return this.options; } + // The following getters exist for asserting immutability for collections held by this builder, + // and shouldn't be exposed to the public. + @VisibleForTesting + List getStandardMacros() { + return this.standardMacros; + } + + @VisibleForTesting + Map getMacros() { + return this.macros; + } + + @VisibleForTesting + ImmutableSet.Builder getParserLibraries() { + return this.celParserLibraries; + } + @Override @CheckReturnValue public CelParserImpl build() { @@ -149,7 +176,7 @@ public CelParserImpl build() { standardMacros.stream() .map(CelStandardMacro::getDefinition) .forEach(celMacro -> builder.put(celMacro.getKey(), celMacro)); - return new CelParserImpl(builder.buildOrThrow(), checkNotNull(options)); + return new CelParserImpl(builder.buildOrThrow(), checkNotNull(options), this); } private Builder() { @@ -157,10 +184,23 @@ private Builder() { this.celParserLibraries = ImmutableSet.builder(); this.standardMacros = new ArrayList<>(); } + + private Builder(Builder builder) { + // The following properties are either immutable or simple primitives, thus can be assigned + // directly. + this.options = builder.options; + // The following needs to be deep copied as they are collection builders + this.macros = new HashMap<>(builder.macros); + this.standardMacros = new ArrayList<>(builder.standardMacros); + this.celParserLibraries = ImmutableSet.builder(); + this.celParserLibraries.addAll(builder.celParserLibraries.build()); + } } - private CelParserImpl(ImmutableMap macros, CelOptions options) { + private CelParserImpl( + ImmutableMap macros, CelOptions options, Builder parserBuilder) { this.macros = macros; this.options = options; + this.parserBuilder = new Builder(parserBuilder); } } diff --git a/parser/src/test/java/dev/cel/parser/CelParserImplTest.java b/parser/src/test/java/dev/cel/parser/CelParserImplTest.java index 7c01c3611..f12fef292 100644 --- a/parser/src/test/java/dev/cel/parser/CelParserImplTest.java +++ b/parser/src/test/java/dev/cel/parser/CelParserImplTest.java @@ -271,4 +271,44 @@ public void parse_macroArgumentContainsSyntaxError_throws(String expression) { assertThat(parseResult.getErrorString()).containsMatch("ERROR: .*mismatched input ','"); assertThrows(CelValidationException.class, parseResult::getAst); } + + @Test + public void toParserBuilder_isNewInstance() { + CelParserBuilder celParserBuilder = CelParserFactory.standardCelParserBuilder(); + CelParserImpl celParser = (CelParserImpl) celParserBuilder.build(); + + CelParserImpl.Builder newParserBuilder = (CelParserImpl.Builder) celParser.toParserBuilder(); + + assertThat(newParserBuilder).isNotEqualTo(celParserBuilder); + } + + @Test + public void toParserBuilder_isImmutable() { + CelParserBuilder originalParserBuilder = CelParserFactory.standardCelParserBuilder(); + CelParserImpl celParser = (CelParserImpl) originalParserBuilder.build(); + originalParserBuilder.addLibraries(new CelParserLibrary() {}); + + CelParserImpl.Builder newParserBuilder = (CelParserImpl.Builder) celParser.toParserBuilder(); + + assertThat(newParserBuilder.getParserLibraries().build()).isEmpty(); + } + + @Test + public void toParserBuilder_collectionProperties_copied() { + CelParserBuilder celParserBuilder = + CelParserFactory.standardCelParserBuilder() + .setStandardMacros(CelStandardMacro.STANDARD_MACROS) + .addMacros( + CelMacro.newGlobalMacro( + "test", 1, (a, b, c) -> Optional.of(CelExpr.newBuilder().build()))) + .addLibraries(new CelParserLibrary() {}); + CelParserImpl celParser = (CelParserImpl) celParserBuilder.build(); + + CelParserImpl.Builder newParserBuilder = (CelParserImpl.Builder) celParser.toParserBuilder(); + + assertThat(newParserBuilder.getStandardMacros()) + .hasSize(CelStandardMacro.STANDARD_MACROS.size()); + assertThat(newParserBuilder.getMacros()).hasSize(1); + assertThat(newParserBuilder.getParserLibraries().build()).hasSize(1); + } } diff --git a/runtime/src/main/java/dev/cel/runtime/CelRuntime.java b/runtime/src/main/java/dev/cel/runtime/CelRuntime.java index 01260fb79..2b28d015b 100644 --- a/runtime/src/main/java/dev/cel/runtime/CelRuntime.java +++ b/runtime/src/main/java/dev/cel/runtime/CelRuntime.java @@ -37,6 +37,8 @@ public interface CelRuntime { @CanIgnoreReturnValue Program createProgram(CelAbstractSyntaxTree ast) throws CelEvaluationException; + CelRuntimeBuilder toRuntimeBuilder(); + /** Creates an evaluable {@code Program} instance which is thread-safe and immutable. */ @AutoValue @Immutable diff --git a/runtime/src/main/java/dev/cel/runtime/CelRuntimeLegacyImpl.java b/runtime/src/main/java/dev/cel/runtime/CelRuntimeLegacyImpl.java index 5f8f3f259..19059506a 100644 --- a/runtime/src/main/java/dev/cel/runtime/CelRuntimeLegacyImpl.java +++ b/runtime/src/main/java/dev/cel/runtime/CelRuntimeLegacyImpl.java @@ -17,6 +17,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; +import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; @@ -43,6 +44,8 @@ import dev.cel.common.values.CelValueProvider; import dev.cel.common.values.ProtoMessageValueProvider; import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; import java.util.Optional; import java.util.function.Function; import org.jspecify.nullness.Nullable; @@ -60,12 +63,21 @@ public final class CelRuntimeLegacyImpl implements CelRuntime { private final Interpreter interpreter; private final CelOptions options; + // Builder is mutable by design. APIs must guarantee a new instance to be returned. + // CEL-Internal-4 + private final Builder runtimeBuilder; + @Override public CelRuntime.Program createProgram(CelAbstractSyntaxTree ast) { checkState(ast.isChecked(), "programs must be created from checked expressions"); return CelRuntime.Program.from(interpreter.createInterpretable(ast), options); } + @Override + public CelRuntimeBuilder toRuntimeBuilder() { + return new Builder(runtimeBuilder); + } + /** Create a new builder for constructing a {@code CelRuntime} instance. */ public static CelRuntimeBuilder newBuilder() { return new Builder(); @@ -75,7 +87,7 @@ public static CelRuntimeBuilder newBuilder() { public static final class Builder implements CelRuntimeBuilder { private final ImmutableSet.Builder fileTypes; - private final ImmutableMap.Builder functionBindings; + private final HashMap functionBindings; private final ImmutableSet.Builder celRuntimeLibraries; @SuppressWarnings("unused") @@ -99,7 +111,7 @@ public CelRuntimeBuilder addFunctionBindings(CelFunctionBinding... bindings) { @Override public CelRuntimeBuilder addFunctionBindings(Iterable bindings) { - bindings.forEach(o -> functionBindings.put(o.getOverloadId(), o)); + bindings.forEach(o -> functionBindings.putIfAbsent(o.getOverloadId(), o)); return this; } @@ -168,6 +180,23 @@ public CelRuntimeBuilder setExtensionRegistry(ExtensionRegistry extensionRegistr return this; } + // The following getters exist for asserting immutability for collections held by this builder, + // and shouldn't be exposed to the public. + @VisibleForTesting + Map getFunctionBindings() { + return this.functionBindings; + } + + @VisibleForTesting + ImmutableSet.Builder getRuntimeLibraries() { + return this.celRuntimeLibraries; + } + + @VisibleForTesting + ImmutableSet.Builder getFileTypes() { + return this.fileTypes; + } + /** Build a new {@code CelRuntimeLegacyImpl} instance from the builder config. */ @Override public CelRuntimeLegacyImpl build() { @@ -203,7 +232,8 @@ public CelRuntimeLegacyImpl build() { StandardFunctions.add(dispatcher, dynamicProto, options); } - ImmutableMap functionBindingMap = functionBindings.buildOrThrow(); + ImmutableMap functionBindingMap = + ImmutableMap.copyOf(functionBindings); functionBindingMap.forEach( (String overloadId, CelFunctionBinding func) -> dispatcher.add( @@ -238,7 +268,7 @@ public CelRuntimeLegacyImpl build() { } return new CelRuntimeLegacyImpl( - new DefaultInterpreter(runtimeTypeProvider, dispatcher, options), options); + new DefaultInterpreter(runtimeTypeProvider, dispatcher, options), options, this); } private static CelDescriptorPool newDescriptorPool( @@ -264,15 +294,35 @@ private static ProtoMessageFactory maybeCombineMessageFactory( private Builder() { this.options = CelOptions.newBuilder().build(); this.fileTypes = ImmutableSet.builder(); - this.functionBindings = ImmutableMap.builder(); + this.functionBindings = new HashMap<>(); this.celRuntimeLibraries = ImmutableSet.builder(); this.extensionRegistry = ExtensionRegistry.getEmptyRegistry(); this.customTypeFactory = null; } + + private Builder(Builder builder) { + // The following properties are either immutable or simple primitives, thus can be assigned + // directly. + this.options = builder.options; + this.extensionRegistry = builder.extensionRegistry; + this.customTypeFactory = builder.customTypeFactory; + // The following needs to be deep copied as they are collection builders + this.fileTypes = deepCopy(builder.fileTypes); + this.celRuntimeLibraries = deepCopy(builder.celRuntimeLibraries); + this.functionBindings = new HashMap<>(builder.functionBindings); + } + + private static ImmutableSet.Builder deepCopy(ImmutableSet.Builder builderToCopy) { + ImmutableSet.Builder newBuilder = ImmutableSet.builder(); + newBuilder.addAll(builderToCopy.build()); + return newBuilder; + } } - private CelRuntimeLegacyImpl(Interpreter interpreter, CelOptions options) { + private CelRuntimeLegacyImpl( + Interpreter interpreter, CelOptions options, Builder runtimeBuilder) { this.interpreter = interpreter; this.options = options; + this.runtimeBuilder = new Builder(runtimeBuilder); } } diff --git a/runtime/src/test/java/dev/cel/runtime/CelRuntimeLegacyImplTest.java b/runtime/src/test/java/dev/cel/runtime/CelRuntimeLegacyImplTest.java index 02fd0ae7c..2ce5e4d0b 100644 --- a/runtime/src/test/java/dev/cel/runtime/CelRuntimeLegacyImplTest.java +++ b/runtime/src/test/java/dev/cel/runtime/CelRuntimeLegacyImplTest.java @@ -19,6 +19,8 @@ import dev.cel.common.CelException; import dev.cel.compiler.CelCompiler; import dev.cel.compiler.CelCompilerFactory; +import dev.cel.runtime.CelRuntime.CelFunctionBinding; +import dev.cel.testing.testdata.proto3.TestAllTypesProto.TestAllTypes; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; @@ -35,4 +37,62 @@ public void evalException() throws CelException { CelEvaluationException e = Assert.assertThrows(CelEvaluationException.class, program::eval); assertThat(e).hasCauseThat().isInstanceOf(ArithmeticException.class); } + + @Test + public void toRuntimeBuilder_isNewInstance() { + CelRuntimeBuilder celRuntimeBuilder = CelRuntimeFactory.standardCelRuntimeBuilder(); + CelRuntimeLegacyImpl celRuntime = (CelRuntimeLegacyImpl) celRuntimeBuilder.build(); + + CelRuntimeLegacyImpl.Builder newRuntimeBuilder = + (CelRuntimeLegacyImpl.Builder) celRuntime.toRuntimeBuilder(); + + assertThat(newRuntimeBuilder).isNotEqualTo(celRuntimeBuilder); + } + + @Test + public void toRuntimeBuilder_isImmutable() { + CelRuntimeBuilder originalRuntimeBuilder = CelRuntimeFactory.standardCelRuntimeBuilder(); + CelRuntimeLegacyImpl celRuntime = (CelRuntimeLegacyImpl) originalRuntimeBuilder.build(); + originalRuntimeBuilder.addLibraries(runtimeBuilder -> {}); + + CelRuntimeLegacyImpl.Builder newRuntimeBuilder = + (CelRuntimeLegacyImpl.Builder) celRuntime.toRuntimeBuilder(); + + assertThat(newRuntimeBuilder.getRuntimeLibraries().build()).isEmpty(); + } + + @Test + public void toRuntimeBuilder_collectionProperties_copied() { + CelRuntimeBuilder celRuntimeBuilder = CelRuntimeFactory.standardCelRuntimeBuilder(); + celRuntimeBuilder.addMessageTypes(TestAllTypes.getDescriptor()); + celRuntimeBuilder.addFileTypes(TestAllTypes.getDescriptor().getFile()); + celRuntimeBuilder.addFunctionBindings(CelFunctionBinding.from("test", Integer.class, arg -> 1)); + celRuntimeBuilder.addLibraries(runtimeBuilder -> {}); + CelRuntimeLegacyImpl celRuntime = (CelRuntimeLegacyImpl) celRuntimeBuilder.build(); + + CelRuntimeLegacyImpl.Builder newRuntimeBuilder = + (CelRuntimeLegacyImpl.Builder) celRuntime.toRuntimeBuilder(); + + assertThat(newRuntimeBuilder.getFunctionBindings()).hasSize(1); + assertThat(newRuntimeBuilder.getRuntimeLibraries().build()).hasSize(1); + assertThat(newRuntimeBuilder.getFileTypes().build()).hasSize(6); + } + + @Test + public void toRuntimeBuilder_collectionProperties_areImmutable() { + CelRuntimeBuilder celRuntimeBuilder = CelRuntimeFactory.standardCelRuntimeBuilder(); + CelRuntimeLegacyImpl celRuntime = (CelRuntimeLegacyImpl) celRuntimeBuilder.build(); + CelRuntimeLegacyImpl.Builder newRuntimeBuilder = + (CelRuntimeLegacyImpl.Builder) celRuntime.toRuntimeBuilder(); + + // Mutate the original builder containing collections + celRuntimeBuilder.addMessageTypes(TestAllTypes.getDescriptor()); + celRuntimeBuilder.addFileTypes(TestAllTypes.getDescriptor().getFile()); + celRuntimeBuilder.addFunctionBindings(CelFunctionBinding.from("test", Integer.class, arg -> 1)); + celRuntimeBuilder.addLibraries(runtimeBuilder -> {}); + + assertThat(newRuntimeBuilder.getFunctionBindings()).isEmpty(); + assertThat(newRuntimeBuilder.getRuntimeLibraries().build()).isEmpty(); + assertThat(newRuntimeBuilder.getFileTypes().build()).isEmpty(); + } } From c916a111a2d75f1fa6b047a50991170d81bcb345 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Mon, 12 Feb 2024 11:39:14 -0800 Subject: [PATCH 026/486] Add capability to evaluate cel.block calls in the runtime PiperOrigin-RevId: 606316063 --- .../dev/cel/optimizer/optimizers/BUILD.bazel | 3 + .../optimizers/SubexpressionOptimizer.java | 15 ++ .../dev/cel/optimizer/optimizers/BUILD.bazel | 3 + .../SubexpressionOptimizerTest.java | 252 ++++++++++++++++++ .../dev/cel/runtime/DefaultInterpreter.java | 22 +- 5 files changed, 292 insertions(+), 3 deletions(-) diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel b/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel index 10096a73d..77b3d289b 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel @@ -42,8 +42,11 @@ java_library( "//bundle:cel", "//checker:checker_legacy_environment", "//common", + "//common:compiler_common", "//common/ast", "//common/navigation", + "//common/types", + "//common/types:type_providers", "//optimizer:ast_optimizer", "//optimizer:mutable_ast", "//parser:operator", diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java index 8d057c74a..241680bb2 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java @@ -19,12 +19,15 @@ import static java.util.Arrays.stream; import com.google.auto.value.AutoValue; +import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Streams; import dev.cel.bundle.Cel; import dev.cel.checker.Standard; import dev.cel.common.CelAbstractSyntaxTree; +import dev.cel.common.CelFunctionDecl; +import dev.cel.common.CelOverloadDecl; import dev.cel.common.CelSource; import dev.cel.common.ast.CelExpr; import dev.cel.common.ast.CelExpr.CelIdent; @@ -32,6 +35,9 @@ import dev.cel.common.navigation.CelNavigableAst; import dev.cel.common.navigation.CelNavigableExpr; import dev.cel.common.navigation.CelNavigableExpr.TraversalOrder; +import dev.cel.common.types.CelType; +import dev.cel.common.types.ListType; +import dev.cel.common.types.SimpleType; import dev.cel.optimizer.CelAstOptimizer; import dev.cel.optimizer.MutableAst; import dev.cel.parser.Operator; @@ -64,6 +70,7 @@ public class SubexpressionOptimizer implements CelAstOptimizer { new SubexpressionOptimizer(SubexpressionOptimizerOptions.newBuilder().build()); private static final String BIND_IDENTIFIER_PREFIX = "@r"; private static final String MANGLED_COMPREHENSION_IDENTIFIER_PREFIX = "@c"; + private static final String CEL_BLOCK_FUNCTION = "cel.@block"; private static final ImmutableSet CSE_ALLOWED_FUNCTIONS = Streams.concat( stream(Operator.values()).map(Operator::getFunction), @@ -325,6 +332,14 @@ private CelExpr normalizeForEquality(CelExpr celExpr) { return mutableAst.clearExprIds(celExpr); } + @VisibleForTesting + static CelFunctionDecl newCelBlockFunctionDecl(CelType resultType) { + return CelFunctionDecl.newFunctionDeclaration( + CEL_BLOCK_FUNCTION, + CelOverloadDecl.newGlobalOverload( + "cel_block_list", resultType, ListType.create(SimpleType.DYN), resultType)); + } + /** Options to configure how Common Subexpression Elimination behave. */ @AutoValue public abstract static class SubexpressionOptimizerOptions { diff --git a/optimizer/src/test/java/dev/cel/optimizer/optimizers/BUILD.bazel b/optimizer/src/test/java/dev/cel/optimizer/optimizers/BUILD.bazel index a4f8143f8..c907ef1f7 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/optimizers/BUILD.bazel +++ b/optimizer/src/test/java/dev/cel/optimizer/optimizers/BUILD.bazel @@ -13,11 +13,13 @@ java_library( "//common:compiler_common", "//common:options", "//common/ast", + "//common/navigation", "//common/resources/testdata/proto3:test_all_types_java_proto", "//common/types", "//extensions", "//extensions:optional_library", "//optimizer", + "//optimizer:mutable_ast", "//optimizer:optimization_exception", "//optimizer:optimizer_builder", "//optimizer/optimizers:common_subexpression_elimination", @@ -25,6 +27,7 @@ java_library( "//parser:macro", "//parser:operator", "//parser:unparser", + "//runtime", "@maven//:com_google_guava_guava", "@maven//:com_google_testparameterinjector_test_parameter_injector", "@maven//:junit_junit", diff --git a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java index 9b516bdd5..70b12f536 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java @@ -29,8 +29,15 @@ import dev.cel.common.CelAbstractSyntaxTree; import dev.cel.common.CelFunctionDecl; import dev.cel.common.CelOptions; +import dev.cel.common.CelOverloadDecl; +import dev.cel.common.CelValidationException; +import dev.cel.common.CelVarDecl; import dev.cel.common.ast.CelConstant; import dev.cel.common.ast.CelExpr; +import dev.cel.common.ast.CelExpr.ExprKind.Kind; +import dev.cel.common.navigation.CelNavigableAst; +import dev.cel.common.navigation.CelNavigableExpr; +import dev.cel.common.types.ListType; import dev.cel.common.types.OptionalType; import dev.cel.common.types.SimpleType; import dev.cel.common.types.StructTypeReference; @@ -39,14 +46,19 @@ import dev.cel.optimizer.CelOptimizationException; import dev.cel.optimizer.CelOptimizer; import dev.cel.optimizer.CelOptimizerFactory; +import dev.cel.optimizer.MutableAst; import dev.cel.optimizer.optimizers.SubexpressionOptimizer.SubexpressionOptimizerOptions; import dev.cel.parser.CelStandardMacro; import dev.cel.parser.CelUnparser; import dev.cel.parser.CelUnparserFactory; import dev.cel.parser.Operator; +import dev.cel.runtime.CelRuntime; +import dev.cel.runtime.CelRuntime.CelFunctionBinding; +import dev.cel.runtime.CelRuntimeFactory; import dev.cel.testing.testdata.proto3.TestAllTypesProto.NestedTestAllTypes; import dev.cel.testing.testdata.proto3.TestAllTypesProto.TestAllTypes; import java.util.Optional; +import java.util.concurrent.atomic.AtomicInteger; import org.junit.Test; import org.junit.runner.RunWith; @@ -55,6 +67,37 @@ public class SubexpressionOptimizerTest { private static final Cel CEL = newCelBuilder().build(); + private static final Cel CEL_FOR_EVALUATING_BLOCK = + CelFactory.standardCelBuilder() + .setStandardMacros(CelStandardMacro.STANDARD_MACROS) + .addFunctionDeclarations( + // These are test only declarations, as the actual function is made internal using @ + // symbol. + // If the main function declaration needs updating, be sure to update the test + // declaration as well. + CelFunctionDecl.newFunctionDeclaration( + "cel.block", + CelOverloadDecl.newGlobalOverload( + "block_test_only_overload", + SimpleType.DYN, + ListType.create(SimpleType.DYN), + SimpleType.DYN)), + SubexpressionOptimizer.newCelBlockFunctionDecl(SimpleType.DYN), + CelFunctionDecl.newFunctionDeclaration( + "get_true", + CelOverloadDecl.newGlobalOverload("get_true_overload", SimpleType.BOOL))) + // Similarly, this is a test only decl (index0 -> @index0) + .addVarDeclarations( + CelVarDecl.newVarDeclaration("index0", SimpleType.DYN), + CelVarDecl.newVarDeclaration("index1", SimpleType.DYN), + CelVarDecl.newVarDeclaration("index2", SimpleType.DYN), + CelVarDecl.newVarDeclaration("@index0", SimpleType.DYN), + CelVarDecl.newVarDeclaration("@index1", SimpleType.DYN), + CelVarDecl.newVarDeclaration("@index2", SimpleType.DYN)) + .addMessageTypes(TestAllTypes.getDescriptor()) + .addVar("msg", StructTypeReference.create(TestAllTypes.getDescriptor().getFullName())) + .build(); + private static final CelOptimizer CEL_OPTIMIZER = CelOptimizerFactory.standardCelOptimizerBuilder(CEL) .addAstOptimizers( @@ -659,4 +702,213 @@ public void iterationLimitReached_throws() throws Exception { .optimize(ast)); assertThat(e).hasMessageThat().isEqualTo("Optimization failure: Max iteration count reached."); } + + private enum BlockTestCase { + BOOL_LITERAL("cel.block([true, false], index0 || index1)"), + STRING_CONCAT("cel.block(['a' + 'b', index0 + 'c'], index1 + 'd') == 'abcd'"), + + BLOCK_WITH_EXISTS_TRUE("cel.block([[1, 2, 3], [3, 4, 5].exists(e, e in index0)], index1)"), + BLOCK_WITH_EXISTS_FALSE("cel.block([[1, 2, 3], ![4, 5].exists(e, e in index0)], index1)"), + ; + + private final String source; + + BlockTestCase(String source) { + this.source = source; + } + } + + @Test + public void block_success(@TestParameter BlockTestCase testCase) throws Exception { + CelAbstractSyntaxTree ast = compileUsingInternalFunctions(testCase.source); + + Object evaluatedResult = CEL_FOR_EVALUATING_BLOCK.createProgram(ast).eval(); + + assertThat(evaluatedResult).isNotNull(); + } + + @Test + @SuppressWarnings("Immutable") // Test only + public void lazyEval_blockIndexNeverReferenced() throws Exception { + AtomicInteger invocation = new AtomicInteger(); + CelRuntime celRuntime = + CelRuntimeFactory.standardCelRuntimeBuilder() + .addMessageTypes(TestAllTypes.getDescriptor()) + .addFunctionBindings( + CelFunctionBinding.from( + "get_true_overload", + ImmutableList.of(), + arg -> { + invocation.getAndIncrement(); + return true; + })) + .build(); + CelAbstractSyntaxTree ast = + compileUsingInternalFunctions( + "cel.block([get_true()], has(msg.single_int64) ? index0 : false)"); + + boolean result = + (boolean) + celRuntime + .createProgram(ast) + .eval(ImmutableMap.of("msg", TestAllTypes.getDefaultInstance())); + + assertThat(result).isFalse(); + assertThat(invocation.get()).isEqualTo(0); + } + + @Test + @SuppressWarnings("Immutable") // Test only + public void lazyEval_blockIndexEvaluatedOnlyOnce() throws Exception { + AtomicInteger invocation = new AtomicInteger(); + CelRuntime celRuntime = + CelRuntimeFactory.standardCelRuntimeBuilder() + .addMessageTypes(TestAllTypes.getDescriptor()) + .addFunctionBindings( + CelFunctionBinding.from( + "get_true_overload", + ImmutableList.of(), + arg -> { + invocation.getAndIncrement(); + return true; + })) + .build(); + CelAbstractSyntaxTree ast = + compileUsingInternalFunctions("cel.block([get_true()], index0 && index0 && index0)"); + + boolean result = (boolean) celRuntime.createProgram(ast).eval(); + + assertThat(result).isTrue(); + assertThat(invocation.get()).isEqualTo(1); + } + + @Test + @SuppressWarnings("Immutable") // Test only + public void lazyEval_multipleBlockIndices_inResultExpr() throws Exception { + AtomicInteger invocation = new AtomicInteger(); + CelRuntime celRuntime = + CelRuntimeFactory.standardCelRuntimeBuilder() + .addMessageTypes(TestAllTypes.getDescriptor()) + .addFunctionBindings( + CelFunctionBinding.from( + "get_true_overload", + ImmutableList.of(), + arg -> { + invocation.getAndIncrement(); + return true; + })) + .build(); + CelAbstractSyntaxTree ast = + compileUsingInternalFunctions( + "cel.block([get_true(), get_true(), get_true()], index0 && index0 && index1 && index1" + + " && index2 && index2)"); + + boolean result = (boolean) celRuntime.createProgram(ast).eval(); + + assertThat(result).isTrue(); + assertThat(invocation.get()).isEqualTo(3); + } + + @Test + @SuppressWarnings("Immutable") // Test only + public void lazyEval_multipleBlockIndices_cascaded() throws Exception { + AtomicInteger invocation = new AtomicInteger(); + CelRuntime celRuntime = + CelRuntimeFactory.standardCelRuntimeBuilder() + .addMessageTypes(TestAllTypes.getDescriptor()) + .addFunctionBindings( + CelFunctionBinding.from( + "get_true_overload", + ImmutableList.of(), + arg -> { + invocation.getAndIncrement(); + return true; + })) + .build(); + CelAbstractSyntaxTree ast = + compileUsingInternalFunctions("cel.block([get_true(), index0, index1], index2)"); + + boolean result = (boolean) celRuntime.createProgram(ast).eval(); + + assertThat(result).isTrue(); + assertThat(invocation.get()).isEqualTo(1); + } + + @Test + @TestParameters("{source: 'cel.block([])'}") + @TestParameters("{source: 'cel.block([1])'}") + @TestParameters("{source: 'cel.block(1, 2)'}") + @TestParameters("{source: 'cel.block(1, [1])'}") + public void block_invalidArguments_throws(String source) { + CelValidationException e = + assertThrows(CelValidationException.class, () -> compileUsingInternalFunctions(source)); + + assertThat(e).hasMessageThat().contains("found no matching overload for 'cel.block'"); + } + + @Test + public void blockIndex_invalidArgument_throws() { + CelValidationException e = + assertThrows( + CelValidationException.class, + () -> compileUsingInternalFunctions("cel.block([1], index)")); + + assertThat(e).hasMessageThat().contains("undeclared reference"); + } + + /** + * Converts AST containing cel.block related test functions to internal functions (e.g: cel.block + * -> cel.@block) + */ + private static CelAbstractSyntaxTree compileUsingInternalFunctions(String expression) + throws CelValidationException { + MutableAst mutableAst = MutableAst.newInstance(1000); + CelAbstractSyntaxTree astToModify = CEL_FOR_EVALUATING_BLOCK.compile(expression).getAst(); + while (true) { + CelExpr celExpr = + CelNavigableAst.fromAst(astToModify) + .getRoot() + .allNodes() + .filter(node -> node.getKind().equals(Kind.CALL)) + .map(CelNavigableExpr::expr) + .filter(expr -> expr.call().function().equals("cel.block")) + .findAny() + .orElse(null); + if (celExpr == null) { + break; + } + astToModify = + mutableAst.replaceSubtree( + astToModify, + celExpr.toBuilder() + .setCall(celExpr.call().toBuilder().setFunction("cel.@block").build()) + .build(), + celExpr.id()); + } + + while (true) { + CelExpr celExpr = + CelNavigableAst.fromAst(astToModify) + .getRoot() + .allNodes() + .filter(node -> node.getKind().equals(Kind.IDENT)) + .map(CelNavigableExpr::expr) + .filter(expr -> expr.ident().name().startsWith("index")) + .findAny() + .orElse(null); + if (celExpr == null) { + break; + } + String internalIdentName = "@" + celExpr.ident().name(); + astToModify = + mutableAst.replaceSubtree( + astToModify, + celExpr.toBuilder() + .setIdent(celExpr.ident().toBuilder().setName(internalIdentName).build()) + .build(), + celExpr.id()); + } + + return CEL_FOR_EVALUATING_BLOCK.check(astToModify).getAst(); + } } diff --git a/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java b/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java index f27882eda..3c4c0003a 100644 --- a/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java +++ b/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java @@ -34,7 +34,6 @@ import dev.cel.common.ast.CelExpr.CelCreateList; import dev.cel.common.ast.CelExpr.CelCreateMap; import dev.cel.common.ast.CelExpr.CelCreateStruct; -import dev.cel.common.ast.CelExpr.CelIdent; import dev.cel.common.ast.CelExpr.CelSelect; import dev.cel.common.ast.CelExpr.ExprKind; import dev.cel.common.ast.CelReference; @@ -194,7 +193,7 @@ private IntermediateResult evalInternal(ExecutionFrame frame, CelExpr expr) result = IntermediateResult.create(evalConstant(frame, expr, expr.constant())); break; case IDENT: - result = evalIdent(frame, expr, expr.ident()); + result = evalIdent(frame, expr); break; case SELECT: result = evalSelect(frame, expr, expr.select()); @@ -257,7 +256,7 @@ private Object evalConstant( } } - private IntermediateResult evalIdent(ExecutionFrame frame, CelExpr expr, CelIdent unusedIdent) + private IntermediateResult evalIdent(ExecutionFrame frame, CelExpr expr) throws InterpreterException { CelReference reference = ast.getReferenceOrThrow(expr.id()); if (reference.value().isPresent()) { @@ -371,6 +370,8 @@ private IntermediateResult evalCall(ExecutionFrame frame, CelExpr expr, CelCall return result.get(); } break; + case "cel_block_list": + return evalCelBlock(frame, expr, callExpr); default: break; } @@ -846,6 +847,21 @@ private IntermediateResult evalComprehension( frame.popScope(); return result; } + + private IntermediateResult evalCelBlock( + ExecutionFrame frame, CelExpr unusedExpr, CelCall blockCall) throws InterpreterException { + CelCreateList exprList = blockCall.args().get(0).createList(); + ImmutableMap.Builder blockList = ImmutableMap.builder(); + for (int index = 0; index < exprList.elements().size(); index++) { + // Register the block indices as lazily evaluated expressions stored as unique identifiers. + blockList.put( + "@index" + index, + IntermediateResult.create(new LazyExpression(exprList.elements().get(index)))); + } + frame.pushScope(blockList.buildOrThrow()); + + return evalInternal(frame, blockCall.args().get(1)); + } } /** Contains a CelExpr that is to be lazily evaluated. */ From f98b582ab7bb96dd468f452d12dd59f68ccc06fa Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Tue, 13 Feb 2024 09:56:44 -0800 Subject: [PATCH 027/486] Add height property to CelNavigableExpr PiperOrigin-RevId: 606657258 --- .../dev/cel/common/navigation/BUILD.bazel | 1 + .../common/navigation/CelNavigableExpr.java | 45 +++- .../navigation/CelNavigableExprVisitor.java | 101 +++++---- .../CelNavigableExprVisitorTest.java | 206 ++++++++++++++++++ 4 files changed, 308 insertions(+), 45 deletions(-) diff --git a/common/src/main/java/dev/cel/common/navigation/BUILD.bazel b/common/src/main/java/dev/cel/common/navigation/BUILD.bazel index a9ca1c4e9..07604c5f7 100644 --- a/common/src/main/java/dev/cel/common/navigation/BUILD.bazel +++ b/common/src/main/java/dev/cel/common/navigation/BUILD.bazel @@ -20,6 +20,7 @@ java_library( "//:auto_value", "//common", "//common/ast", + "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", ], ) diff --git a/common/src/main/java/dev/cel/common/navigation/CelNavigableExpr.java b/common/src/main/java/dev/cel/common/navigation/CelNavigableExpr.java index 326f8b78f..249a31262 100644 --- a/common/src/main/java/dev/cel/common/navigation/CelNavigableExpr.java +++ b/common/src/main/java/dev/cel/common/navigation/CelNavigableExpr.java @@ -15,6 +15,8 @@ package dev.cel.common.navigation; import com.google.auto.value.AutoValue; +import com.google.errorprone.annotations.CanIgnoreReturnValue; +import com.google.errorprone.annotations.CheckReturnValue; import dev.cel.common.ast.CelExpr; import dev.cel.common.ast.CelExpr.CelComprehension; import dev.cel.common.ast.CelExpr.ExprKind; @@ -59,6 +61,12 @@ public long id() { /** Represents the count of transitive parents. Depth of an AST's root is 0. */ public abstract int depth(); + /** + * Represents the maximum count of children from any of its branches. Height of a leaf node is 0. + * For example, the height of the call node 'func' in expression `(1 + 2 + 3).func(4 + 5)` is 3. + */ + public abstract int height(); + /** Constructs a new instance of {@link CelNavigableExpr} from {@link CelExpr}. */ public static CelNavigableExpr fromExpr(CelExpr expr) { return CelNavigableExpr.builder().setExpr(expr).build(); @@ -93,7 +101,8 @@ public Stream descendants() { * the specified traversal order. */ public Stream descendants(TraversalOrder traversalOrder) { - return CelNavigableExprVisitor.collect(this, traversalOrder).filter(node -> !node.equals(this)); + return CelNavigableExprVisitor.collect(this, traversalOrder) + .filter(node -> node.depth() > this.depth()); } /** @@ -110,7 +119,7 @@ public Stream children() { */ public Stream children(TraversalOrder traversalOrder) { return CelNavigableExprVisitor.collect(this, this.depth() + 1, traversalOrder) - .filter(node -> !node.equals(this)); + .filter(node -> node.depth() > this.depth()); } /** Returns the underlying kind of the {@link CelExpr}. */ @@ -120,21 +129,47 @@ public ExprKind.Kind getKind() { /** Create a new builder to construct a {@link CelNavigableExpr} instance. */ public static Builder builder() { - return new AutoValue_CelNavigableExpr.Builder().setDepth(0); + return new AutoValue_CelNavigableExpr.Builder().setDepth(0).setHeight(0); } /** Builder to configure {@link CelNavigableExpr}. */ @AutoValue.Builder public abstract static class Builder { + private Builder parentBuilder; + public abstract CelExpr expr(); + public abstract int depth(); + + public ExprKind.Kind getKind() { + return expr().exprKind().getKind(); + } + public abstract Builder setExpr(CelExpr value); - public abstract Builder setParent(CelNavigableExpr value); + abstract Builder setParent(CelNavigableExpr value); + + @CanIgnoreReturnValue + public Builder setParentBuilder(CelNavigableExpr.Builder value) { + parentBuilder = value; + return this; + } public abstract Builder setDepth(int value); - public abstract CelNavigableExpr build(); + public abstract Builder setHeight(int value); + + public abstract CelNavigableExpr autoBuild(); + + @CheckReturnValue + public CelNavigableExpr build() { + if (parentBuilder != null) { + setParent(parentBuilder.build()); + } + return autoBuild(); + } } + + public abstract Builder toBuilder(); } diff --git a/common/src/main/java/dev/cel/common/navigation/CelNavigableExprVisitor.java b/common/src/main/java/dev/cel/common/navigation/CelNavigableExprVisitor.java index 8abcf017f..59cde7495 100644 --- a/common/src/main/java/dev/cel/common/navigation/CelNavigableExprVisitor.java +++ b/common/src/main/java/dev/cel/common/navigation/CelNavigableExprVisitor.java @@ -14,6 +14,8 @@ package dev.cel.common.navigation; +import static java.lang.Math.max; + import com.google.common.collect.ImmutableList; import dev.cel.common.ast.CelExpr; import dev.cel.common.ast.CelExpr.CelCall; @@ -29,7 +31,7 @@ final class CelNavigableExprVisitor { private static final int MAX_DESCENDANTS_RECURSION_DEPTH = 500; - private final Stream.Builder streamBuilder; + private final Stream.Builder streamBuilder; private final TraversalOrder traversalOrder; private final int maxDepth; @@ -84,105 +86,124 @@ static Stream collect( CelNavigableExpr navigableExpr, int maxDepth, TraversalOrder traversalOrder) { CelNavigableExprVisitor visitor = new CelNavigableExprVisitor(maxDepth, traversalOrder); - visitor.visit(navigableExpr); + visitor.visit(navigableExpr.toBuilder()); - return visitor.streamBuilder.build(); + return visitor.streamBuilder.build().map(CelNavigableExpr.Builder::build); } - private void visit(CelNavigableExpr navigableExpr) { + private int visit(CelNavigableExpr.Builder navigableExpr) { if (navigableExpr.depth() > MAX_DESCENDANTS_RECURSION_DEPTH - 1) { throw new IllegalStateException("Max recursion depth reached."); } if (navigableExpr.depth() > maxDepth) { - return; + return -1; } if (traversalOrder.equals(TraversalOrder.PRE_ORDER)) { streamBuilder.add(navigableExpr); } + int height = 1; switch (navigableExpr.getKind()) { case CALL: - visit(navigableExpr, navigableExpr.expr().call()); + height += visit(navigableExpr, navigableExpr.expr().call()); break; case CREATE_LIST: - visit(navigableExpr, navigableExpr.expr().createList()); + height += visit(navigableExpr, navigableExpr.expr().createList()); break; case SELECT: - visit(navigableExpr, navigableExpr.expr().select()); + height += visit(navigableExpr, navigableExpr.expr().select()); break; case CREATE_STRUCT: - visitStruct(navigableExpr, navigableExpr.expr().createStruct()); + height += visitStruct(navigableExpr, navigableExpr.expr().createStruct()); break; case CREATE_MAP: - visitMap(navigableExpr, navigableExpr.expr().createMap()); + height += visitMap(navigableExpr, navigableExpr.expr().createMap()); break; case COMPREHENSION: - visit(navigableExpr, navigableExpr.expr().comprehension()); + height += visit(navigableExpr, navigableExpr.expr().comprehension()); break; default: + // This is a leaf node + height = 0; break; } + navigableExpr.setHeight(height); if (traversalOrder.equals(TraversalOrder.POST_ORDER)) { streamBuilder.add(navigableExpr); } + + return height; } - private void visit(CelNavigableExpr navigableExpr, CelCall call) { + private int visit(CelNavigableExpr.Builder navigableExpr, CelCall call) { + int targetHeight = 0; if (call.target().isPresent()) { - CelNavigableExpr target = newNavigableChild(navigableExpr, call.target().get()); - visit(target); + CelNavigableExpr.Builder target = newNavigableChild(navigableExpr, call.target().get()); + targetHeight = visit(target); } - visitExprList(call.args(), navigableExpr); + int argumentHeight = visitExprList(call.args(), navigableExpr); + return max(targetHeight, argumentHeight); } - private void visit(CelNavigableExpr navigableExpr, CelCreateList createList) { - visitExprList(createList.elements(), navigableExpr); + private int visit(CelNavigableExpr.Builder navigableExpr, CelCreateList createList) { + return visitExprList(createList.elements(), navigableExpr); } - private void visit(CelNavigableExpr navigableExpr, CelSelect selectExpr) { - CelNavigableExpr operand = newNavigableChild(navigableExpr, selectExpr.operand()); - visit(operand); + private int visit(CelNavigableExpr.Builder navigableExpr, CelSelect selectExpr) { + CelNavigableExpr.Builder operand = newNavigableChild(navigableExpr, selectExpr.operand()); + return visit(operand); } - private void visit(CelNavigableExpr navigableExpr, CelComprehension comprehension) { - visit(newNavigableChild(navigableExpr, comprehension.iterRange())); - visit(newNavigableChild(navigableExpr, comprehension.accuInit())); - visit(newNavigableChild(navigableExpr, comprehension.loopCondition())); - visit(newNavigableChild(navigableExpr, comprehension.loopStep())); - visit(newNavigableChild(navigableExpr, comprehension.result())); + private int visit(CelNavigableExpr.Builder navigableExpr, CelComprehension comprehension) { + int maxHeight = 0; + maxHeight = max(visit(newNavigableChild(navigableExpr, comprehension.iterRange())), maxHeight); + maxHeight = max(visit(newNavigableChild(navigableExpr, comprehension.accuInit())), maxHeight); + maxHeight = + max(visit(newNavigableChild(navigableExpr, comprehension.loopCondition())), maxHeight); + maxHeight = max(visit(newNavigableChild(navigableExpr, comprehension.loopStep())), maxHeight); + maxHeight = max(visit(newNavigableChild(navigableExpr, comprehension.result())), maxHeight); + + return maxHeight; } - private void visitStruct(CelNavigableExpr navigableExpr, CelCreateStruct struct) { + private int visitStruct(CelNavigableExpr.Builder navigableExpr, CelCreateStruct struct) { + int maxHeight = 0; for (CelCreateStruct.Entry entry : struct.entries()) { - CelNavigableExpr value = newNavigableChild(navigableExpr, entry.value()); - visit(value); + CelNavigableExpr.Builder value = newNavigableChild(navigableExpr, entry.value()); + maxHeight = max(visit(value), maxHeight); } + return maxHeight; } - private void visitMap(CelNavigableExpr navigableExpr, CelCreateMap map) { + private int visitMap(CelNavigableExpr.Builder navigableExpr, CelCreateMap map) { + int maxHeight = 0; for (CelCreateMap.Entry entry : map.entries()) { - CelNavigableExpr key = newNavigableChild(navigableExpr, entry.key()); - visit(key); + CelNavigableExpr.Builder key = newNavigableChild(navigableExpr, entry.key()); + maxHeight = max(visit(key), maxHeight); - CelNavigableExpr value = newNavigableChild(navigableExpr, entry.value()); - visit(value); + CelNavigableExpr.Builder value = newNavigableChild(navigableExpr, entry.value()); + maxHeight = max(visit(value), maxHeight); } + return 0; } - private void visitExprList(ImmutableList createListExpr, CelNavigableExpr parent) { + private int visitExprList( + ImmutableList createListExpr, CelNavigableExpr.Builder parent) { + int maxHeight = 0; for (CelExpr expr : createListExpr) { - CelNavigableExpr arg = newNavigableChild(parent, expr); - visit(arg); + CelNavigableExpr.Builder arg = newNavigableChild(parent, expr); + maxHeight = max(visit(arg), maxHeight); } + return maxHeight; } - private CelNavigableExpr newNavigableChild(CelNavigableExpr parent, CelExpr expr) { + private CelNavigableExpr.Builder newNavigableChild( + CelNavigableExpr.Builder parent, CelExpr expr) { return CelNavigableExpr.builder() .setExpr(expr) .setDepth(parent.depth() + 1) - .setParent(parent) - .build(); + .setParentBuilder(parent); } } diff --git a/common/src/test/java/dev/cel/common/navigation/CelNavigableExprVisitorTest.java b/common/src/test/java/dev/cel/common/navigation/CelNavigableExprVisitorTest.java index f3739ca53..3501aea6b 100644 --- a/common/src/test/java/dev/cel/common/navigation/CelNavigableExprVisitorTest.java +++ b/common/src/test/java/dev/cel/common/navigation/CelNavigableExprVisitorTest.java @@ -107,6 +107,46 @@ public void add_allNodes_allNodesReturned() throws Exception { CelExpr.ofConstantExpr(5, CelConstant.ofValue(2))); } + @Test + public void add_preOrder_heightSet() throws Exception { + CelCompiler compiler = + CelCompilerFactory.standardCelCompilerBuilder().addVar("a", SimpleType.INT).build(); + // Tree shape: + // + + // + 2 + // 1 a + CelAbstractSyntaxTree ast = compiler.compile("1 + a + 2").getAst(); + CelNavigableAst navigableAst = CelNavigableAst.fromAst(ast); + + ImmutableList allNodeHeights = + navigableAst + .getRoot() + .allNodes(TraversalOrder.PRE_ORDER) + .map(CelNavigableExpr::height) + .collect(toImmutableList()); + assertThat(allNodeHeights).containsExactly(2, 1, 0, 0, 0).inOrder(); // +, +, 1, a, 2 + } + + @Test + public void add_postOrder_heightSet() throws Exception { + CelCompiler compiler = + CelCompilerFactory.standardCelCompilerBuilder().addVar("a", SimpleType.INT).build(); + // Tree shape: + // + + // + 2 + // 1 a + CelAbstractSyntaxTree ast = compiler.compile("1 + a + 2").getAst(); + CelNavigableAst navigableAst = CelNavigableAst.fromAst(ast); + + ImmutableList allNodeHeights = + navigableAst + .getRoot() + .allNodes(TraversalOrder.POST_ORDER) + .map(CelNavigableExpr::height) + .collect(toImmutableList()); + assertThat(allNodeHeights).containsExactly(0, 0, 1, 0, 2).inOrder(); // 1, a, +, 2, + + } + @Test public void add_filterConstants_allNodesReturned() throws Exception { CelCompiler compiler = @@ -450,6 +490,46 @@ public void messageConstruction_filterCreateStruct_allNodesReturned() throws Exc false)))); } + @Test + public void messageConstruction_preOrder_heightSet() throws Exception { + CelCompiler compiler = + CelCompilerFactory.standardCelCompilerBuilder() + .addMessageTypes(TestAllTypes.getDescriptor()) + .setContainer("dev.cel.testing.testdata.proto3") + .build(); + CelAbstractSyntaxTree ast = compiler.compile("TestAllTypes{single_int64: 1}").getAst(); + CelNavigableAst navigableAst = CelNavigableAst.fromAst(ast); + + ImmutableList allNodes = + navigableAst + .getRoot() + .allNodes(TraversalOrder.PRE_ORDER) + .map(CelNavigableExpr::height) + .collect(toImmutableList()); + + assertThat(allNodes).containsExactly(1, 0).inOrder(); + } + + @Test + public void messageConstruction_postOrder_heightSet() throws Exception { + CelCompiler compiler = + CelCompilerFactory.standardCelCompilerBuilder() + .addMessageTypes(TestAllTypes.getDescriptor()) + .setContainer("dev.cel.testing.testdata.proto3") + .build(); + CelAbstractSyntaxTree ast = compiler.compile("TestAllTypes{single_int64: 1}").getAst(); + CelNavigableAst navigableAst = CelNavigableAst.fromAst(ast); + + ImmutableList allNodes = + navigableAst + .getRoot() + .allNodes(TraversalOrder.POST_ORDER) + .map(CelNavigableExpr::height) + .collect(toImmutableList()); + + assertThat(allNodes).containsExactly(0, 1).inOrder(); + } + @Test public void mapConstruction_allNodesReturned() throws Exception { CelCompiler compiler = CelCompilerFactory.standardCelCompilerBuilder().build(); @@ -496,6 +576,38 @@ public void mapConstruction_filterCreateMap_allNodesReturned() throws Exception CelExpr.ofCreateMapEntryExpr(2, mapKeyExpr, mapValueExpr, false)))); } + @Test + public void mapConstruction_preOrder_heightSet() throws Exception { + CelCompiler compiler = CelCompilerFactory.standardCelCompilerBuilder().build(); + CelAbstractSyntaxTree ast = compiler.compile("{'key': 2}").getAst(); + CelNavigableAst navigableAst = CelNavigableAst.fromAst(ast); + + ImmutableList allNodes = + navigableAst + .getRoot() + .allNodes(TraversalOrder.PRE_ORDER) + .map(CelNavigableExpr::height) + .collect(toImmutableList()); + + assertThat(allNodes).containsExactly(1, 0, 0).inOrder(); + } + + @Test + public void mapConstruction_postOrder_heightSet() throws Exception { + CelCompiler compiler = CelCompilerFactory.standardCelCompilerBuilder().build(); + CelAbstractSyntaxTree ast = compiler.compile("{'key': 2}").getAst(); + CelNavigableAst navigableAst = CelNavigableAst.fromAst(ast); + + ImmutableList allNodes = + navigableAst + .getRoot() + .allNodes(TraversalOrder.POST_ORDER) + .map(CelNavigableExpr::height) + .collect(toImmutableList()); + + assertThat(allNodes).containsExactly(0, 0, 1).inOrder(); + } + @Test public void emptyMapConstruction_allNodesReturned() throws Exception { CelCompiler compiler = CelCompilerFactory.standardCelCompilerBuilder().build(); @@ -633,6 +745,44 @@ public void comprehension_postOrder_allNodesReturned() throws Exception { .inOrder(); } + @Test + public void comprehension_preOrder_heightSet() throws Exception { + CelCompiler compiler = + CelCompilerFactory.standardCelCompilerBuilder() + .setStandardMacros(CelStandardMacro.EXISTS) + .build(); + CelAbstractSyntaxTree ast = compiler.compile("[true].exists(i, i)").getAst(); + CelNavigableAst navigableAst = CelNavigableAst.fromAst(ast); + + ImmutableList allNodes = + navigableAst + .getRoot() + .allNodes(TraversalOrder.PRE_ORDER) + .map(CelNavigableExpr::height) + .collect(toImmutableList()); + + assertThat(allNodes).containsExactly(3, 1, 0, 0, 2, 1, 0, 1, 0, 0, 0).inOrder(); + } + + @Test + public void comprehension_postOrder_heightSet() throws Exception { + CelCompiler compiler = + CelCompilerFactory.standardCelCompilerBuilder() + .setStandardMacros(CelStandardMacro.EXISTS) + .build(); + CelAbstractSyntaxTree ast = compiler.compile("[true].exists(i, i)").getAst(); + CelNavigableAst navigableAst = CelNavigableAst.fromAst(ast); + + ImmutableList allNodes = + navigableAst + .getRoot() + .allNodes(TraversalOrder.POST_ORDER) + .map(CelNavigableExpr::height) + .collect(toImmutableList()); + + assertThat(allNodes).containsExactly(0, 1, 0, 0, 1, 2, 0, 0, 1, 0, 3).inOrder(); + } + @Test public void comprehension_allNodes_parentsPopulated() throws Exception { CelCompiler compiler = @@ -816,6 +966,62 @@ public void callExpr_postOrder() throws Exception { .inOrder(); } + @Test + public void callExpr_preOrder_heightSet() throws Exception { + CelCompiler compiler = + CelCompilerFactory.standardCelCompilerBuilder() + .addFunctionDeclarations( + newFunctionDeclaration( + "test", + newMemberOverload( + "test_overload", + SimpleType.STRING, + SimpleType.STRING, + SimpleType.INT, + SimpleType.UINT))) + .build(); + CelAbstractSyntaxTree ast = + compiler.compile("('a' + 'b' + 'c' + 'd').test((1 + 2 + 3), 6u)").getAst(); + CelNavigableAst navigableAst = CelNavigableAst.fromAst(ast); + + ImmutableList allNodes = + navigableAst + .getRoot() + .allNodes(TraversalOrder.PRE_ORDER) + .map(CelNavigableExpr::height) + .collect(toImmutableList()); + + assertThat(allNodes).containsExactly(4, 3, 2, 1, 0, 0, 0, 0, 2, 1, 0, 0, 0, 0).inOrder(); + } + + @Test + public void callExpr_postOrder_heightSet() throws Exception { + CelCompiler compiler = + CelCompilerFactory.standardCelCompilerBuilder() + .addFunctionDeclarations( + newFunctionDeclaration( + "test", + newMemberOverload( + "test_overload", + SimpleType.STRING, + SimpleType.STRING, + SimpleType.INT, + SimpleType.UINT))) + .build(); + CelAbstractSyntaxTree ast = + compiler.compile("('a' + 'b' + 'c' + 'd').test((1 + 2 + 3), 6u)").getAst(); + CelNavigableAst navigableAst = CelNavigableAst.fromAst(ast); + + ImmutableList allNodes = + navigableAst + .getRoot() + .allNodes(TraversalOrder.POST_ORDER) + .map(CelNavigableExpr::height) + .collect(toImmutableList()); + + assertThat(allNodes).containsExactly(0, 0, 1, 0, 2, 0, 3, 0, 0, 1, 0, 2, 0, 4).inOrder(); + } + @Test public void maxRecursionLimitReached_throws() throws Exception { StringBuilder sb = new StringBuilder(); From 4a723aab1782e10bacac4ba8a60db750495b2329 Mon Sep 17 00:00:00 2001 From: CEL Dev Team Date: Tue, 13 Feb 2024 10:26:17 -0800 Subject: [PATCH 028/486] No public description PiperOrigin-RevId: 606668350 --- WORKSPACE | 2 +- .../dev/cel/common/testing/RepeatedTestProvider.java | 6 +++--- .../test/java/dev/cel/parser/CelUnparserImplTest.java | 10 +++++----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/WORKSPACE b/WORKSPACE index d2cd47952..f7b21a719 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -68,7 +68,7 @@ maven_install( "com.google.protobuf:protobuf-java:3.24.4", "com.google.protobuf:protobuf-java-util:3.24.4", "com.google.re2j:re2j:1.7", - "com.google.testparameterinjector:test-parameter-injector:1.14", + "com.google.testparameterinjector:test-parameter-injector:1.15", "com.google.truth.extensions:truth-java8-extension:1.4.0", "com.google.truth.extensions:truth-proto-extension:1.4.0", "com.google.truth:truth:1.4.0", diff --git a/common/src/main/java/dev/cel/common/testing/RepeatedTestProvider.java b/common/src/main/java/dev/cel/common/testing/RepeatedTestProvider.java index a8502e0b5..974c504b7 100644 --- a/common/src/main/java/dev/cel/common/testing/RepeatedTestProvider.java +++ b/common/src/main/java/dev/cel/common/testing/RepeatedTestProvider.java @@ -18,7 +18,7 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableList; -import com.google.testing.junit.testparameterinjector.TestParameter.TestParameterValuesProvider; +import com.google.testing.junit.testparameterinjector.TestParameterValuesProvider; import dev.cel.common.annotations.Internal; import java.util.stream.IntStream; @@ -34,11 +34,11 @@ */ @Internal @VisibleForTesting -public final class RepeatedTestProvider implements TestParameterValuesProvider { +public final class RepeatedTestProvider extends TestParameterValuesProvider { private static final int REPEATED_TEST_RUN_COUNT = 50; @Override - public ImmutableList provideValues() { + public ImmutableList provideValues(Context context) { return IntStream.rangeClosed(1, REPEATED_TEST_RUN_COUNT).boxed().collect(toImmutableList()); } } diff --git a/parser/src/test/java/dev/cel/parser/CelUnparserImplTest.java b/parser/src/test/java/dev/cel/parser/CelUnparserImplTest.java index 8eb312560..86fb279c0 100644 --- a/parser/src/test/java/dev/cel/parser/CelUnparserImplTest.java +++ b/parser/src/test/java/dev/cel/parser/CelUnparserImplTest.java @@ -18,8 +18,8 @@ import static org.junit.Assert.assertThrows; import com.google.testing.junit.testparameterinjector.TestParameter; -import com.google.testing.junit.testparameterinjector.TestParameter.TestParameterValuesProvider; import com.google.testing.junit.testparameterinjector.TestParameterInjector; +import com.google.testing.junit.testparameterinjector.TestParameterValuesProvider; import dev.cel.common.CelAbstractSyntaxTree; import dev.cel.common.CelOptions; import dev.cel.common.CelProtoAbstractSyntaxTree; @@ -46,9 +46,9 @@ public final class CelUnparserImplTest { private final CelUnparserImpl unparser = new CelUnparserImpl(); - private static final class ValidExprDataProvider implements TestParameterValuesProvider { + private static final class ValidExprDataProvider extends TestParameterValuesProvider { @Override - public List provideValues() { + public List provideValues(Context context) { return Arrays.asList( "a + b - c", "a && b && c && d && e", @@ -182,9 +182,9 @@ public void unparse_succeeds( .isEqualTo(CelProtoAbstractSyntaxTree.fromCelAst(astOne).toParsedExpr()); } - private static final class InvalidExprDataProvider implements TestParameterValuesProvider { + private static final class InvalidExprDataProvider extends TestParameterValuesProvider { @Override - public List provideValues() { + public List provideValues(Context context) { return Arrays.asList( CelExpr.newBuilder().build(), // empty expr CelExpr.newBuilder() From bda6026bd0693ab4fa60027763f4af58495ba86c Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Tue, 13 Feb 2024 13:54:15 -0800 Subject: [PATCH 029/486] Properly set subtree height for navigable expr's children PiperOrigin-RevId: 606736573 --- .../navigation/CelNavigableExprVisitor.java | 9 ++- .../CelNavigableExprVisitorTest.java | 64 +++++++++++++++++++ 2 files changed, 68 insertions(+), 5 deletions(-) diff --git a/common/src/main/java/dev/cel/common/navigation/CelNavigableExprVisitor.java b/common/src/main/java/dev/cel/common/navigation/CelNavigableExprVisitor.java index 59cde7495..cc49ffcec 100644 --- a/common/src/main/java/dev/cel/common/navigation/CelNavigableExprVisitor.java +++ b/common/src/main/java/dev/cel/common/navigation/CelNavigableExprVisitor.java @@ -95,10 +95,9 @@ private int visit(CelNavigableExpr.Builder navigableExpr) { if (navigableExpr.depth() > MAX_DESCENDANTS_RECURSION_DEPTH - 1) { throw new IllegalStateException("Max recursion depth reached."); } - if (navigableExpr.depth() > maxDepth) { - return -1; - } - if (traversalOrder.equals(TraversalOrder.PRE_ORDER)) { + + boolean addToStream = navigableExpr.depth() <= maxDepth; + if (addToStream && traversalOrder.equals(TraversalOrder.PRE_ORDER)) { streamBuilder.add(navigableExpr); } @@ -129,7 +128,7 @@ private int visit(CelNavigableExpr.Builder navigableExpr) { } navigableExpr.setHeight(height); - if (traversalOrder.equals(TraversalOrder.POST_ORDER)) { + if (addToStream && traversalOrder.equals(TraversalOrder.POST_ORDER)) { streamBuilder.add(navigableExpr); } diff --git a/common/src/test/java/dev/cel/common/navigation/CelNavigableExprVisitorTest.java b/common/src/test/java/dev/cel/common/navigation/CelNavigableExprVisitorTest.java index 3501aea6b..e263020fb 100644 --- a/common/src/test/java/dev/cel/common/navigation/CelNavigableExprVisitorTest.java +++ b/common/src/test/java/dev/cel/common/navigation/CelNavigableExprVisitorTest.java @@ -22,6 +22,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.primitives.UnsignedLong; +import com.google.testing.junit.testparameterinjector.TestParameter; import com.google.testing.junit.testparameterinjector.TestParameterInjector; import com.google.testing.junit.testparameterinjector.TestParameters; import dev.cel.common.CelAbstractSyntaxTree; @@ -147,6 +148,51 @@ public void add_postOrder_heightSet() throws Exception { assertThat(allNodeHeights).containsExactly(0, 0, 1, 0, 2).inOrder(); // 1, a, +, 2, + } + @Test + public void add_fromLeaf_heightSetForParents() throws Exception { + CelCompiler compiler = + CelCompilerFactory.standardCelCompilerBuilder().addVar("a", SimpleType.INT).build(); + // Tree shape: + // + + // + 2 + // 1 a + CelAbstractSyntaxTree ast = compiler.compile("1 + a + 2").getAst(); + CelNavigableAst navigableAst = CelNavigableAst.fromAst(ast); + + CelNavigableExpr oneConst = + navigableAst + .getRoot() + .descendants() + .filter(node -> node.expr().constantOrDefault().int64Value() == 1) + .findAny() + .get(); + assertThat(oneConst.height()).isEqualTo(0); // 1 + assertThat(oneConst.parent().get().height()).isEqualTo(1); // + + assertThat(oneConst.parent().get().parent().get().height()).isEqualTo(2); // root + } + + @Test + public void add_children_heightSet(@TestParameter TraversalOrder traversalOrder) + throws Exception { + CelCompiler compiler = + CelCompilerFactory.standardCelCompilerBuilder().addVar("a", SimpleType.INT).build(); + // Tree shape: + // + + // + 2 + // + a + // 3 + CelAbstractSyntaxTree ast = compiler.compile("1 + a + 2 + 3").getAst(); + CelNavigableAst navigableAst = CelNavigableAst.fromAst(ast); + + ImmutableList allNodeHeights = + navigableAst + .getRoot() + .children(traversalOrder) + .map(CelNavigableExpr::height) + .collect(toImmutableList()); + assertThat(allNodeHeights).containsExactly(2, 0).inOrder(); // + (2), 2 (0) regardless of order + } + @Test public void add_filterConstants_allNodesReturned() throws Exception { CelCompiler compiler = @@ -1022,6 +1068,24 @@ public void callExpr_postOrder_heightSet() throws Exception { assertThat(allNodes).containsExactly(0, 0, 1, 0, 2, 0, 3, 0, 0, 1, 0, 2, 0, 4).inOrder(); } + @Test + public void createList_children_heightSet(@TestParameter TraversalOrder traversalOrder) + throws Exception { + CelCompiler compiler = + CelCompilerFactory.standardCelCompilerBuilder().addVar("a", SimpleType.INT).build(); + CelAbstractSyntaxTree ast = compiler.compile("[1, a, (2 + 2), (3 + 4 + 5)]").getAst(); + + CelNavigableAst navigableAst = CelNavigableAst.fromAst(ast); + + ImmutableList allNodeHeights = + navigableAst + .getRoot() + .children(traversalOrder) + .map(CelNavigableExpr::height) + .collect(toImmutableList()); + assertThat(allNodeHeights).containsExactly(0, 0, 1, 2).inOrder(); + } + @Test public void maxRecursionLimitReached_throws() throws Exception { StringBuilder sb = new StringBuilder(); From 70ef6f94b713aa100bf1fa1f7cabca32830c2743 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Thu, 15 Feb 2024 16:08:03 -0800 Subject: [PATCH 030/486] Augment CSE to produce optimized ASTs using cel.block PiperOrigin-RevId: 607486802 --- .../dev/cel/optimizer/CelAstOptimizer.java | 4 +- .../dev/cel/optimizer/CelOptimizerImpl.java | 8 +- .../optimizers/ConstantFoldingOptimizer.java | 4 +- .../optimizers/SubexpressionOptimizer.java | 160 ++++- .../SubexpressionOptimizerTest.java | 546 +++++++++++++++--- 5 files changed, 642 insertions(+), 80 deletions(-) diff --git a/optimizer/src/main/java/dev/cel/optimizer/CelAstOptimizer.java b/optimizer/src/main/java/dev/cel/optimizer/CelAstOptimizer.java index b9f35dcf4..730b5cc3c 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/CelAstOptimizer.java +++ b/optimizer/src/main/java/dev/cel/optimizer/CelAstOptimizer.java @@ -14,7 +14,7 @@ package dev.cel.optimizer; -import dev.cel.bundle.Cel; +import dev.cel.bundle.CelBuilder; import dev.cel.common.CelAbstractSyntaxTree; import dev.cel.common.navigation.CelNavigableAst; @@ -22,6 +22,6 @@ public interface CelAstOptimizer { /** Optimizes a single AST. */ - CelAbstractSyntaxTree optimize(CelNavigableAst navigableAst, Cel cel) + CelAbstractSyntaxTree optimize(CelNavigableAst navigableAst, CelBuilder cel) throws CelOptimizationException; } diff --git a/optimizer/src/main/java/dev/cel/optimizer/CelOptimizerImpl.java b/optimizer/src/main/java/dev/cel/optimizer/CelOptimizerImpl.java index 8ce74e1a3..d57181fc2 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/CelOptimizerImpl.java +++ b/optimizer/src/main/java/dev/cel/optimizer/CelOptimizerImpl.java @@ -18,6 +18,7 @@ import com.google.common.collect.ImmutableSet; import dev.cel.bundle.Cel; +import dev.cel.bundle.CelBuilder; import dev.cel.common.CelAbstractSyntaxTree; import dev.cel.common.CelValidationException; import dev.cel.common.navigation.CelNavigableAst; @@ -39,11 +40,12 @@ public CelAbstractSyntaxTree optimize(CelAbstractSyntaxTree ast) throws CelOptim } CelAbstractSyntaxTree optimizedAst = ast; + CelBuilder celBuilder = cel.toCelBuilder(); try { for (CelAstOptimizer optimizer : astOptimizers) { - CelNavigableAst navigableAst = CelNavigableAst.fromAst(ast); - optimizedAst = optimizer.optimize(navigableAst, cel); - optimizedAst = cel.check(optimizedAst).getAst(); + CelNavigableAst navigableAst = CelNavigableAst.fromAst(optimizedAst); + optimizedAst = optimizer.optimize(navigableAst, celBuilder); + optimizedAst = celBuilder.build().check(optimizedAst).getAst(); } } catch (CelValidationException e) { throw new CelOptimizationException( diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java b/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java index 2e63c0364..8ca19e941 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java @@ -19,6 +19,7 @@ import com.google.auto.value.AutoValue; import com.google.common.collect.ImmutableList; import dev.cel.bundle.Cel; +import dev.cel.bundle.CelBuilder; import dev.cel.common.CelAbstractSyntaxTree; import dev.cel.common.CelValidationException; import dev.cel.common.ast.CelConstant; @@ -76,8 +77,9 @@ public static ConstantFoldingOptimizer newInstance( private final MutableAst mutableAst; @Override - public CelAbstractSyntaxTree optimize(CelNavigableAst navigableAst, Cel cel) + public CelAbstractSyntaxTree optimize(CelNavigableAst navigableAst, CelBuilder celBuilder) throws CelOptimizationException { + Cel cel = celBuilder.build(); Set visitedExprs = new HashSet<>(); int iterCount = 0; while (true) { diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java index 241680bb2..150a91dc5 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java @@ -23,13 +23,15 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Streams; -import dev.cel.bundle.Cel; +import dev.cel.bundle.CelBuilder; import dev.cel.checker.Standard; import dev.cel.common.CelAbstractSyntaxTree; import dev.cel.common.CelFunctionDecl; import dev.cel.common.CelOverloadDecl; import dev.cel.common.CelSource; +import dev.cel.common.CelValidationException; import dev.cel.common.ast.CelExpr; +import dev.cel.common.ast.CelExpr.CelCall; import dev.cel.common.ast.CelExpr.CelIdent; import dev.cel.common.ast.CelExpr.ExprKind.Kind; import dev.cel.common.navigation.CelNavigableAst; @@ -41,8 +43,10 @@ import dev.cel.optimizer.CelAstOptimizer; import dev.cel.optimizer.MutableAst; import dev.cel.parser.Operator; +import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.NoSuchElementException; import java.util.Optional; import java.util.stream.Stream; @@ -63,6 +67,12 @@ * cel.bind(@r0, message.child.text_map[x], * @r0.startsWith("hello") && @r0.endsWith("world")) * } + * + * Or, using the equivalent form of cel.@block (requires special runtime support): + * {@code + * cel.block([message.child.text_map[x]], + * @index0.startsWith("hello") && @index1.endsWith("world")) + * } * */ public class SubexpressionOptimizer implements CelAstOptimizer { @@ -71,6 +81,7 @@ public class SubexpressionOptimizer implements CelAstOptimizer { private static final String BIND_IDENTIFIER_PREFIX = "@r"; private static final String MANGLED_COMPREHENSION_IDENTIFIER_PREFIX = "@c"; private static final String CEL_BLOCK_FUNCTION = "cel.@block"; + private static final String BLOCK_INDEX_PREFIX = "@index"; private static final ImmutableSet CSE_ALLOWED_FUNCTIONS = Streams.concat( stream(Operator.values()).map(Operator::getFunction), @@ -96,7 +107,138 @@ public static SubexpressionOptimizer newInstance(SubexpressionOptimizerOptions c } @Override - public CelAbstractSyntaxTree optimize(CelNavigableAst navigableAst, Cel cel) { + public CelAbstractSyntaxTree optimize(CelNavigableAst navigableAst, CelBuilder celBuilder) { + return cseOptions.enableCelBlock() + ? optimizeUsingCelBlock(navigableAst, celBuilder) + : optimizeUsingCelBind(navigableAst); + } + + private CelAbstractSyntaxTree optimizeUsingCelBlock( + CelNavigableAst navigableAst, CelBuilder celBuilder) { + // Retain the original expected result type, so that it can be reset in celBuilder at the end of + // the optimization pass. + CelType resultType = navigableAst.getAst().getResultType(); + CelAbstractSyntaxTree astToModify = + mutableAst.mangleComprehensionIdentifierNames( + navigableAst.getAst(), MANGLED_COMPREHENSION_IDENTIFIER_PREFIX); + CelSource sourceToModify = astToModify.getSource(); + + int blockIdentifierIndex = 0; + int iterCount; + ArrayList subexpressions = new ArrayList<>(); + for (iterCount = 0; iterCount < cseOptions.iterationLimit(); iterCount++) { + CelExpr cseCandidate = findCseCandidate(astToModify).map(CelNavigableExpr::expr).orElse(null); + if (cseCandidate == null) { + break; + } + subexpressions.add(cseCandidate); + + String blockIdentifier = BLOCK_INDEX_PREFIX + blockIdentifierIndex++; + + // Using the CSE candidate, fetch all semantically equivalent subexpressions ahead of time. + ImmutableList allCseCandidates = + getAllCseCandidatesStream(astToModify, cseCandidate).collect(toImmutableList()); + + // Replace all CSE candidates with new block index identifier + for (CelExpr semanticallyEqualNode : allCseCandidates) { + iterCount++; + // Refetch the candidate expr as mutating the AST could have renumbered its IDs. + CelExpr exprToReplace = + getAllCseCandidatesStream(astToModify, semanticallyEqualNode) + .findAny() + .orElseThrow( + () -> + new NoSuchElementException( + "No value present for expr ID: " + semanticallyEqualNode.id())); + + astToModify = + mutableAst.replaceSubtree( + astToModify, + CelExpr.newBuilder() + .setIdent(CelIdent.newBuilder().setName(blockIdentifier).build()) + .build(), + exprToReplace.id()); + } + + sourceToModify = + sourceToModify.toBuilder() + .addAllMacroCalls(astToModify.getSource().getMacroCalls()) + .build(); + astToModify = CelAbstractSyntaxTree.newParsedAst(astToModify.getExpr(), sourceToModify); + + // Retain the existing macro calls in case if the block identifiers are replacing a subtree + // that contains a comprehension. + sourceToModify = astToModify.getSource(); + } + + if (iterCount >= cseOptions.iterationLimit()) { + throw new IllegalStateException("Max iteration count reached."); + } + + if (iterCount == 0) { + // No modification has been made. + return astToModify; + } + + // Type-check all sub-expressions then add them as block identifiers to the CEL environment + addBlockIdentsToEnv(celBuilder, subexpressions); + + // Wrap the optimized expression in cel.block + celBuilder.addFunctionDeclarations(newCelBlockFunctionDecl(resultType)); + int newId = 0; + CelExpr blockExpr = + CelExpr.newBuilder() + .setId(++newId) + .setCall( + CelCall.newBuilder() + .setFunction(CEL_BLOCK_FUNCTION) + .addArgs( + CelExpr.ofCreateListExpr( + ++newId, ImmutableList.copyOf(subexpressions), ImmutableList.of()), + astToModify.getExpr()) + .build()) + .build(); + astToModify = + mutableAst.renumberIdsConsecutively( + CelAbstractSyntaxTree.newParsedAst(blockExpr, astToModify.getSource())); + + if (!cseOptions.populateMacroCalls()) { + astToModify = + CelAbstractSyntaxTree.newParsedAst(astToModify.getExpr(), CelSource.newBuilder().build()); + } + + // Restore the expected result type the environment had prior to optimization. + celBuilder.setResultType(resultType); + return astToModify; + } + + /** + * Adds all subexpression as numbered identifiers that acts as an indexer to cel.block + * (ex: @index0, @index1..) Each subexpressions are type-checked, then its result type is used as + * the new identifiers' types. + */ + private static void addBlockIdentsToEnv(CelBuilder celBuilder, List subexpressions) { + // The resulting type of the subexpressions will likely be different from the + // entire expression's expected result type. + celBuilder.setResultType(SimpleType.DYN); + + for (int i = 0; i < subexpressions.size(); i++) { + CelExpr subexpression = subexpressions.get(i); + + CelAbstractSyntaxTree subAst = + CelAbstractSyntaxTree.newParsedAst(subexpression, CelSource.newBuilder().build()); + + try { + subAst = celBuilder.build().check(subAst).getAst(); + } catch (CelValidationException e) { + throw new IllegalStateException("Failed to type-check subexpression", e); + } + + celBuilder.addVar("@index" + i, subAst.getResultType()); + } + } + + private CelAbstractSyntaxTree optimizeUsingCelBind(CelNavigableAst navigableAst) { CelAbstractSyntaxTree astToModify = mutableAst.mangleComprehensionIdentifierNames( navigableAst.getAst(), MANGLED_COMPREHENSION_IDENTIFIER_PREFIX); @@ -166,12 +308,13 @@ public CelAbstractSyntaxTree optimize(CelNavigableAst navigableAst, Cel cel) { return astToModify; } + astToModify = mutableAst.renumberIdsConsecutively(astToModify); if (!cseOptions.populateMacroCalls()) { astToModify = CelAbstractSyntaxTree.newParsedAst(astToModify.getExpr(), CelSource.newBuilder().build()); } - return mutableAst.renumberIdsConsecutively(astToModify); + return astToModify; } private Stream getAllCseCandidatesStream( @@ -347,6 +490,8 @@ public abstract static class SubexpressionOptimizerOptions { public abstract boolean populateMacroCalls(); + public abstract boolean enableCelBlock(); + /** Builder for configuring the {@link SubexpressionOptimizerOptions}. */ @AutoValue.Builder public abstract static class Builder { @@ -363,6 +508,12 @@ public abstract static class Builder { */ public abstract Builder populateMacroCalls(boolean value); + /** + * Rewrites the optimized AST using cel.@block call instead of cascaded cel.bind macros, aimed + * to produce a more compact AST. + */ + public abstract Builder enableCelBlock(boolean value); + public abstract SubexpressionOptimizerOptions build(); Builder() {} @@ -372,7 +523,8 @@ public abstract static class Builder { public static Builder newBuilder() { return new AutoValue_SubexpressionOptimizer_SubexpressionOptimizerOptions.Builder() .iterationLimit(500) - .populateMacroCalls(false); + .populateMacroCalls(false) + .enableCelBlock(false); } SubexpressionOptimizerOptions() {} diff --git a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java index 70b12f536..377756fc9 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java @@ -98,13 +98,6 @@ public class SubexpressionOptimizerTest { .addVar("msg", StructTypeReference.create(TestAllTypes.getDescriptor().getFullName())) .build(); - private static final CelOptimizer CEL_OPTIMIZER = - CelOptimizerFactory.standardCelOptimizerBuilder(CEL) - .addAstOptimizers( - SubexpressionOptimizer.newInstance( - SubexpressionOptimizerOptions.newBuilder().populateMacroCalls(true).build())) - .build(); - private static final CelUnparser CEL_UNPARSER = CelUnparserFactory.newUnparser(); private static final TestAllTypes TEST_ALL_TYPES_INPUT = @@ -141,12 +134,24 @@ private static CelBuilder newCelBuilder() { .addVar("msg", StructTypeReference.create(TestAllTypes.getDescriptor().getFullName())); } + private static CelOptimizer newCseOptimizer(SubexpressionOptimizerOptions options) { + return CelOptimizerFactory.standardCelOptimizerBuilder(CEL) + .addAstOptimizers(SubexpressionOptimizer.newInstance(options)) + .build(); + } + @Test - public void cse_producesOptimizedAst() throws Exception { + public void cse_withCelBind_producesOptimizedAst() throws Exception { CelAbstractSyntaxTree ast = CEL.compile("size([0]) + size([0]) + size([1,2]) + size([1,2])").getAst(); - CelAbstractSyntaxTree optimizedAst = CEL_OPTIMIZER.optimize(ast); + CelAbstractSyntaxTree optimizedAst = + newCseOptimizer( + SubexpressionOptimizerOptions.newBuilder() + .populateMacroCalls(false) + .enableCelBlock(false) + .build()) + .optimize(ast); assertThat(CEL.createProgram(optimizedAst).eval()).isEqualTo(6); assertThat(optimizedAst.getExpr().toString()) @@ -245,24 +250,102 @@ public void cse_producesOptimizedAst() throws Exception { + "}"); } + @Test + public void cse_withCelBlock_producesOptimizedAst() throws Exception { + CelAbstractSyntaxTree ast = + CEL.compile("size([0]) + size([0]) + size([1,2]) + size([1,2])").getAst(); + CelOptimizer celOptimizer = + newCseOptimizer(SubexpressionOptimizerOptions.newBuilder().enableCelBlock(true).build()); + CelAbstractSyntaxTree optimizedAst = celOptimizer.optimize(ast); + + assertThat(CEL.createProgram(optimizedAst).eval()).isEqualTo(6); + assertThat(optimizedAst.getExpr().toString()) + .isEqualTo( + "CALL [1] {\n" + + " function: cel.@block\n" + + " args: {\n" + + " CREATE_LIST [2] {\n" + + " elements: {\n" + + " CALL [3] {\n" + + " function: size\n" + + " args: {\n" + + " CREATE_LIST [4] {\n" + + " elements: {\n" + + " CONSTANT [5] { value: 0 }\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + " CALL [6] {\n" + + " function: size\n" + + " args: {\n" + + " CREATE_LIST [7] {\n" + + " elements: {\n" + + " CONSTANT [8] { value: 1 }\n" + + " CONSTANT [9] { value: 2 }\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + " CALL [10] {\n" + + " function: _+_\n" + + " args: {\n" + + " CALL [11] {\n" + + " function: _+_\n" + + " args: {\n" + + " CALL [12] {\n" + + " function: _+_\n" + + " args: {\n" + + " IDENT [13] {\n" + + " name: @index0\n" + + " }\n" + + " IDENT [14] {\n" + + " name: @index0\n" + + " }\n" + + " }\n" + + " }\n" + + " IDENT [15] {\n" + + " name: @index1\n" + + " }\n" + + " }\n" + + " }\n" + + " IDENT [16] {\n" + + " name: @index1\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + "}"); + } + private enum CseTestCase { - SIZE_1("size([1,2]) + size([1,2]) + 1 == 5", "cel.bind(@r0, size([1, 2]), @r0 + @r0) + 1 == 5"), + SIZE_1( + "size([1,2]) + size([1,2]) + 1 == 5", + "cel.bind(@r0, size([1, 2]), @r0 + @r0) + 1 == 5", + "cel.@block([size([1, 2])], @index0 + @index0 + 1 == 5)"), SIZE_2( "2 + size([1,2]) + size([1,2]) + 1 == 7", - "cel.bind(@r0, size([1, 2]), 2 + @r0 + @r0) + 1 == 7"), + "cel.bind(@r0, size([1, 2]), 2 + @r0 + @r0) + 1 == 7", + "cel.@block([size([1, 2])], 2 + @index0 + @index0 + 1 == 7)"), SIZE_3( "size([0]) + size([0]) + size([1,2]) + size([1,2]) == 6", - "cel.bind(@r1, size([1, 2]), cel.bind(@r0, size([0]), @r0 + @r0) + @r1 + @r1) == 6"), + "cel.bind(@r1, size([1, 2]), cel.bind(@r0, size([0]), @r0 + @r0) + @r1 + @r1) == 6", + "cel.@block([size([0]), size([1, 2])], @index0 + @index0 + @index1 + @index1 == 6)"), SIZE_4( "5 + size([0]) + size([0]) + size([1,2]) + size([1,2]) + " + "size([1,2,3]) + size([1,2,3]) == 17", "cel.bind(@r2, size([1, 2, 3]), cel.bind(@r1, size([1, 2]), cel.bind(@r0, size([0]), 5 +" - + " @r0 + @r0) + @r1 + @r1) + @r2 + @r2) == 17"), + + " @r0 + @r0) + @r1 + @r1) + @r2 + @r2) == 17", + "cel.@block([size([0]), size([1, 2]), size([1, 2, 3])], 5 + @index0 + @index0 + @index1 +" + + " @index1 + @index2 + @index2 == 17)"), /** - * Unparsed form is: + * Unparsed form: * *

      * {@code
+     * // With binds
      * cel.bind(@r0, timestamp(int(timestamp(1000000000))).getFullYear(),
      *    cel.bind(@r3, timestamp(int(timestamp(75))),
      *      cel.bind(@r2, timestamp(int(timestamp(200))).getFullYear(),
@@ -274,6 +357,21 @@ private enum CseTestCase {
      *) == 13934
      * }
      * 
+ *
+     * {@code
+     * // With block
+     * cel.@block(
+     *     [
+     *      timestamp(int(timestamp(1000000000))).getFullYear(),
+     *      timestamp(int(timestamp(50))),
+     *      timestamp(int(timestamp(200))).getFullYear(),
+     *      timestamp(int(timestamp(75)))
+     *     ],
+     *     @index0 + @index3.getFullYear() + @index1.getFullYear() + @index0 +
+     *     @index1.getSeconds() + @index2 + @index2 + @index3.getMinutes() + @index0 == 13934
+     * )
+     * 
+ * } */ TIMESTAMP( "timestamp(int(timestamp(1000000000))).getFullYear() +" @@ -290,10 +388,16 @@ private enum CseTestCase { + "cel.bind(@r2, timestamp(int(timestamp(200))).getFullYear(), " + "cel.bind(@r1, timestamp(int(timestamp(50))), " + "@r0 + @r3.getFullYear() + @r1.getFullYear() + " - + "@r0 + @r1.getSeconds()) + @r2 + @r2) + @r3.getMinutes()) + @r0) == 13934"), + + "@r0 + @r1.getSeconds()) + @r2 + @r2) + @r3.getMinutes()) + @r0) == 13934", + "cel.@block([timestamp(int(timestamp(1000000000))).getFullYear()," + + " timestamp(int(timestamp(50))), timestamp(int(timestamp(200))).getFullYear()," + + " timestamp(int(timestamp(75)))], @index0 + @index3.getFullYear() +" + + " @index1.getFullYear() + @index0 + @index1.getSeconds() + @index2 + @index2 +" + + " @index3.getMinutes() + @index0 == 13934)"), MAP_INDEX( "{\"a\": 2}[\"a\"] + {\"a\": 2}[\"a\"] * {\"a\": 2}[\"a\"] == 6", - "cel.bind(@r0, {\"a\": 2}[\"a\"], @r0 + @r0 * @r0) == 6"), + "cel.bind(@r0, {\"a\": 2}[\"a\"], @r0 + @r0 * @r0) == 6", + "cel.@block([{\"a\": 2}[\"a\"]], @index0 + @index0 * @index0 == 6)"), /** * Input map is: * @@ -313,84 +417,117 @@ private enum CseTestCase { NESTED_MAP_CONSTRUCTION( "size({'a': {'b': 1}, 'c': {'b': 1}, 'd': {'e': {'b': 1}}, 'e': {'e': {'b': 1}}}) == 4", "size(cel.bind(@r0, {\"b\": 1}, cel.bind(@r1, {\"e\": @r0}, {\"a\": @r0, \"c\": @r0, \"d\":" - + " @r1, \"e\": @r1}))) == 4"), + + " @r1, \"e\": @r1}))) == 4", + "cel.@block([{\"b\": 1}, {\"e\": @index0}], size({\"a\": @index0, \"c\": @index0, \"d\":" + + " @index1, \"e\": @index1}) == 4)"), NESTED_LIST_CONSTRUCTION( "size([1, [1,2,3,4], 2, [1,2,3,4], 5, [1,2,3,4], 7, [[1,2], [1,2,3,4]], [1,2]]) == 9", "size(cel.bind(@r0, [1, 2, 3, 4], " - + "cel.bind(@r1, [1, 2], [1, @r0, 2, @r0, 5, @r0, 7, [@r1, @r0], @r1]))) == 9"), + + "cel.bind(@r1, [1, 2], [1, @r0, 2, @r0, 5, @r0, 7, [@r1, @r0], @r1]))) == 9", + "cel.@block([[1, 2, 3, 4], [1, 2]], size([1, @index0, 2, @index0, 5, @index0, 7, [@index1," + + " @index0], @index1]) == 9)"), SELECT( "msg.single_int64 + msg.single_int64 == 6", - "cel.bind(@r0, msg.single_int64, @r0 + @r0) == 6"), + "cel.bind(@r0, msg.single_int64, @r0 + @r0) == 6", + "cel.@block([msg.single_int64], @index0 + @index0 == 6)"), SELECT_NESTED( "msg.oneof_type.payload.single_int64 + msg.oneof_type.payload.single_int32 + " + "msg.oneof_type.payload.single_int64 + " + "msg.single_int64 + msg.oneof_type.payload.oneof_type.payload.single_int64 == 31", "cel.bind(@r0, msg.oneof_type.payload, " + "cel.bind(@r1, @r0.single_int64, @r1 + @r0.single_int32 + @r1) + " - + "msg.single_int64 + @r0.oneof_type.payload.single_int64) == 31"), + + "msg.single_int64 + @r0.oneof_type.payload.single_int64) == 31", + "cel.@block([msg.oneof_type.payload, @index0.single_int64], @index1 + @index0.single_int32" + + " + @index1 + msg.single_int64 + @index0.oneof_type.payload.single_int64 == 31)"), SELECT_NESTED_MESSAGE_MAP_INDEX_1( "msg.oneof_type.payload.map_int32_int64[1] + " + "msg.oneof_type.payload.map_int32_int64[1] + " + "msg.oneof_type.payload.map_int32_int64[1] == 15", - "cel.bind(@r0, msg.oneof_type.payload.map_int32_int64[1], @r0 + @r0 + @r0) == 15"), + "cel.bind(@r0, msg.oneof_type.payload.map_int32_int64[1], @r0 + @r0 + @r0) == 15", + "cel.@block([msg.oneof_type.payload.map_int32_int64[1]], @index0 + @index0 + @index0 ==" + + " 15)"), SELECT_NESTED_MESSAGE_MAP_INDEX_2( "msg.oneof_type.payload.map_int32_int64[0] + " + "msg.oneof_type.payload.map_int32_int64[1] + " + "msg.oneof_type.payload.map_int32_int64[2] == 8", - "cel.bind(@r0, msg.oneof_type.payload.map_int32_int64, @r0[0] + @r0[1] + @r0[2]) == 8"), + "cel.bind(@r0, msg.oneof_type.payload.map_int32_int64, @r0[0] + @r0[1] + @r0[2]) == 8", + "cel.@block([msg.oneof_type.payload.map_int32_int64], @index0[0] + @index0[1] + @index0[2]" + + " == 8)"), TERNARY( "(msg.single_int64 > 0 ? msg.single_int64 : 0) == 3", - "cel.bind(@r0, msg.single_int64, (@r0 > 0) ? @r0 : 0) == 3"), + "cel.bind(@r0, msg.single_int64, (@r0 > 0) ? @r0 : 0) == 3", + "cel.@block([msg.single_int64], ((@index0 > 0) ? @index0 : 0) == 3)"), TERNARY_BIND_RHS_ONLY( "false ? false : (msg.single_int64) + ((msg.single_int64 + 1) * 2) == 11", - "false ? false : (cel.bind(@r0, msg.single_int64, @r0 + (@r0 + 1) * 2) == 11)"), + "false ? false : (cel.bind(@r0, msg.single_int64, @r0 + (@r0 + 1) * 2) == 11)", + "cel.@block([msg.single_int64], false ? false : (@index0 + (@index0 + 1) * 2 == 11))"), NESTED_TERNARY( "(msg.single_int64 > 0 ? (msg.single_int32 > 0 ? " + "msg.single_int64 + msg.single_int32 : 0) : 0) == 8", "cel.bind(@r0, msg.single_int64, (@r0 > 0) ? " - + "cel.bind(@r1, msg.single_int32, (@r1 > 0) ? (@r0 + @r1) : 0) : 0) == 8"), + + "cel.bind(@r1, msg.single_int32, (@r1 > 0) ? (@r0 + @r1) : 0) : 0) == 8", + "cel.@block([msg.single_int64, msg.single_int32], ((@index0 > 0) ? ((@index1 > 0) ?" + + " (@index0 + @index1) : 0) : 0) == 8)"), MULTIPLE_MACROS( // Note that all of these have different iteration variables, but they are still logically // the same. "size([[1].exists(i, i > 0)]) + size([[1].exists(j, j > 0)]) + " + "size([[2].exists(k, k > 1)]) + size([[2].exists(l, l > 1)]) == 4", "cel.bind(@r1, size([[2].exists(@c0, @c0 > 1)]), " - + "cel.bind(@r0, size([[1].exists(@c0, @c0 > 0)]), @r0 + @r0) + @r1 + @r1) == 4"), + + "cel.bind(@r0, size([[1].exists(@c0, @c0 > 0)]), @r0 + @r0) + @r1 + @r1) == 4", + "cel.@block([size([[1].exists(@c0, @c0 > 0)]), size([[2].exists(@c0, @c0 > 1)])], @index0 +" + + " @index0 + @index1 + @index1 == 4)"), NESTED_MACROS( "[1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [[2, 3, 4], [2, 3, 4], [2, 3, 4]]", "cel.bind(@r0, [1, 2, 3], @r0.map(@c0, @r0.map(@c1, @c1 + 1))) == " - + "cel.bind(@r1, [2, 3, 4], [@r1, @r1, @r1])"), + + "cel.bind(@r1, [2, 3, 4], [@r1, @r1, @r1])", + "cel.@block([[1, 2, 3], [2, 3, 4]], @index0.map(@c0, @index0.map(@c1, @c1 + 1)) ==" + + " [@index1, @index1, @index1])"), INCLUSION_LIST( "1 in [1,2,3] && 2 in [1,2,3] && 3 in [3, [1,2,3]] && 1 in [1,2,3]", "cel.bind(@r0, [1, 2, 3], cel.bind(@r1, 1 in @r0, @r1 && 2 in @r0 && 3 in [3, @r0] &&" - + " @r1))"), + + " @r1))", + "cel.@block([[1, 2, 3], 1 in @index0], @index1 && 2 in @index0 && 3 in [3, @index0] &&" + + " @index1)"), INCLUSION_MAP( "2 in {'a': 1, 2: {true: false}, 3: {true: false}}", - "2 in cel.bind(@r0, {true: false}, {\"a\": 1, 2: @r0, 3: @r0})"), + "2 in cel.bind(@r0, {true: false}, {\"a\": 1, 2: @r0, 3: @r0})", + "cel.@block([{true: false}], 2 in {\"a\": 1, 2: @index0, 3: @index0})"), MACRO_SHADOWED_VARIABLE( "[x - 1 > 3 ? x - 1 : 5].exists(x, x - 1 > 3) || x - 1 > 3", "cel.bind(@r0, x - 1, cel.bind(@r1, @r0 > 3, [@r1 ? @r0 : 5].exists(@c0, @c0 - 1 > 3) ||" - + " @r1))"), + + " @r1))", + "cel.@block([x - 1, @index0 > 3], [@index1 ? @index0 : 5].exists(@c0, @c0 - 1 > 3) ||" + + " @index1)"), MACRO_SHADOWED_VARIABLE_2( "size([\"foo\", \"bar\"].map(x, [x + x, x + x]).map(x, [x + x, x + x])) == 2", "size([\"foo\", \"bar\"].map(@c1, cel.bind(@r0, @c1 + @c1, [@r0, @r0]))" - + ".map(@c0, cel.bind(@r1, @c0 + @c0, [@r1, @r1]))) == 2"), + + ".map(@c0, cel.bind(@r1, @c0 + @c0, [@r1, @r1]))) == 2", + "Currently Unsupported"), // TODO: Handle comprehension variables that fall + // outside the cel.block scope PRESENCE_TEST( "has({'a': true}.a) && {'a':true}['a']", - "cel.bind(@r0, {\"a\": true}, has(@r0.a) && @r0[\"a\"])"), + "cel.bind(@r0, {\"a\": true}, has(@r0.a) && @r0[\"a\"])", + "cel.@block([{\"a\": true}], has(@index0.a) && @index0[\"a\"])"), PRESENCE_TEST_WITH_TERNARY( "(has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : 0) == 10", - "cel.bind(@r0, msg.oneof_type, has(@r0.payload) ? @r0.payload.single_int64 : 0) == 10"), + "cel.bind(@r0, msg.oneof_type, has(@r0.payload) ? @r0.payload.single_int64 : 0) == 10", + "cel.@block([msg.oneof_type], (has(@index0.payload) ? @index0.payload.single_int64 : 0) ==" + + " 10)"), PRESENCE_TEST_WITH_TERNARY_2( "(has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 :" + " msg.oneof_type.payload.single_int64 * 0) == 10", "cel.bind(@r0, msg.oneof_type, cel.bind(@r1, @r0.payload.single_int64, has(@r0.payload) ?" - + " @r1 : (@r1 * 0))) == 10"), + + " @r1 : (@r1 * 0))) == 10", + "cel.@block([msg.oneof_type, @index0.payload.single_int64], (has(@index0.payload) ? @index1" + + " : (@index1 * 0)) == 10)"), PRESENCE_TEST_WITH_TERNARY_3( "(has(msg.oneof_type.payload.single_int64) ? msg.oneof_type.payload.single_int64 :" + " msg.oneof_type.payload.single_int64 * 0) == 10", "cel.bind(@r0, msg.oneof_type.payload, cel.bind(@r1, @r0.single_int64," - + " has(@r0.single_int64) ? @r1 : (@r1 * 0))) == 10"), + + " has(@r0.single_int64) ? @r1 : (@r1 * 0))) == 10", + "cel.@block([msg.oneof_type.payload, @index0.single_int64], (has(@index0.single_int64) ?" + + " @index1 : (@index1 * 0)) == 10)"), /** * Input: * @@ -414,6 +551,7 @@ private enum CseTestCase { * Unparsed: * *
{@code
+     * // With binds
      * cel.bind(
      *   @r0, msg.oneof_type,
      *   cel.bind(
@@ -427,6 +565,22 @@ private enum CseTestCase {
      *   ),
      * )
      * }
+ *
{@code
+     * // With block
+     * cel.@block(
+     *   [
+     *     msg.oneof_type,
+     *     @index0.payload,
+     *     @index1.map_string_string
+     *   ],
+     *   (has(msg.oneof_type) && has(@index0.payload) && has(@index1.single_int64)) ?
+     *     (
+     *       (has(@index1.map_string_string) && has(@index2.key)) ?
+     *         (@index2.key == "A") : false
+     *     )
+     *     : false
+     *   )
+     * }
*/ PRESENCE_TEST_WITH_TERNARY_NESTED( "(has(msg.oneof_type) && has(msg.oneof_type.payload) &&" @@ -437,41 +591,59 @@ private enum CseTestCase { "cel.bind(@r0, msg.oneof_type, cel.bind(@r1, @r0.payload, (has(msg.oneof_type) &&" + " has(@r0.payload) && has(@r1.single_int64)) ? cel.bind(@r2, @r1.map_string_string," + " (has(@r1.map_string_string) && has(@r2.key)) ? (@r2.key == \"A\") : false) :" - + " false))"), + + " false))", + "cel.@block([msg.oneof_type, @index0.payload, @index1.map_string_string]," + + " (has(msg.oneof_type) && has(@index0.payload) && has(@index1.single_int64)) ?" + + " ((has(@index1.map_string_string) && has(@index2.key)) ? (@index2.key == \"A\") :" + + " false) : false)"), OPTIONAL_LIST( "[10, ?optional.none(), [?optional.none(), ?opt_x], [?optional.none(), ?opt_x]] == [10," + " [5], [5]]", "cel.bind(@r0, [?optional.none(), ?opt_x], [10, ?optional.none(), @r0, @r0]) ==" - + " cel.bind(@r1, [5], [10, @r1, @r1])"), + + " cel.bind(@r1, [5], [10, @r1, @r1])", + "cel.@block([[?optional.none(), ?opt_x], [5]], [10, ?optional.none(), @index0, @index0] ==" + + " [10, @index1, @index1])"), OPTIONAL_MAP( "{?'hello': optional.of('hello')}['hello'] + {?'hello': optional.of('hello')}['hello'] ==" + " 'hellohello'", "cel.bind(@r0, {?\"hello\": optional.of(\"hello\")}[\"hello\"], @r0 + @r0) ==" - + " \"hellohello\""), + + " \"hellohello\"", + "cel.@block([{?\"hello\": optional.of(\"hello\")}[\"hello\"]], @index0 + @index0 ==" + + " \"hellohello\")"), OPTIONAL_MESSAGE( "TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32:" + " optional.of(4)}.single_int32 + TestAllTypes{?single_int64:" + " optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}.single_int64 == 5", "cel.bind(@r0, TestAllTypes{" + "?single_int64: optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}, " - + "@r0.single_int32 + @r0.single_int64) == 5"), + + "@r0.single_int32 + @r0.single_int64) == 5", + "cel.@block([TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32:" + + " optional.of(4)}], @index0.single_int32 + @index0.single_int64 == 5)"), ; private final String source; - private final String unparsed; + private final String unparsedBind; + private final String unparsedBlock; - CseTestCase(String source, String unparsed) { + CseTestCase(String source, String unparsedBind, String unparsedBlock) { this.source = source; - this.unparsed = unparsed; + this.unparsedBind = unparsedBind; + this.unparsedBlock = unparsedBlock; } } @Test - public void cse_withMacroMapPopulated_success(@TestParameter CseTestCase testCase) + public void cse_withCelBind_macroMapPopulated(@TestParameter CseTestCase testCase) throws Exception { CelAbstractSyntaxTree ast = CEL.compile(testCase.source).getAst(); - CelAbstractSyntaxTree optimizedAst = CEL_OPTIMIZER.optimize(ast); + CelAbstractSyntaxTree optimizedAst = + newCseOptimizer( + SubexpressionOptimizerOptions.newBuilder() + .populateMacroCalls(true) + .enableCelBlock(false) + .build()) + .optimize(ast); assertThat( CEL.createProgram(optimizedAst) @@ -479,27 +651,25 @@ public void cse_withMacroMapPopulated_success(@TestParameter CseTestCase testCas ImmutableMap.of( "msg", TEST_ALL_TYPES_INPUT, "x", 5L, "opt_x", Optional.of(5L)))) .isEqualTo(true); - assertThat(CEL_UNPARSER.unparse(optimizedAst)).isEqualTo(testCase.unparsed); + assertThat(CEL_UNPARSER.unparse(optimizedAst)).isEqualTo(testCase.unparsedBind); } @Test - public void cse_withoutMacroMap_success(@TestParameter CseTestCase testCase) throws Exception { - Cel celWithoutMacroMap = - newCelBuilder() - .setOptions( - CelOptions.current().populateMacroCalls(false).enableTimestampEpoch(true).build()) - .build(); - CelAbstractSyntaxTree ast = celWithoutMacroMap.compile(testCase.source).getAst(); + public void cse_withCelBind_macroMapUnpopulated(@TestParameter CseTestCase testCase) + throws Exception { + CelBuilder celWithoutMacroMap = + newCelBuilder().setOptions(CelOptions.current().enableTimestampEpoch(true).build()); + CelAbstractSyntaxTree ast = celWithoutMacroMap.build().compile(testCase.source).getAst(); CelAbstractSyntaxTree optimizedAst = - CelOptimizerFactory.standardCelOptimizerBuilder(celWithoutMacroMap) - .addAstOptimizers(SubexpressionOptimizer.getInstance()) - .build() + newCseOptimizer( + SubexpressionOptimizerOptions.newBuilder().populateMacroCalls(false).build()) .optimize(ast); assertThat(optimizedAst.getSource().getMacroCalls()).isEmpty(); assertThat( celWithoutMacroMap + .build() .createProgram(optimizedAst) .eval( ImmutableMap.of( @@ -507,6 +677,108 @@ public void cse_withoutMacroMap_success(@TestParameter CseTestCase testCase) thr .isEqualTo(true); } + @Test + public void cse_withCelBlock_macroMapPopulated(@TestParameter CseTestCase testCase) + throws Exception { + if (testCase.equals(CseTestCase.MACRO_SHADOWED_VARIABLE_2)) { + // TODO: Handle comprehension variables that fall outside the cel.block scope + return; + } + CelOptimizer celOptimizer = + newCseOptimizer( + SubexpressionOptimizerOptions.newBuilder() + .populateMacroCalls(true) + .enableCelBlock(true) + .build()); + CelAbstractSyntaxTree ast = CEL.compile(testCase.source).getAst(); + + CelAbstractSyntaxTree optimizedAst = celOptimizer.optimize(ast); + + assertThat( + CEL.createProgram(optimizedAst) + .eval( + ImmutableMap.of( + "msg", TEST_ALL_TYPES_INPUT, "x", 5L, "opt_x", Optional.of(5L)))) + .isEqualTo(true); + assertThat(CEL_UNPARSER.unparse(optimizedAst)).isEqualTo(testCase.unparsedBlock); + } + + @Test + public void cse_withCelBlock_macroMapUnpopulated(@TestParameter CseTestCase testCase) + throws Exception { + if (testCase.equals(CseTestCase.MACRO_SHADOWED_VARIABLE_2)) { + // TODO: Handle comprehension variables that fall outside the cel.block scope + return; + } + CelOptimizer celOptimizer = + newCseOptimizer( + SubexpressionOptimizerOptions.newBuilder() + .populateMacroCalls(false) + .enableCelBlock(true) + .build()); + CelAbstractSyntaxTree ast = CEL.compile(testCase.source).getAst(); + + CelAbstractSyntaxTree optimizedAst = celOptimizer.optimize(ast); + + assertThat(optimizedAst.getSource().getMacroCalls()).isEmpty(); + assertThat( + CEL.createProgram(optimizedAst) + .eval( + ImmutableMap.of( + "msg", TEST_ALL_TYPES_INPUT, "x", 5L, "opt_x", Optional.of(5L)))) + .isEqualTo(true); + } + + @Test + public void cse_resultTypeSet_celBlockOptimizationSuccess() throws Exception { + Cel cel = newCelBuilder().setResultType(SimpleType.BOOL).build(); + CelOptimizer celOptimizer = + CelOptimizerFactory.standardCelOptimizerBuilder(cel) + .addAstOptimizers( + SubexpressionOptimizer.newInstance( + SubexpressionOptimizerOptions.newBuilder().enableCelBlock(true).build())) + .build(); + CelAbstractSyntaxTree ast = CEL.compile("size('a') + size('a') == 2").getAst(); + + CelAbstractSyntaxTree optimizedAst = celOptimizer.optimize(ast); + + assertThat(CEL.createProgram(optimizedAst).eval()).isEqualTo(true); + assertThat(CEL_UNPARSER.unparse(optimizedAst)) + .isEqualTo("cel.@block([size(\"a\")], @index0 + @index0 == 2)"); + } + + @Test + // Nothing to optimize + @TestParameters("{source: 'size(\"hello\")'}") + // Constants and identifiers + @TestParameters("{source: '2 + 2 + 2 + 2'}") + @TestParameters("{source: 'x + x + x + x'}") + @TestParameters("{source: 'true == true && false == false'}") + // Constants and identifiers within a function + @TestParameters("{source: 'size(\"hello\" + \"hello\" + \"hello\")'}") + @TestParameters("{source: 'string(x + x + x)'}") + // Non-standard functions are considered non-pure for time being + @TestParameters("{source: 'custom_func(1) + custom_func(1)'}") + // Duplicated but nested calls. + @TestParameters("{source: 'int(timestamp(int(timestamp(1000000000))))'}") + // This cannot be optimized. Extracting the common subexpression would presence test + // the bound identifier (e.g: has(@r0)), which is not valid. + @TestParameters("{source: 'has(msg.single_any) ? msg.single_any : 10'}") + public void cse_withCelBind_noop(String source) throws Exception { + CelAbstractSyntaxTree ast = CEL.compile(source).getAst(); + + CelAbstractSyntaxTree optimizedAst = + newCseOptimizer( + SubexpressionOptimizerOptions.newBuilder() + .populateMacroCalls(true) + .enableCelBlock(false) + .build()) + .optimize(ast); + + assertThat(ast.getExpr()).isEqualTo(optimizedAst.getExpr()); + assertThat(CEL_UNPARSER.unparse(optimizedAst)).isEqualTo(source); + } + @Test // Nothing to optimize @TestParameters("{source: 'size(\"hello\")'}") @@ -524,10 +796,16 @@ public void cse_withoutMacroMap_success(@TestParameter CseTestCase testCase) thr // This cannot be optimized. Extracting the common subexpression would presence test // the bound identifier (e.g: has(@r0)), which is not valid. @TestParameters("{source: 'has(msg.single_any) ? msg.single_any : 10'}") - public void cse_noop(String source) throws Exception { + public void cse_withCelBlock_noop(String source) throws Exception { CelAbstractSyntaxTree ast = CEL.compile(source).getAst(); - CelAbstractSyntaxTree optimizedAst = CEL_OPTIMIZER.optimize(ast); + CelAbstractSyntaxTree optimizedAst = + newCseOptimizer( + SubexpressionOptimizerOptions.newBuilder() + .populateMacroCalls(true) + .enableCelBlock(true) + .build()) + .optimize(ast); assertThat(ast.getExpr()).isEqualTo(optimizedAst.getExpr()); assertThat(CEL_UNPARSER.unparse(optimizedAst)).isEqualTo(source); @@ -548,7 +826,13 @@ public void cse_largeCalcExpr() throws Exception { } CelAbstractSyntaxTree ast = CEL.compile(sb.toString()).getAst(); - CelAbstractSyntaxTree optimizedAst = CEL_OPTIMIZER.optimize(ast); + CelAbstractSyntaxTree optimizedAst = + newCseOptimizer( + SubexpressionOptimizerOptions.newBuilder() + .populateMacroCalls(true) + .enableCelBlock(false) + .build()) + .optimize(ast); assertThat(CEL_UNPARSER.unparse(optimizedAst)) .isEqualTo( @@ -582,7 +866,13 @@ public void cse_largeNestedBinds() throws Exception { } CelAbstractSyntaxTree ast = CEL.compile(sb.toString()).getAst(); - CelAbstractSyntaxTree optimizedAst = CEL_OPTIMIZER.optimize(ast); + CelAbstractSyntaxTree optimizedAst = + newCseOptimizer( + SubexpressionOptimizerOptions.newBuilder() + .populateMacroCalls(true) + .enableCelBlock(false) + .build()) + .optimize(ast); assertThat(CEL_UNPARSER.unparse(optimizedAst)) .isEqualTo( @@ -620,7 +910,58 @@ public void cse_largeNestedBinds() throws Exception { } @Test - public void cse_largeNestedMacro() throws Exception { + public void cse_largeFlattenedBlocks() throws Exception { + StringBuilder sb = new StringBuilder(); + int limit = 50; + for (int i = 0; i < limit; i++) { + sb.append(String.format("size([%d, %d]) + ", i, i + 1)); + sb.append(String.format("size([%d, %d]) ", i, i + 1)); + if (i < limit - 1) { + sb.append("+"); + } + } + CelAbstractSyntaxTree ast = CEL.compile(sb.toString()).getAst(); + + CelAbstractSyntaxTree optimizedAst = + newCseOptimizer( + SubexpressionOptimizerOptions.newBuilder() + .populateMacroCalls(true) + .enableCelBlock(true) + .build()) + .optimize(ast); + + assertThat(CEL_UNPARSER.unparse(optimizedAst)) + .isEqualTo( + "cel.@block([size([0, 1]), size([1, 2]), size([2, 3]), size([3, 4]), size([4, 5])," + + " size([5, 6]), size([6, 7]), size([7, 8]), size([8, 9]), size([9, 10])," + + " size([10, 11]), size([11, 12]), size([12, 13]), size([13, 14]), size([14, 15])," + + " size([15, 16]), size([16, 17]), size([17, 18]), size([18, 19]), size([19, 20])," + + " size([20, 21]), size([21, 22]), size([22, 23]), size([23, 24]), size([24, 25])," + + " size([25, 26]), size([26, 27]), size([27, 28]), size([28, 29]), size([29, 30])," + + " size([30, 31]), size([31, 32]), size([32, 33]), size([33, 34]), size([34, 35])," + + " size([35, 36]), size([36, 37]), size([37, 38]), size([38, 39]), size([39, 40])," + + " size([40, 41]), size([41, 42]), size([42, 43]), size([43, 44]), size([44, 45])," + + " size([45, 46]), size([46, 47]), size([47, 48]), size([48, 49]), size([49," + + " 50])], @index0 + @index0 + @index1 + @index1 + @index2 + @index2 + @index3 +" + + " @index3 + @index4 + @index4 + @index5 + @index5 + @index6 + @index6 + @index7 +" + + " @index7 + @index8 + @index8 + @index9 + @index9 + @index10 + @index10 +" + + " @index11 + @index11 + @index12 + @index12 + @index13 + @index13 + @index14 +" + + " @index14 + @index15 + @index15 + @index16 + @index16 + @index17 + @index17 +" + + " @index18 + @index18 + @index19 + @index19 + @index20 + @index20 + @index21 +" + + " @index21 + @index22 + @index22 + @index23 + @index23 + @index24 + @index24 +" + + " @index25 + @index25 + @index26 + @index26 + @index27 + @index27 + @index28 +" + + " @index28 + @index29 + @index29 + @index30 + @index30 + @index31 + @index31 +" + + " @index32 + @index32 + @index33 + @index33 + @index34 + @index34 + @index35 +" + + " @index35 + @index36 + @index36 + @index37 + @index37 + @index38 + @index38 +" + + " @index39 + @index39 + @index40 + @index40 + @index41 + @index41 + @index42 +" + + " @index42 + @index43 + @index43 + @index44 + @index44 + @index45 + @index45 +" + + " @index46 + @index46 + @index47 + @index47 + @index48 + @index48 + @index49 +" + + " @index49)"); + assertThat(CEL.createProgram(optimizedAst).eval()).isEqualTo(200L); + } + + @Test + public void cse_withCelBind_largeNestedMacro() throws Exception { StringBuilder sb = new StringBuilder(); sb.append("size([1,2,3]"); int limit = 8; @@ -639,7 +980,13 @@ public void cse_largeNestedMacro() throws Exception { } CelAbstractSyntaxTree ast = CEL.compile(sb.toString()).getAst(); - CelAbstractSyntaxTree optimizedAst = CEL_OPTIMIZER.optimize(ast); + CelAbstractSyntaxTree optimizedAst = + newCseOptimizer( + SubexpressionOptimizerOptions.newBuilder() + .populateMacroCalls(true) + .enableCelBlock(false) + .build()) + .optimize(ast); assertThat(CEL_UNPARSER.unparse(optimizedAst)) .isEqualTo( @@ -649,6 +996,43 @@ public void cse_largeNestedMacro() throws Exception { assertThat(CEL.createProgram(optimizedAst).eval()).isEqualTo(27); } + @Test + public void cse_withCelBlock_largeNestedMacro() throws Exception { + StringBuilder sb = new StringBuilder(); + sb.append("size([1,2,3]"); + int limit = 8; + for (int i = 0; i < limit; i++) { + sb.append(".map(i, [1, 2, 3]"); + } + for (int i = 0; i < limit; i++) { + sb.append(")"); + } + sb.append(")"); + String nestedMapCallExpr = sb.toString(); // size([1,2,3].map(i, [1,2,3].map(i, [1,2,3].map(... + // Add this large macro call 8 times + for (int i = 0; i < limit; i++) { + sb.append("+"); + sb.append(nestedMapCallExpr); + } + CelAbstractSyntaxTree ast = CEL.compile(sb.toString()).getAst(); + + CelAbstractSyntaxTree optimizedAst = + newCseOptimizer( + SubexpressionOptimizerOptions.newBuilder() + .populateMacroCalls(true) + .enableCelBlock(true) + .build()) + .optimize(ast); + + assertThat(CEL_UNPARSER.unparse(optimizedAst)) + .isEqualTo( + "cel.@block([[1, 2, 3], size(@index0.map(@c0, @index0.map(@c1, @index0.map(@c2," + + " @index0.map(@c3, @index0.map(@c4, @index0.map(@c5, @index0.map(@c6," + + " @index0.map(@c7, @index0)))))))))], @index1 + @index1 + @index1 + @index1 +" + + " @index1 + @index1 + @index1 + @index1 + @index1)"); + assertThat(CEL.createProgram(optimizedAst).eval()).isEqualTo(27); + } + @Test public void cse_applyConstFoldingAfter() throws Exception { CelAbstractSyntaxTree ast = @@ -658,7 +1042,7 @@ public void cse_applyConstFoldingAfter() throws Exception { CelOptimizerFactory.standardCelOptimizerBuilder(CEL) .addAstOptimizers( SubexpressionOptimizer.newInstance( - SubexpressionOptimizerOptions.newBuilder().populateMacroCalls(true).build()), + SubexpressionOptimizerOptions.newBuilder().build()), ConstantFoldingOptimizer.getInstance()) .build(); @@ -677,7 +1061,31 @@ public void cse_applyConstFoldingAfter() throws Exception { } @Test - public void iterationLimitReached_throws() throws Exception { + @TestParameters("{enableCelBlock: false, unparsed: 'cel.bind(@r0, size(x), @r0 + @r0)'}") + @TestParameters("{enableCelBlock: true, unparsed: 'cel.@block([size(x)], @index0 + @index0)'}") + public void cse_applyConstFoldingAfter_nothingToFold(boolean enableCelBlock, String unparsed) + throws Exception { + CelAbstractSyntaxTree ast = CEL.compile("size(x) + size(x)").getAst(); + CelOptimizer optimizer = + CelOptimizerFactory.standardCelOptimizerBuilder(CEL) + .addAstOptimizers( + SubexpressionOptimizer.newInstance( + SubexpressionOptimizerOptions.newBuilder() + .populateMacroCalls(true) + .enableCelBlock(enableCelBlock) + .build()), + ConstantFoldingOptimizer.getInstance()) + .build(); + + CelAbstractSyntaxTree optimizedAst = optimizer.optimize(ast); + + assertThat(CEL_UNPARSER.unparse(optimizedAst)).isEqualTo(unparsed); + } + + @Test + @TestParameters("{enableCelBlock: false}") + @TestParameters("{enableCelBlock: true}") + public void iterationLimitReached_throws(boolean enableCelBlock) throws Exception { StringBuilder largeExprBuilder = new StringBuilder(); int iterationLimit = 100; for (int i = 0; i < iterationLimit; i++) { @@ -692,13 +1100,11 @@ public void iterationLimitReached_throws() throws Exception { assertThrows( CelOptimizationException.class, () -> - CelOptimizerFactory.standardCelOptimizerBuilder(CEL) - .addAstOptimizers( - SubexpressionOptimizer.newInstance( - SubexpressionOptimizerOptions.newBuilder() - .iterationLimit(iterationLimit) - .build())) - .build() + newCseOptimizer( + SubexpressionOptimizerOptions.newBuilder() + .iterationLimit(iterationLimit) + .enableCelBlock(enableCelBlock) + .build()) .optimize(ast)); assertThat(e).hasMessageThat().isEqualTo("Optimization failure: Max iteration count reached."); } From 496ab085793fab6a666b6b21c73ce4273c114531 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Thu, 15 Feb 2024 16:53:44 -0800 Subject: [PATCH 031/486] Tag AST containing cel.block call PiperOrigin-RevId: 607499642 --- .../main/java/dev/cel/common/CelSource.java | 14 ++++++----- .../java/dev/cel/optimizer/MutableAst.java | 5 ++-- .../optimizers/SubexpressionOptimizer.java | 22 +++++++++++++++-- .../dev/cel/optimizer/MutableAstTest.java | 21 ++++++++++++++++ .../SubexpressionOptimizerTest.java | 24 +++++++++++++++++++ 5 files changed, 76 insertions(+), 10 deletions(-) diff --git a/common/src/main/java/dev/cel/common/CelSource.java b/common/src/main/java/dev/cel/common/CelSource.java index 3f4c0d2d7..62a74873a 100644 --- a/common/src/main/java/dev/cel/common/CelSource.java +++ b/common/src/main/java/dev/cel/common/CelSource.java @@ -184,6 +184,7 @@ public Builder toBuilder() { return new Builder(codePoints, lineOffsets) .setDescription(description) .addPositionsMap(positions) + .addAllExtensions(extensions) .addAllMacroCalls(macroCalls); } @@ -354,7 +355,7 @@ private LineAndOffset(int line, int offset) { */ @AutoValue @Immutable - abstract static class Extension { + public abstract static class Extension { /** Identifier for the extension. Example: constant_folding */ abstract String id(); @@ -371,9 +372,10 @@ abstract static class Extension { */ abstract ImmutableList affectedComponents(); + /** Version of the extension */ @AutoValue @Immutable - abstract static class Version { + public abstract static class Version { /** * Major version changes indicate different required support level from the required @@ -388,13 +390,13 @@ abstract static class Version { abstract long minor(); /** Create a new instance of Version with the provided major and minor values. */ - static Version of(long major, long minor) { + public static Version of(long major, long minor) { return new AutoValue_CelSource_Extension_Version(major, minor); } } /** CEL component specifier. */ - enum Component { + public enum Component { /** Unspecified, default. */ COMPONENT_UNSPECIFIED, /** Parser. Converts a CEL string to an AST. */ @@ -406,14 +408,14 @@ enum Component { } @CheckReturnValue - static Extension create(String id, Version version, Iterable components) { + public static Extension create(String id, Version version, Iterable components) { checkNotNull(version); checkNotNull(components); return new AutoValue_CelSource_Extension(id, version, ImmutableList.copyOf(components)); } @CheckReturnValue - static Extension create(String id, Version version, Component... components) { + public static Extension create(String id, Version version, Component... components) { return create(id, version, Arrays.asList(components)); } } diff --git a/optimizer/src/main/java/dev/cel/optimizer/MutableAst.java b/optimizer/src/main/java/dev/cel/optimizer/MutableAst.java index 5562428ca..5798006c7 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/MutableAst.java +++ b/optimizer/src/main/java/dev/cel/optimizer/MutableAst.java @@ -456,11 +456,12 @@ private CelSource normalizeMacroSource( ExprIdGenerator idGenerator) { // Remove the macro metadata that no longer exists in the AST due to being replaced. celSource = celSource.toBuilder().clearMacroCall(exprIdToReplace).build(); + CelSource.Builder sourceBuilder = + CelSource.newBuilder().addAllExtensions(celSource.getExtensions()); if (celSource.getMacroCalls().isEmpty()) { - return CelSource.newBuilder().build(); + return sourceBuilder.build(); } - CelSource.Builder sourceBuilder = CelSource.newBuilder(); ImmutableMap allExprs = CelNavigableExpr.fromExpr(mutatedRoot.build()) .allNodes() diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java index 150a91dc5..b62267bd1 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java @@ -29,6 +29,9 @@ import dev.cel.common.CelFunctionDecl; import dev.cel.common.CelOverloadDecl; import dev.cel.common.CelSource; +import dev.cel.common.CelSource.Extension; +import dev.cel.common.CelSource.Extension.Component; +import dev.cel.common.CelSource.Extension.Version; import dev.cel.common.CelValidationException; import dev.cel.common.ast.CelExpr; import dev.cel.common.ast.CelExpr.CelCall; @@ -87,6 +90,10 @@ public class SubexpressionOptimizer implements CelAstOptimizer { stream(Operator.values()).map(Operator::getFunction), stream(Standard.Function.values()).map(Standard.Function::getFunction)) .collect(toImmutableSet()); + + private static final Extension CEL_BLOCK_AST_EXTENSION_TAG = + Extension.create("cel_block", Version.of(1L, 1L), Component.COMPONENT_RUNTIME); + private final SubexpressionOptimizerOptions cseOptions; private final MutableAst mutableAst; @@ -209,7 +216,16 @@ private CelAbstractSyntaxTree optimizeUsingCelBlock( // Restore the expected result type the environment had prior to optimization. celBuilder.setResultType(resultType); - return astToModify; + + return tagAstExtension(astToModify); + } + + private static CelAbstractSyntaxTree tagAstExtension(CelAbstractSyntaxTree ast) { + // Tag the extension + CelSource.Builder celSourceBuilder = + ast.getSource().toBuilder().addAllExtensions(CEL_BLOCK_AST_EXTENSION_TAG); + + return CelAbstractSyntaxTree.newParsedAst(ast.getExpr(), celSourceBuilder.build()); } /** @@ -510,7 +526,9 @@ public abstract static class Builder { /** * Rewrites the optimized AST using cel.@block call instead of cascaded cel.bind macros, aimed - * to produce a more compact AST. + * to produce a more compact AST. {@link com.google.api.expr.SourceInfo.Extension} field will + * be populated in the AST to inform that special runtime support is required to evaluate the + * optimized expression. */ public abstract Builder enableCelBlock(boolean value); diff --git a/optimizer/src/test/java/dev/cel/optimizer/MutableAstTest.java b/optimizer/src/test/java/dev/cel/optimizer/MutableAstTest.java index d027c6b8e..bd9d122cf 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/MutableAstTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/MutableAstTest.java @@ -27,6 +27,9 @@ import dev.cel.common.CelFunctionDecl; import dev.cel.common.CelOptions; import dev.cel.common.CelOverloadDecl; +import dev.cel.common.CelSource; +import dev.cel.common.CelSource.Extension; +import dev.cel.common.CelSource.Extension.Version; import dev.cel.common.ast.CelConstant; import dev.cel.common.ast.CelExpr; import dev.cel.common.ast.CelExpr.CelCall; @@ -99,6 +102,7 @@ public void mutableAst_nonMacro_sourceCleared() throws Exception { assertThat(mutatedAst.getSource().getDescription()).isEmpty(); assertThat(mutatedAst.getSource().getLineOffsets()).isEmpty(); assertThat(mutatedAst.getSource().getPositionsMap()).isEmpty(); + assertThat(mutatedAst.getSource().getExtensions()).isEmpty(); assertThat(mutatedAst.getSource().getMacroCalls()).isEmpty(); } @@ -113,9 +117,26 @@ public void mutableAst_macro_sourceMacroCallsPopulated() throws Exception { assertThat(mutatedAst.getSource().getDescription()).isEmpty(); assertThat(mutatedAst.getSource().getLineOffsets()).isEmpty(); assertThat(mutatedAst.getSource().getPositionsMap()).isEmpty(); + assertThat(mutatedAst.getSource().getExtensions()).isEmpty(); assertThat(mutatedAst.getSource().getMacroCalls()).isNotEmpty(); } + @Test + public void mutableAst_astContainsTaggedExtension_retained() throws Exception { + CelAbstractSyntaxTree ast = CEL.compile("has(TestAllTypes{}.single_int32)").getAst(); + Extension extension = Extension.create("test", Version.of(1, 1)); + CelSource celSource = ast.getSource().toBuilder().addAllExtensions(extension).build(); + ast = + CelAbstractSyntaxTree.newCheckedAst( + ast.getExpr(), celSource, ast.getReferenceMap(), ast.getTypeMap()); + + CelAbstractSyntaxTree mutatedAst = + MUTABLE_AST.replaceSubtree( + ast, CelExpr.newBuilder().setConstant(CelConstant.ofValue(true)).build(), 1); + + assertThat(mutatedAst.getSource().getExtensions()).containsExactly(extension); + } + @Test @TestParameters("{source: '[1].exists(x, x > 0)', expectedMacroCallSize: 1}") @TestParameters( diff --git a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java index 377756fc9..ae8bc7f16 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java @@ -30,6 +30,9 @@ import dev.cel.common.CelFunctionDecl; import dev.cel.common.CelOptions; import dev.cel.common.CelOverloadDecl; +import dev.cel.common.CelSource.Extension; +import dev.cel.common.CelSource.Extension.Component; +import dev.cel.common.CelSource.Extension.Version; import dev.cel.common.CelValidationException; import dev.cel.common.CelVarDecl; import dev.cel.common.ast.CelConstant; @@ -1109,6 +1112,27 @@ public void iterationLimitReached_throws(boolean enableCelBlock) throws Exceptio assertThat(e).hasMessageThat().isEqualTo("Optimization failure: Max iteration count reached."); } + @Test + public void celBlock_astExtensionTagged() throws Exception { + CelAbstractSyntaxTree ast = CEL.compile("size(x) + size(x)").getAst(); + CelOptimizer optimizer = + CelOptimizerFactory.standardCelOptimizerBuilder(CEL) + .addAstOptimizers( + SubexpressionOptimizer.newInstance( + SubexpressionOptimizerOptions.newBuilder() + .populateMacroCalls(true) + .enableCelBlock(true) + .build()), + ConstantFoldingOptimizer.getInstance()) + .build(); + + CelAbstractSyntaxTree optimizedAst = optimizer.optimize(ast); + + assertThat(optimizedAst.getSource().getExtensions()) + .containsExactly( + Extension.create("cel_block", Version.of(1L, 1L), Component.COMPONENT_RUNTIME)); + } + private enum BlockTestCase { BOOL_LITERAL("cel.block([true, false], index0 || index1)"), STRING_CONCAT("cel.block(['a' + 'b', index0 + 'c'], index1 + 'd') == 'abcd'"), From 629f85b5ad8b5db0ac113eea864f74d20616e4dd Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Thu, 15 Feb 2024 17:20:32 -0800 Subject: [PATCH 032/486] Add mangled comprehension variables as identifier declaration to the environment PiperOrigin-RevId: 607507168 --- .../java/dev/cel/optimizer/MutableAst.java | 26 ++++++- .../optimizers/SubexpressionOptimizer.java | 59 ++++++++++++--- .../dev/cel/optimizer/MutableAstTest.java | 9 ++- .../SubexpressionOptimizerTest.java | 72 ++++++++++++++++--- 4 files changed, 143 insertions(+), 23 deletions(-) diff --git a/optimizer/src/main/java/dev/cel/optimizer/MutableAst.java b/optimizer/src/main/java/dev/cel/optimizer/MutableAst.java index 5798006c7..ae2f328e9 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/MutableAst.java +++ b/optimizer/src/main/java/dev/cel/optimizer/MutableAst.java @@ -23,6 +23,7 @@ import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; import com.google.errorprone.annotations.Immutable; import dev.cel.common.CelAbstractSyntaxTree; import dev.cel.common.CelSource; @@ -200,10 +201,11 @@ public CelAbstractSyntaxTree renumberIdsConsecutively(CelAbstractSyntaxTree ast) * @param newIdentPrefix Prefix to use for new identifier names. For example, providing @c will * produce @c0, @c1, @c2... as new names. */ - public CelAbstractSyntaxTree mangleComprehensionIdentifierNames( + public MangledComprehensionAst mangleComprehensionIdentifierNames( CelAbstractSyntaxTree ast, String newIdentPrefix) { int iterCount; CelNavigableAst newNavigableAst = CelNavigableAst.fromAst(ast); + ImmutableSet.Builder mangledComprehensionIdents = ImmutableSet.builder(); for (iterCount = 0; iterCount < iterationLimit; iterCount++) { CelNavigableExpr comprehensionNode = newNavigableAst @@ -223,6 +225,7 @@ public CelAbstractSyntaxTree mangleComprehensionIdentifierNames( String iterVar = comprehensionExpr.comprehension().iterVar(); int comprehensionNestingLevel = countComprehensionNestingLevel(comprehensionNode); String mangledVarName = newIdentPrefix + comprehensionNestingLevel; + mangledComprehensionIdents.add(mangledVarName); CelExpr.Builder mutatedComprehensionExpr = mangleIdentsInComprehensionExpr( @@ -251,7 +254,7 @@ public CelAbstractSyntaxTree mangleComprehensionIdentifierNames( throw new IllegalStateException("Max iteration count reached."); } - return newNavigableAst.getAst(); + return MangledComprehensionAst.of(newNavigableAst.getAst(), mangledComprehensionIdents.build()); } /** @@ -575,6 +578,25 @@ private static int countComprehensionNestingLevel(CelNavigableExpr comprehension return nestedLevel; } + /** + * Intermediate value class to store the mangled identifiers for iteration variable in the + * comprehension. + */ + @AutoValue + public abstract static class MangledComprehensionAst { + + /** AST after the iteration variables have been mangled. */ + public abstract CelAbstractSyntaxTree ast(); + + /** Set of identifiers with the iteration variable mangled. */ + public abstract ImmutableSet mangledComprehensionIdents(); + + private static MangledComprehensionAst of( + CelAbstractSyntaxTree ast, ImmutableSet mangledComprehensionIdents) { + return new AutoValue_MutableAst_MangledComprehensionAst(ast, mangledComprehensionIdents); + } + } + /** * Intermediate value class to store the generated CelExpr for the bind macro and the macro call * information. diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java index b62267bd1..28b5e02a4 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java @@ -33,6 +33,7 @@ import dev.cel.common.CelSource.Extension.Component; import dev.cel.common.CelSource.Extension.Version; import dev.cel.common.CelValidationException; +import dev.cel.common.CelVarDecl; import dev.cel.common.ast.CelExpr; import dev.cel.common.ast.CelExpr.CelCall; import dev.cel.common.ast.CelExpr.CelIdent; @@ -45,6 +46,7 @@ import dev.cel.common.types.SimpleType; import dev.cel.optimizer.CelAstOptimizer; import dev.cel.optimizer.MutableAst; +import dev.cel.optimizer.MutableAst.MangledComprehensionAst; import dev.cel.parser.Operator; import java.util.ArrayList; import java.util.HashMap; @@ -90,10 +92,8 @@ public class SubexpressionOptimizer implements CelAstOptimizer { stream(Operator.values()).map(Operator::getFunction), stream(Standard.Function.values()).map(Standard.Function::getFunction)) .collect(toImmutableSet()); - private static final Extension CEL_BLOCK_AST_EXTENSION_TAG = Extension.create("cel_block", Version.of(1L, 1L), Component.COMPONENT_RUNTIME); - private final SubexpressionOptimizerOptions cseOptions; private final MutableAst mutableAst; @@ -125,10 +125,13 @@ private CelAbstractSyntaxTree optimizeUsingCelBlock( // Retain the original expected result type, so that it can be reset in celBuilder at the end of // the optimization pass. CelType resultType = navigableAst.getAst().getResultType(); - CelAbstractSyntaxTree astToModify = + MangledComprehensionAst mangledComprehensionAst = mutableAst.mangleComprehensionIdentifierNames( navigableAst.getAst(), MANGLED_COMPREHENSION_IDENTIFIER_PREFIX); + CelAbstractSyntaxTree astToModify = mangledComprehensionAst.ast(); CelSource sourceToModify = astToModify.getSource(); + ImmutableSet mangledIdentDecls = + newMangledIdentDecls(celBuilder, mangledComprehensionAst); int blockIdentifierIndex = 0; int iterCount; @@ -187,6 +190,9 @@ private CelAbstractSyntaxTree optimizeUsingCelBlock( return astToModify; } + // Add all mangled comprehension identifiers to the environment, so that the subexpressions can + // retain context to them. + celBuilder.addVarDeclarations(mangledIdentDecls); // Type-check all sub-expressions then add them as block identifiers to the CEL environment addBlockIdentsToEnv(celBuilder, subexpressions); @@ -254,10 +260,47 @@ private static void addBlockIdentsToEnv(CelBuilder celBuilder, List sub } } + private static ImmutableSet newMangledIdentDecls( + CelBuilder celBuilder, MangledComprehensionAst mangledComprehensionAst) { + if (mangledComprehensionAst.mangledComprehensionIdents().isEmpty()) { + return ImmutableSet.of(); + } + CelAbstractSyntaxTree ast = mangledComprehensionAst.ast(); + try { + ast = celBuilder.build().check(ast).getAst(); + } catch (CelValidationException e) { + throw new IllegalStateException("Failed to type-check mangled AST.", e); + } + + ImmutableSet.Builder mangledVarDecls = ImmutableSet.builder(); + for (String ident : mangledComprehensionAst.mangledComprehensionIdents()) { + CelExpr mangledIdentExpr = + CelNavigableAst.fromAst(ast) + .getRoot() + .allNodes() + .filter(node -> node.getKind().equals(Kind.IDENT)) + .map(CelNavigableExpr::expr) + .filter(expr -> expr.ident().name().equals(ident)) + .findAny() + .orElse(null); + if (mangledIdentExpr == null) { + break; + } + + CelType mangledIdentType = + ast.getType(mangledIdentExpr.id()).orElseThrow(() -> new NoSuchElementException("?")); + mangledVarDecls.add(CelVarDecl.newVarDeclaration(ident, mangledIdentType)); + } + + return mangledVarDecls.build(); + } + private CelAbstractSyntaxTree optimizeUsingCelBind(CelNavigableAst navigableAst) { CelAbstractSyntaxTree astToModify = - mutableAst.mangleComprehensionIdentifierNames( - navigableAst.getAst(), MANGLED_COMPREHENSION_IDENTIFIER_PREFIX); + mutableAst + .mangleComprehensionIdentifierNames( + navigableAst.getAst(), MANGLED_COMPREHENSION_IDENTIFIER_PREFIX) + .ast(); CelSource sourceToModify = astToModify.getSource(); int bindIdentifierIndex = 0; @@ -526,9 +569,9 @@ public abstract static class Builder { /** * Rewrites the optimized AST using cel.@block call instead of cascaded cel.bind macros, aimed - * to produce a more compact AST. {@link com.google.api.expr.SourceInfo.Extension} field will - * be populated in the AST to inform that special runtime support is required to evaluate the - * optimized expression. + * to produce a more compact AST. {@link CelSource.Extension} field will be populated in the + * AST to inform that special runtime support is required to evaluate the optimized + * expression. */ public abstract Builder enableCelBlock(boolean value); diff --git a/optimizer/src/test/java/dev/cel/optimizer/MutableAstTest.java b/optimizer/src/test/java/dev/cel/optimizer/MutableAstTest.java index bd9d122cf..9c32520b3 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/MutableAstTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/MutableAstTest.java @@ -681,7 +681,8 @@ public void comprehension_replaceLoopStep() throws Exception { public void mangleComprehensionVariable_singleMacro() throws Exception { CelAbstractSyntaxTree ast = CEL.compile("[false].exists(i, i)").getAst(); - CelAbstractSyntaxTree mangledAst = MUTABLE_AST.mangleComprehensionIdentifierNames(ast, "@c"); + CelAbstractSyntaxTree mangledAst = + MUTABLE_AST.mangleComprehensionIdentifierNames(ast, "@c").ast(); assertThat(mangledAst.getExpr().toString()) .isEqualTo( @@ -741,7 +742,8 @@ public void mangleComprehensionVariable_singleMacro() throws Exception { public void mangleComprehensionVariable_nestedMacroWithShadowedVariables() throws Exception { CelAbstractSyntaxTree ast = CEL.compile("[x].exists(x, [x].exists(x, x == 1))").getAst(); - CelAbstractSyntaxTree mangledAst = MUTABLE_AST.mangleComprehensionIdentifierNames(ast, "@c"); + CelAbstractSyntaxTree mangledAst = + MUTABLE_AST.mangleComprehensionIdentifierNames(ast, "@c").ast(); assertThat(mangledAst.getExpr().toString()) .isEqualTo( @@ -858,7 +860,8 @@ public void mangleComprehensionVariable_nestedMacroWithShadowedVariables() throw public void mangleComprehensionVariable_hasMacro_noOp() throws Exception { CelAbstractSyntaxTree ast = CEL.compile("has(msg.single_int64)").getAst(); - CelAbstractSyntaxTree mangledAst = MUTABLE_AST.mangleComprehensionIdentifierNames(ast, "@c"); + CelAbstractSyntaxTree mangledAst = + MUTABLE_AST.mangleComprehensionIdentifierNames(ast, "@c").ast(); assertThat(CEL_UNPARSER.unparse(mangledAst)).isEqualTo("has(msg.single_int64)"); assertThat( diff --git a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java index ae8bc7f16..cf7cdd6df 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java @@ -91,6 +91,8 @@ public class SubexpressionOptimizerTest { CelOverloadDecl.newGlobalOverload("get_true_overload", SimpleType.BOOL))) // Similarly, this is a test only decl (index0 -> @index0) .addVarDeclarations( + CelVarDecl.newVarDeclaration("c0", SimpleType.DYN), + CelVarDecl.newVarDeclaration("c1", SimpleType.DYN), CelVarDecl.newVarDeclaration("index0", SimpleType.DYN), CelVarDecl.newVarDeclaration("index1", SimpleType.DYN), CelVarDecl.newVarDeclaration("index2", SimpleType.DYN), @@ -506,8 +508,9 @@ private enum CseTestCase { "size([\"foo\", \"bar\"].map(x, [x + x, x + x]).map(x, [x + x, x + x])) == 2", "size([\"foo\", \"bar\"].map(@c1, cel.bind(@r0, @c1 + @c1, [@r0, @r0]))" + ".map(@c0, cel.bind(@r1, @c0 + @c0, [@r1, @r1]))) == 2", - "Currently Unsupported"), // TODO: Handle comprehension variables that fall - // outside the cel.block scope + "cel.@block([@c1 + @c1, @c0 + @c0], " + + "size([\"foo\", \"bar\"].map(@c1, [@index0, @index0])" + + ".map(@c0, [@index1, @index1])) == 2)"), PRESENCE_TEST( "has({'a': true}.a) && {'a':true}['a']", "cel.bind(@r0, {\"a\": true}, has(@r0.a) && @r0[\"a\"])", @@ -683,10 +686,6 @@ public void cse_withCelBind_macroMapUnpopulated(@TestParameter CseTestCase testC @Test public void cse_withCelBlock_macroMapPopulated(@TestParameter CseTestCase testCase) throws Exception { - if (testCase.equals(CseTestCase.MACRO_SHADOWED_VARIABLE_2)) { - // TODO: Handle comprehension variables that fall outside the cel.block scope - return; - } CelOptimizer celOptimizer = newCseOptimizer( SubexpressionOptimizerOptions.newBuilder() @@ -709,10 +708,6 @@ public void cse_withCelBlock_macroMapPopulated(@TestParameter CseTestCase testCa @Test public void cse_withCelBlock_macroMapUnpopulated(@TestParameter CseTestCase testCase) throws Exception { - if (testCase.equals(CseTestCase.MACRO_SHADOWED_VARIABLE_2)) { - // TODO: Handle comprehension variables that fall outside the cel.block scope - return; - } CelOptimizer celOptimizer = newCseOptimizer( SubexpressionOptimizerOptions.newBuilder() @@ -732,6 +727,32 @@ public void cse_withCelBlock_macroMapUnpopulated(@TestParameter CseTestCase test .isEqualTo(true); } + @Test + public void celBlock_nestedComprehension_iterVarReferencedAcrossComprehensions() + throws Exception { + String nestedComprehension = + "[\"foo\"].map(x, [[\"bar\"], [x + x, x + x]] + [\"bar\"].map(y, [x + y, [\"baz\"].map(z," + + " [x + y + z, x + y, x + y + z])])) == [[[\"bar\"], [\"foofoo\", \"foofoo\"]," + + " [\"foobar\", [[\"foobarbaz\", \"foobar\", \"foobarbaz\"]]]]]"; + CelOptimizer celOptimizer = + newCseOptimizer( + SubexpressionOptimizerOptions.newBuilder() + .populateMacroCalls(true) + .enableCelBlock(true) + .build()); + CelAbstractSyntaxTree ast = CEL.compile(nestedComprehension).getAst(); + + CelAbstractSyntaxTree optimizedAst = celOptimizer.optimize(ast); + + assertThat(CEL.createProgram(optimizedAst).eval()).isEqualTo(true); + assertThat(CEL_UNPARSER.unparse(optimizedAst)) + .isEqualTo( + "cel.@block([@c0 + @c0, [\"bar\"], @c0 + @c1, @index2 + @c2], [\"foo\"].map(@c0," + + " [@index1, [@index0, @index0]] + @index1.map(@c1, [@index2, [\"baz\"].map(@c2," + + " [@index3, @index2, @index3])])) == [[@index1, [\"foofoo\", \"foofoo\"]," + + " [\"foobar\", [[\"foobarbaz\", \"foobar\", \"foobarbaz\"]]]]])"); + } + @Test public void cse_resultTypeSet_celBlockOptimizationSuccess() throws Exception { Cel cel = newCelBuilder().setResultType(SimpleType.BOOL).build(); @@ -1264,6 +1285,37 @@ public void lazyEval_multipleBlockIndices_cascaded() throws Exception { assertThat(invocation.get()).isEqualTo(1); } + @Test + @SuppressWarnings("Immutable") // Test only + public void lazyEval_nestedComprehension_indexReferencedInNestedScopes() throws Exception { + AtomicInteger invocation = new AtomicInteger(); + CelRuntime celRuntime = + CelRuntimeFactory.standardCelRuntimeBuilder() + .addMessageTypes(TestAllTypes.getDescriptor()) + .addFunctionBindings( + CelFunctionBinding.from( + "get_true_overload", + ImmutableList.of(), + arg -> { + invocation.getAndIncrement(); + return true; + })) + .build(); + // Equivalent of [true, false, true].map(c0, [c0].map(c1, [c0, c1, true])) + CelAbstractSyntaxTree ast = + compileUsingInternalFunctions( + "cel.block([c0, c1, get_true()], [index2, false, index2].map(c0, [c0].map(c1, [index0," + + " index1, index2]))) == [[[true, true, true]], [[false, false, true]], [[true," + + " true, true]]]"); + + boolean result = (boolean) celRuntime.createProgram(ast).eval(); + + assertThat(result).isTrue(); + // Even though the function get_true() is referenced across different comprehension scopes, + // it still gets memoized only once. + assertThat(invocation.get()).isEqualTo(1); + } + @Test @TestParameters("{source: 'cel.block([])'}") @TestParameters("{source: 'cel.block([1])'}") From ad2c6b62a337669cbb580e5be96861d22e4a4a08 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Thu, 15 Feb 2024 17:49:17 -0800 Subject: [PATCH 033/486] Assign unique indices for mangled comprehension identifiers with different types PiperOrigin-RevId: 607513056 --- .../main/java/dev/cel/optimizer/BUILD.bazel | 1 + .../java/dev/cel/optimizer/MutableAst.java | 117 ++++++++++++++---- .../optimizers/SubexpressionOptimizer.java | 43 +------ .../dev/cel/optimizer/MutableAstTest.java | 16 +-- .../dev/cel/optimizer/optimizers/BUILD.bazel | 8 +- .../SubexpressionOptimizerTest.java | 60 +++++---- 6 files changed, 149 insertions(+), 96 deletions(-) diff --git a/optimizer/src/main/java/dev/cel/optimizer/BUILD.bazel b/optimizer/src/main/java/dev/cel/optimizer/BUILD.bazel index 954deb74f..c86b4559b 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/BUILD.bazel +++ b/optimizer/src/main/java/dev/cel/optimizer/BUILD.bazel @@ -88,6 +88,7 @@ java_library( "//common/ast", "//common/ast:expr_factory", "//common/navigation", + "//common/types:type_providers", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", ], diff --git a/optimizer/src/main/java/dev/cel/optimizer/MutableAst.java b/optimizer/src/main/java/dev/cel/optimizer/MutableAst.java index ae2f328e9..1e67a4c76 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/MutableAst.java +++ b/optimizer/src/main/java/dev/cel/optimizer/MutableAst.java @@ -21,9 +21,10 @@ import com.google.auto.value.AutoValue; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; +import com.google.common.collect.HashBasedTable; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Table; import com.google.errorprone.annotations.Immutable; import dev.cel.common.CelAbstractSyntaxTree; import dev.cel.common.CelSource; @@ -38,9 +39,13 @@ import dev.cel.common.navigation.CelNavigableAst; import dev.cel.common.navigation.CelNavigableExpr; import dev.cel.common.navigation.CelNavigableExpr.TraversalOrder; +import dev.cel.common.types.CelType; +import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.Map.Entry; import java.util.NoSuchElementException; import java.util.Optional; +import java.util.stream.Collectors; /** MutableAst contains logic for mutating a {@link CelAbstractSyntaxTree}. */ @Immutable @@ -187,45 +192,112 @@ public CelAbstractSyntaxTree renumberIdsConsecutively(CelAbstractSyntaxTree ast) * *

The expression IDs are not modified when the identifier names are changed. * + *

Mangling occurs only if the iteration variable is referenced within the loop step. + * *

Iteration variables in comprehensions are numbered based on their comprehension nesting - * levels. Examples: + * levels and the iteration variable's type. Examples: * *

    - *
  • {@code [true].exists(i, i) && [true].exists(j, j)} -> {@code [true].exists(@c0, @c0) && - * [true].exists(@c0, @c0)} // Note that i,j gets replaced to the same @c0 in this example - *
  • {@code [true].exists(i, i && [true].exists(j, j))} -> {@code [true].exists(@c0, @c0 && - * [true].exists(@c1, @c1))} + *
  • {@code [true].exists(i, i) && [true].exists(j, j)} -> {@code [true].exists(@c0:0, @c0:0) + * && [true].exists(@c0:0, @c0:0)} // Note that i,j gets replaced to the same @c0:0 in this + * example as they share the same nesting level and type. + *
  • {@code [1].exists(i, i > 0) && [1u].exists(j, j > 0u)} -> {@code [1].exists(@c0:0, @c0:0 + * > 0) && [1u].exists(@c0:1, @c0:1 > 0u)} + *
  • {@code [true].exists(i, i && [true].exists(j, j))} -> {@code [true].exists(@c0:0, @c0:0 + * && [true].exists(@c1:0, @c1:0))} *
* * @param ast AST to mutate * @param newIdentPrefix Prefix to use for new identifier names. For example, providing @c will - * produce @c0, @c1, @c2... as new names. + * produce @c0:0, @c0:1, @c1:0, @c2:0... as new names. */ public MangledComprehensionAst mangleComprehensionIdentifierNames( CelAbstractSyntaxTree ast, String newIdentPrefix) { - int iterCount; CelNavigableAst newNavigableAst = CelNavigableAst.fromAst(ast); - ImmutableSet.Builder mangledComprehensionIdents = ImmutableSet.builder(); - for (iterCount = 0; iterCount < iterationLimit; iterCount++) { + LinkedHashMap comprehensionsToMangle = + newNavigableAst + .getRoot() + // This is important - mangling needs to happen bottom-up to avoid stepping over + // shadowed variables that are not part of the comprehension being mangled. + .allNodes(TraversalOrder.POST_ORDER) + .filter(node -> node.getKind().equals(Kind.COMPREHENSION)) + .filter(node -> !node.expr().comprehension().iterVar().startsWith(newIdentPrefix)) + .filter( + node -> { + // Ensure the iter_var is actually referenced in the loop_step. If it's not, we + // can skip mangling. + String iterVar = node.expr().comprehension().iterVar(); + return CelNavigableExpr.fromExpr(node.expr().comprehension().loopStep()) + .allNodes() + .anyMatch( + subNode -> subNode.expr().identOrDefault().name().contains(iterVar)); + }) + .collect( + Collectors.toMap( + k -> k, + v -> { + String iterVar = v.expr().comprehension().iterVar(); + long iterVarId = + CelNavigableExpr.fromExpr(v.expr().comprehension().loopStep()) + .allNodes() + .filter( + loopStepNode -> + loopStepNode.expr().identOrDefault().name().equals(iterVar)) + .map(CelNavigableExpr::id) + .findAny() + .orElseThrow( + () -> { + throw new NoSuchElementException( + "Expected iteration variable to exist in expr id: " + + v.id()); + }); + + return ast.getType(iterVarId) + .orElseThrow( + () -> + new NoSuchElementException( + "Checked type not present for: " + iterVarId)); + }, + (x, y) -> { + throw new IllegalStateException("Unexpected CelNavigableExpr collision"); + }, + LinkedHashMap::new)); + int iterCount = 0; + + // The map that we'll eventually return to the caller. + HashMap mangledIdentNamesToType = new HashMap<>(); + // Intermediary table used for the purposes of generating a unique mangled variable name. + Table comprehensionLevelToType = HashBasedTable.create(); + for (Entry comprehensionEntry : comprehensionsToMangle.entrySet()) { + iterCount++; + // Refetch the comprehension node as mutating the AST could have renumbered its IDs. CelNavigableExpr comprehensionNode = newNavigableAst .getRoot() - // This is important - mangling needs to happen bottom-up to avoid stepping over - // shadowed variables that are not part of the comprehension being mangled. .allNodes(TraversalOrder.POST_ORDER) .filter(node -> node.getKind().equals(Kind.COMPREHENSION)) .filter(node -> !node.expr().comprehension().iterVar().startsWith(newIdentPrefix)) .findAny() - .orElse(null); - if (comprehensionNode == null) { - break; - } + .orElseThrow( + () -> new NoSuchElementException("Failed to refetch mutated comprehension")); + CelType comprehensionEntryType = comprehensionEntry.getValue(); CelExpr.Builder comprehensionExpr = comprehensionNode.expr().toBuilder(); String iterVar = comprehensionExpr.comprehension().iterVar(); int comprehensionNestingLevel = countComprehensionNestingLevel(comprehensionNode); - String mangledVarName = newIdentPrefix + comprehensionNestingLevel; - mangledComprehensionIdents.add(mangledVarName); + String mangledVarName; + if (comprehensionLevelToType.contains(comprehensionNestingLevel, comprehensionEntryType)) { + mangledVarName = + comprehensionLevelToType.get(comprehensionNestingLevel, comprehensionEntryType); + } else { + // First time encountering the pair of . Generate a unique + // mangled variable name for this. + int uniqueTypeIdx = comprehensionLevelToType.row(comprehensionNestingLevel).size(); + mangledVarName = newIdentPrefix + comprehensionNestingLevel + ":" + uniqueTypeIdx; + comprehensionLevelToType.put( + comprehensionNestingLevel, comprehensionEntryType, mangledVarName); + } + mangledIdentNamesToType.put(mangledVarName, comprehensionEntryType); CelExpr.Builder mutatedComprehensionExpr = mangleIdentsInComprehensionExpr( @@ -254,7 +326,8 @@ public MangledComprehensionAst mangleComprehensionIdentifierNames( throw new IllegalStateException("Max iteration count reached."); } - return MangledComprehensionAst.of(newNavigableAst.getAst(), mangledComprehensionIdents.build()); + return MangledComprehensionAst.of( + newNavigableAst.getAst(), ImmutableMap.copyOf(mangledIdentNamesToType)); } /** @@ -588,11 +661,11 @@ public abstract static class MangledComprehensionAst { /** AST after the iteration variables have been mangled. */ public abstract CelAbstractSyntaxTree ast(); - /** Set of identifiers with the iteration variable mangled. */ - public abstract ImmutableSet mangledComprehensionIdents(); + /** Map containing the mangled identifier names to their types. */ + public abstract ImmutableMap mangledComprehensionIdents(); private static MangledComprehensionAst of( - CelAbstractSyntaxTree ast, ImmutableSet mangledComprehensionIdents) { + CelAbstractSyntaxTree ast, ImmutableMap mangledComprehensionIdents) { return new AutoValue_MutableAst_MangledComprehensionAst(ast, mangledComprehensionIdents); } } diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java index 28b5e02a4..4933b90d8 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java @@ -130,8 +130,6 @@ private CelAbstractSyntaxTree optimizeUsingCelBlock( navigableAst.getAst(), MANGLED_COMPREHENSION_IDENTIFIER_PREFIX); CelAbstractSyntaxTree astToModify = mangledComprehensionAst.ast(); CelSource sourceToModify = astToModify.getSource(); - ImmutableSet mangledIdentDecls = - newMangledIdentDecls(celBuilder, mangledComprehensionAst); int blockIdentifierIndex = 0; int iterCount; @@ -192,7 +190,11 @@ private CelAbstractSyntaxTree optimizeUsingCelBlock( // Add all mangled comprehension identifiers to the environment, so that the subexpressions can // retain context to them. - celBuilder.addVarDeclarations(mangledIdentDecls); + mangledComprehensionAst + .mangledComprehensionIdents() + .forEach( + (identName, type) -> + celBuilder.addVarDeclarations(CelVarDecl.newVarDeclaration(identName, type))); // Type-check all sub-expressions then add them as block identifiers to the CEL environment addBlockIdentsToEnv(celBuilder, subexpressions); @@ -260,41 +262,6 @@ private static void addBlockIdentsToEnv(CelBuilder celBuilder, List sub } } - private static ImmutableSet newMangledIdentDecls( - CelBuilder celBuilder, MangledComprehensionAst mangledComprehensionAst) { - if (mangledComprehensionAst.mangledComprehensionIdents().isEmpty()) { - return ImmutableSet.of(); - } - CelAbstractSyntaxTree ast = mangledComprehensionAst.ast(); - try { - ast = celBuilder.build().check(ast).getAst(); - } catch (CelValidationException e) { - throw new IllegalStateException("Failed to type-check mangled AST.", e); - } - - ImmutableSet.Builder mangledVarDecls = ImmutableSet.builder(); - for (String ident : mangledComprehensionAst.mangledComprehensionIdents()) { - CelExpr mangledIdentExpr = - CelNavigableAst.fromAst(ast) - .getRoot() - .allNodes() - .filter(node -> node.getKind().equals(Kind.IDENT)) - .map(CelNavigableExpr::expr) - .filter(expr -> expr.ident().name().equals(ident)) - .findAny() - .orElse(null); - if (mangledIdentExpr == null) { - break; - } - - CelType mangledIdentType = - ast.getType(mangledIdentExpr.id()).orElseThrow(() -> new NoSuchElementException("?")); - mangledVarDecls.add(CelVarDecl.newVarDeclaration(ident, mangledIdentType)); - } - - return mangledVarDecls.build(); - } - private CelAbstractSyntaxTree optimizeUsingCelBind(CelNavigableAst navigableAst) { CelAbstractSyntaxTree astToModify = mutableAst diff --git a/optimizer/src/test/java/dev/cel/optimizer/MutableAstTest.java b/optimizer/src/test/java/dev/cel/optimizer/MutableAstTest.java index 9c32520b3..557302e40 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/MutableAstTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/MutableAstTest.java @@ -687,7 +687,7 @@ public void mangleComprehensionVariable_singleMacro() throws Exception { assertThat(mangledAst.getExpr().toString()) .isEqualTo( "COMPREHENSION [13] {\n" - + " iter_var: @c0\n" + + " iter_var: @c0:0\n" + " iter_range: {\n" + " CREATE_LIST [1] {\n" + " elements: {\n" @@ -722,7 +722,7 @@ public void mangleComprehensionVariable_singleMacro() throws Exception { + " name: __result__\n" + " }\n" + " IDENT [5] {\n" - + " name: @c0\n" + + " name: @c0:0\n" + " }\n" + " }\n" + " }\n" @@ -733,7 +733,7 @@ public void mangleComprehensionVariable_singleMacro() throws Exception { + " }\n" + " }\n" + "}"); - assertThat(CEL_UNPARSER.unparse(mangledAst)).isEqualTo("[false].exists(@c0, @c0)"); + assertThat(CEL_UNPARSER.unparse(mangledAst)).isEqualTo("[false].exists(@c0:0, @c0:0)"); assertThat(CEL.createProgram(CEL.check(mangledAst).getAst()).eval()).isEqualTo(false); assertConsistentMacroCalls(ast); } @@ -748,7 +748,7 @@ public void mangleComprehensionVariable_nestedMacroWithShadowedVariables() throw assertThat(mangledAst.getExpr().toString()) .isEqualTo( "COMPREHENSION [27] {\n" - + " iter_var: @c0\n" + + " iter_var: @c0:0\n" + " iter_range: {\n" + " CREATE_LIST [1] {\n" + " elements: {\n" @@ -785,12 +785,12 @@ public void mangleComprehensionVariable_nestedMacroWithShadowedVariables() throw + " name: __result__\n" + " }\n" + " COMPREHENSION [19] {\n" - + " iter_var: @c1\n" + + " iter_var: @c1:0\n" + " iter_range: {\n" + " CREATE_LIST [5] {\n" + " elements: {\n" + " IDENT [6] {\n" - + " name: @c0\n" + + " name: @c0:0\n" + " }\n" + " }\n" + " }\n" @@ -825,7 +825,7 @@ public void mangleComprehensionVariable_nestedMacroWithShadowedVariables() throw + " function: _==_\n" + " args: {\n" + " IDENT [9] {\n" - + " name: @c1\n" + + " name: @c1:0\n" + " }\n" + " CONSTANT [11] { value: 1 }\n" + " }\n" @@ -850,7 +850,7 @@ public void mangleComprehensionVariable_nestedMacroWithShadowedVariables() throw + "}"); assertThat(CEL_UNPARSER.unparse(mangledAst)) - .isEqualTo("[x].exists(@c0, [@c0].exists(@c1, @c1 == 1))"); + .isEqualTo("[x].exists(@c0:0, [@c0:0].exists(@c1:0, @c1:0 == 1))"); assertThat(CEL.createProgram(CEL.check(mangledAst).getAst()).eval(ImmutableMap.of("x", 1))) .isEqualTo(true); assertConsistentMacroCalls(ast); diff --git a/optimizer/src/test/java/dev/cel/optimizer/optimizers/BUILD.bazel b/optimizer/src/test/java/dev/cel/optimizer/optimizers/BUILD.bazel index c907ef1f7..e3861f73c 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/optimizers/BUILD.bazel +++ b/optimizer/src/test/java/dev/cel/optimizer/optimizers/BUILD.bazel @@ -7,7 +7,7 @@ java_library( testonly = 1, srcs = glob(["*.java"]), deps = [ - "//:java_truth", + # "//java/com/google/testing/testsize:annotations", "//bundle:cel", "//common", "//common:compiler_common", @@ -28,9 +28,10 @@ java_library( "//parser:operator", "//parser:unparser", "//runtime", - "@maven//:com_google_guava_guava", - "@maven//:com_google_testparameterinjector_test_parameter_injector", "@maven//:junit_junit", + "@maven//:com_google_testparameterinjector_test_parameter_injector", + "//:java_truth", + "@maven//:com_google_guava_guava", ], ) @@ -38,6 +39,7 @@ junit4_test_suites( name = "test_suites", sizes = [ "small", + "medium", ], src_dir = "src/test/java", deps = [":tests"], diff --git a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java index cf7cdd6df..4b99c325c 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java @@ -23,6 +23,7 @@ import com.google.testing.junit.testparameterinjector.TestParameter; import com.google.testing.junit.testparameterinjector.TestParameterInjector; import com.google.testing.junit.testparameterinjector.TestParameters; +// import com.google.testing.testsize.MediumTest; import dev.cel.bundle.Cel; import dev.cel.bundle.CelBuilder; import dev.cel.bundle.CelFactory; @@ -65,6 +66,7 @@ import org.junit.Test; import org.junit.runner.RunWith; +// @MediumTest @RunWith(TestParameterInjector.class) public class SubexpressionOptimizerTest { @@ -478,15 +480,22 @@ private enum CseTestCase { // the same. "size([[1].exists(i, i > 0)]) + size([[1].exists(j, j > 0)]) + " + "size([[2].exists(k, k > 1)]) + size([[2].exists(l, l > 1)]) == 4", - "cel.bind(@r1, size([[2].exists(@c0, @c0 > 1)]), " - + "cel.bind(@r0, size([[1].exists(@c0, @c0 > 0)]), @r0 + @r0) + @r1 + @r1) == 4", - "cel.@block([size([[1].exists(@c0, @c0 > 0)]), size([[2].exists(@c0, @c0 > 1)])], @index0 +" - + " @index0 + @index1 + @index1 == 4)"), + "cel.bind(@r1, size([[2].exists(@c0:0, @c0:0 > 1)]), " + + "cel.bind(@r0, size([[1].exists(@c0:0, @c0:0 > 0)]), @r0 + @r0) + @r1 + @r1) == 4", + "cel.@block([size([[1].exists(@c0:0, @c0:0 > 0)]), size([[2].exists(@c0:0, @c0:0 > 1)])]," + + " @index0 + @index0 + @index1 + @index1 == 4)"), + MULTIPLE_MACROS_2( + "[[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == 'a')] +" + + " [['a'].exists(l, l == 'a')] == [true, true, true, true]", + "cel.bind(@r1, [[\"a\"].exists(@c0:1, @c0:1 == \"a\")], cel.bind(@r0, [[1].exists(@c0:0," + + " @c0:0 > 0)], @r0 + @r0) + @r1 + @r1) == [true, true, true, true]", + "cel.@block([[[1].exists(@c0:0, @c0:0 > 0)], [[\"a\"].exists(@c0:1, @c0:1 == \"a\")]]," + + " @index0 + @index0 + @index1 + @index1 == [true, true, true, true])"), NESTED_MACROS( "[1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [[2, 3, 4], [2, 3, 4], [2, 3, 4]]", - "cel.bind(@r0, [1, 2, 3], @r0.map(@c0, @r0.map(@c1, @c1 + 1))) == " + "cel.bind(@r0, [1, 2, 3], @r0.map(@c0:0, @r0.map(@c1:0, @c1:0 + 1))) == " + "cel.bind(@r1, [2, 3, 4], [@r1, @r1, @r1])", - "cel.@block([[1, 2, 3], [2, 3, 4]], @index0.map(@c0, @index0.map(@c1, @c1 + 1)) ==" + "cel.@block([[1, 2, 3], [2, 3, 4]], @index0.map(@c0:0, @index0.map(@c1:0, @c1:0 + 1)) ==" + " [@index1, @index1, @index1])"), INCLUSION_LIST( "1 in [1,2,3] && 2 in [1,2,3] && 3 in [3, [1,2,3]] && 1 in [1,2,3]", @@ -500,17 +509,17 @@ private enum CseTestCase { "cel.@block([{true: false}], 2 in {\"a\": 1, 2: @index0, 3: @index0})"), MACRO_SHADOWED_VARIABLE( "[x - 1 > 3 ? x - 1 : 5].exists(x, x - 1 > 3) || x - 1 > 3", - "cel.bind(@r0, x - 1, cel.bind(@r1, @r0 > 3, [@r1 ? @r0 : 5].exists(@c0, @c0 - 1 > 3) ||" - + " @r1))", - "cel.@block([x - 1, @index0 > 3], [@index1 ? @index0 : 5].exists(@c0, @c0 - 1 > 3) ||" + "cel.bind(@r0, x - 1, cel.bind(@r1, @r0 > 3, [@r1 ? @r0 : 5].exists(@c0:0, @c0:0 - 1 > 3)" + + " || @r1))", + "cel.@block([x - 1, @index0 > 3], [@index1 ? @index0 : 5].exists(@c0:0, @c0:0 - 1 > 3) ||" + " @index1)"), MACRO_SHADOWED_VARIABLE_2( "size([\"foo\", \"bar\"].map(x, [x + x, x + x]).map(x, [x + x, x + x])) == 2", - "size([\"foo\", \"bar\"].map(@c1, cel.bind(@r0, @c1 + @c1, [@r0, @r0]))" - + ".map(@c0, cel.bind(@r1, @c0 + @c0, [@r1, @r1]))) == 2", - "cel.@block([@c1 + @c1, @c0 + @c0], " - + "size([\"foo\", \"bar\"].map(@c1, [@index0, @index0])" - + ".map(@c0, [@index1, @index1])) == 2)"), + "size([\"foo\", \"bar\"].map(@c1:0, cel.bind(@r0, @c1:0 + @c1:0, [@r0, @r0]))" + + ".map(@c0:0, cel.bind(@r1, @c0:0 + @c0:0, [@r1, @r1]))) == 2", + "cel.@block([@c1:0 + @c1:0, @c0:0 + @c0:0], " + + "size([\"foo\", \"bar\"].map(@c1:0, [@index0, @index0])" + + ".map(@c0:0, [@index1, @index1])) == 2)"), PRESENCE_TEST( "has({'a': true}.a) && {'a':true}['a']", "cel.bind(@r0, {\"a\": true}, has(@r0.a) && @r0[\"a\"])", @@ -747,10 +756,11 @@ public void celBlock_nestedComprehension_iterVarReferencedAcrossComprehensions() assertThat(CEL.createProgram(optimizedAst).eval()).isEqualTo(true); assertThat(CEL_UNPARSER.unparse(optimizedAst)) .isEqualTo( - "cel.@block([@c0 + @c0, [\"bar\"], @c0 + @c1, @index2 + @c2], [\"foo\"].map(@c0," - + " [@index1, [@index0, @index0]] + @index1.map(@c1, [@index2, [\"baz\"].map(@c2," - + " [@index3, @index2, @index3])])) == [[@index1, [\"foofoo\", \"foofoo\"]," - + " [\"foobar\", [[\"foobarbaz\", \"foobar\", \"foobarbaz\"]]]]])"); + "cel.@block([@c0:0 + @c0:0, [\"bar\"], @c0:0 + @c1:0, @index2 + @c2:0]," + + " [\"foo\"].map(@c0:0, [@index1, [@index0, @index0]] + @index1.map(@c1:0," + + " [@index2, [\"baz\"].map(@c2:0, [@index3, @index2, @index3])])) == [[@index1," + + " [\"foofoo\", \"foofoo\"], [\"foobar\", [[\"foobarbaz\", \"foobar\"," + + " \"foobarbaz\"]]]]])"); } @Test @@ -1014,9 +1024,9 @@ public void cse_withCelBind_largeNestedMacro() throws Exception { assertThat(CEL_UNPARSER.unparse(optimizedAst)) .isEqualTo( - "cel.bind(@r0, [1, 2, 3], cel.bind(@r1, size(@r0.map(@c0, @r0.map(@c1, @r0.map(@c2, " - + "@r0.map(@c3, @r0.map(@c4, @r0.map(@c5, @r0.map(@c6, @r0.map(@c7, @r0))))))))), " - + "@r1 + @r1 + @r1 + @r1 + @r1 + @r1 + @r1 + @r1 + @r1))"); + "cel.bind(@r0, [1, 2, 3], cel.bind(@r1, size(@r0.map(i, @r0.map(i, @r0.map(i," + + " @r0.map(i, @r0.map(i, @r0.map(i, @r0.map(i, @r0.map(i, @r0))))))))), @r1 + @r1" + + " + @r1 + @r1 + @r1 + @r1 + @r1 + @r1 + @r1))"); assertThat(CEL.createProgram(optimizedAst).eval()).isEqualTo(27); } @@ -1050,10 +1060,10 @@ public void cse_withCelBlock_largeNestedMacro() throws Exception { assertThat(CEL_UNPARSER.unparse(optimizedAst)) .isEqualTo( - "cel.@block([[1, 2, 3], size(@index0.map(@c0, @index0.map(@c1, @index0.map(@c2," - + " @index0.map(@c3, @index0.map(@c4, @index0.map(@c5, @index0.map(@c6," - + " @index0.map(@c7, @index0)))))))))], @index1 + @index1 + @index1 + @index1 +" - + " @index1 + @index1 + @index1 + @index1 + @index1)"); + "cel.@block([[1, 2, 3], size(@index0.map(i, @index0.map(i, @index0.map(i," + + " @index0.map(i, @index0.map(i, @index0.map(i, @index0.map(i, @index0.map(i," + + " @index0)))))))))], @index1 + @index1 + @index1 + @index1 + @index1 + @index1 +" + + " @index1 + @index1 + @index1)"); assertThat(CEL.createProgram(optimizedAst).eval()).isEqualTo(27); } From 90671c020c7b1d3c4ac408ae18d3ed2404f8e6fa Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Wed, 21 Feb 2024 12:59:35 -0800 Subject: [PATCH 034/486] Mangle identifier name for comprehension result PiperOrigin-RevId: 609094679 --- .../main/java/dev/cel/common/ast/CelExpr.java | 2 + .../java/dev/cel/optimizer/MutableAst.java | 183 +++++++++++++----- .../optimizers/SubexpressionOptimizer.java | 19 +- .../dev/cel/optimizer/MutableAstTest.java | 31 ++- 4 files changed, 169 insertions(+), 66 deletions(-) diff --git a/common/src/main/java/dev/cel/common/ast/CelExpr.java b/common/src/main/java/dev/cel/common/ast/CelExpr.java index c106a1ff9..c4e53906a 100644 --- a/common/src/main/java/dev/cel/common/ast/CelExpr.java +++ b/common/src/main/java/dev/cel/common/ast/CelExpr.java @@ -1011,6 +1011,8 @@ public abstract static class CelComprehension { /** Builder for Comprehension. */ @AutoValue.Builder public abstract static class Builder { + public abstract String accuVar(); + public abstract CelExpr iterRange(); public abstract CelExpr accuInit(); diff --git a/optimizer/src/main/java/dev/cel/optimizer/MutableAst.java b/optimizer/src/main/java/dev/cel/optimizer/MutableAst.java index 1e67a4c76..9333726ac 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/MutableAst.java +++ b/optimizer/src/main/java/dev/cel/optimizer/MutableAst.java @@ -29,6 +29,7 @@ import dev.cel.common.CelAbstractSyntaxTree; import dev.cel.common.CelSource; import dev.cel.common.ast.CelExpr; +import dev.cel.common.ast.CelExpr.CelComprehension; import dev.cel.common.ast.CelExpr.CelIdent; import dev.cel.common.ast.CelExpr.ExprKind.Kind; import dev.cel.common.ast.CelExprFactory; @@ -45,6 +46,7 @@ import java.util.Map.Entry; import java.util.NoSuchElementException; import java.util.Optional; +import java.util.function.Predicate; import java.util.stream.Collectors; /** MutableAst contains logic for mutating a {@link CelAbstractSyntaxTree}. */ @@ -208,20 +210,27 @@ public CelAbstractSyntaxTree renumberIdsConsecutively(CelAbstractSyntaxTree ast) * * * @param ast AST to mutate - * @param newIdentPrefix Prefix to use for new identifier names. For example, providing @c will - * produce @c0:0, @c0:1, @c1:0, @c2:0... as new names. + * @param newIterVarPrefix Prefix to use for new iteration variable identifier name. For example, + * providing @c will produce @c0:0, @c0:1, @c1:0, @c2:0... as new names. + * @param newResultPrefix Prefix to use for new comprehensin result identifier names. */ public MangledComprehensionAst mangleComprehensionIdentifierNames( - CelAbstractSyntaxTree ast, String newIdentPrefix) { + CelAbstractSyntaxTree ast, String newIterVarPrefix, String newResultPrefix) { CelNavigableAst newNavigableAst = CelNavigableAst.fromAst(ast); - LinkedHashMap comprehensionsToMangle = + Predicate comprehensionIdentifierPredicate = x -> true; + comprehensionIdentifierPredicate = + comprehensionIdentifierPredicate + .and(node -> node.getKind().equals(Kind.COMPREHENSION)) + .and(node -> !node.expr().comprehension().iterVar().startsWith(newIterVarPrefix)) + .and(node -> !node.expr().comprehension().accuVar().startsWith(newResultPrefix)); + + LinkedHashMap comprehensionsToMangle = newNavigableAst .getRoot() // This is important - mangling needs to happen bottom-up to avoid stepping over // shadowed variables that are not part of the comprehension being mangled. .allNodes(TraversalOrder.POST_ORDER) - .filter(node -> node.getKind().equals(Kind.COMPREHENSION)) - .filter(node -> !node.expr().comprehension().iterVar().startsWith(newIdentPrefix)) + .filter(comprehensionIdentifierPredicate) .filter( node -> { // Ensure the iter_var is actually referenced in the loop_step. If it's not, we @@ -236,9 +245,10 @@ public MangledComprehensionAst mangleComprehensionIdentifierNames( Collectors.toMap( k -> k, v -> { - String iterVar = v.expr().comprehension().iterVar(); + CelComprehension comprehension = v.expr().comprehension(); + String iterVar = comprehension.iterVar(); long iterVarId = - CelNavigableExpr.fromExpr(v.expr().comprehension().loopStep()) + CelNavigableExpr.fromExpr(comprehension.loopStep()) .allNodes() .filter( loopStepNode -> @@ -252,11 +262,22 @@ public MangledComprehensionAst mangleComprehensionIdentifierNames( + v.id()); }); - return ast.getType(iterVarId) - .orElseThrow( - () -> - new NoSuchElementException( - "Checked type not present for: " + iterVarId)); + CelType iterVarType = + ast.getType(iterVarId) + .orElseThrow( + () -> + new NoSuchElementException( + "Checked type not present for iteration variable: " + + iterVarId)); + CelType resultType = + ast.getType(comprehension.result().id()) + .orElseThrow( + () -> + new NoSuchElementException( + "Checked type not present for result: " + + comprehension.result().id())); + + return MangledComprehensionType.of(iterVarType, resultType); }, (x, y) -> { throw new IllegalStateException("Unexpected CelNavigableExpr collision"); @@ -265,53 +286,62 @@ public MangledComprehensionAst mangleComprehensionIdentifierNames( int iterCount = 0; // The map that we'll eventually return to the caller. - HashMap mangledIdentNamesToType = new HashMap<>(); + HashMap mangledIdentNamesToType = + new HashMap<>(); // Intermediary table used for the purposes of generating a unique mangled variable name. - Table comprehensionLevelToType = HashBasedTable.create(); - for (Entry comprehensionEntry : comprehensionsToMangle.entrySet()) { + Table comprehensionLevelToType = + HashBasedTable.create(); + for (Entry comprehensionEntry : + comprehensionsToMangle.entrySet()) { iterCount++; // Refetch the comprehension node as mutating the AST could have renumbered its IDs. CelNavigableExpr comprehensionNode = newNavigableAst .getRoot() .allNodes(TraversalOrder.POST_ORDER) - .filter(node -> node.getKind().equals(Kind.COMPREHENSION)) - .filter(node -> !node.expr().comprehension().iterVar().startsWith(newIdentPrefix)) + .filter(comprehensionIdentifierPredicate) .findAny() .orElseThrow( () -> new NoSuchElementException("Failed to refetch mutated comprehension")); - CelType comprehensionEntryType = comprehensionEntry.getValue(); + MangledComprehensionType comprehensionEntryType = comprehensionEntry.getValue(); CelExpr.Builder comprehensionExpr = comprehensionNode.expr().toBuilder(); - String iterVar = comprehensionExpr.comprehension().iterVar(); int comprehensionNestingLevel = countComprehensionNestingLevel(comprehensionNode); - String mangledVarName; + MangledComprehensionName mangledComprehensionName; if (comprehensionLevelToType.contains(comprehensionNestingLevel, comprehensionEntryType)) { - mangledVarName = + mangledComprehensionName = comprehensionLevelToType.get(comprehensionNestingLevel, comprehensionEntryType); } else { // First time encountering the pair of . Generate a unique // mangled variable name for this. int uniqueTypeIdx = comprehensionLevelToType.row(comprehensionNestingLevel).size(); - mangledVarName = newIdentPrefix + comprehensionNestingLevel + ":" + uniqueTypeIdx; + String mangledIterVarName = + newIterVarPrefix + comprehensionNestingLevel + ":" + uniqueTypeIdx; + String mangledResultName = + newResultPrefix + comprehensionNestingLevel + ":" + uniqueTypeIdx; + mangledComprehensionName = + MangledComprehensionName.of(mangledIterVarName, mangledResultName); comprehensionLevelToType.put( - comprehensionNestingLevel, comprehensionEntryType, mangledVarName); + comprehensionNestingLevel, comprehensionEntryType, mangledComprehensionName); } - mangledIdentNamesToType.put(mangledVarName, comprehensionEntryType); + mangledIdentNamesToType.put(mangledComprehensionName, comprehensionEntryType); + String iterVar = comprehensionExpr.comprehension().iterVar(); + String accuVar = comprehensionExpr.comprehension().accuVar(); CelExpr.Builder mutatedComprehensionExpr = mangleIdentsInComprehensionExpr( newNavigableAst.getAst().getExpr().toBuilder(), comprehensionExpr, iterVar, - mangledVarName); + accuVar, + mangledComprehensionName); // Repeat the mangling process for the macro source. CelSource newSource = mangleIdentsInMacroSource( newNavigableAst.getAst(), mutatedComprehensionExpr, iterVar, - mangledVarName, + mangledComprehensionName, comprehensionExpr.id()); newNavigableAst = @@ -381,14 +411,44 @@ private CelExpr.Builder mangleIdentsInComprehensionExpr( CelExpr.Builder root, CelExpr.Builder comprehensionExpr, String originalIterVar, - String mangledVarName) { + String originalAccuVar, + MangledComprehensionName mangledComprehensionName) { + CelExpr.Builder modifiedLoopStep = + replaceIdentName( + comprehensionExpr.comprehension().loopStep().toBuilder(), + originalIterVar, + mangledComprehensionName.iterVarName()); + comprehensionExpr.setComprehension( + comprehensionExpr.comprehension().toBuilder() + .setLoopStep(modifiedLoopStep.build()) + .build()); + comprehensionExpr = + replaceIdentName(comprehensionExpr, originalAccuVar, mangledComprehensionName.resultName()); + + CelComprehension.Builder newComprehension = + comprehensionExpr.comprehension().toBuilder() + .setIterVar(mangledComprehensionName.iterVarName()); + // Most standard macros set accu_var as __result__, but not all (ex: cel.bind). + if (newComprehension.accuVar().equals(originalAccuVar)) { + newComprehension.setAccuVar(mangledComprehensionName.resultName()); + } + + return mutateExpr( + NO_OP_ID_GENERATOR, + root, + comprehensionExpr.setComprehension(newComprehension.build()), + comprehensionExpr.id()); + } + + private CelExpr.Builder replaceIdentName( + CelExpr.Builder comprehensionExpr, String originalIdentName, String newIdentName) { int iterCount; for (iterCount = 0; iterCount < iterationLimit; iterCount++) { Optional identToMangle = - CelNavigableExpr.fromExpr(comprehensionExpr.comprehension().loopStep()) + CelNavigableExpr.fromExpr(comprehensionExpr.build()) .descendants() .map(CelNavigableExpr::expr) - .filter(node -> node.identOrDefault().name().equals(originalIterVar)) + .filter(node -> node.identOrDefault().name().equals(originalIdentName)) .findAny(); if (!identToMangle.isPresent()) { break; @@ -398,7 +458,7 @@ private CelExpr.Builder mangleIdentsInComprehensionExpr( mutateExpr( NO_OP_ID_GENERATOR, comprehensionExpr, - CelExpr.newBuilder().setIdent(CelIdent.newBuilder().setName(mangledVarName).build()), + CelExpr.newBuilder().setIdent(CelIdent.newBuilder().setName(newIdentName).build()), identToMangle.get().id()); } @@ -406,19 +466,14 @@ private CelExpr.Builder mangleIdentsInComprehensionExpr( throw new IllegalStateException("Max iteration count reached."); } - return mutateExpr( - NO_OP_ID_GENERATOR, - root, - comprehensionExpr.setComprehension( - comprehensionExpr.comprehension().toBuilder().setIterVar(mangledVarName).build()), - comprehensionExpr.id()); + return comprehensionExpr; } private CelSource mangleIdentsInMacroSource( CelAbstractSyntaxTree ast, CelExpr.Builder mutatedComprehensionExpr, String originalIterVar, - String mangledVarName, + MangledComprehensionName mangledComprehensionName, long originalComprehensionId) { if (!ast.getSource().getMacroCalls().containsKey(originalComprehensionId)) { return ast.getSource(); @@ -446,7 +501,9 @@ private CelSource mangleIdentsInMacroSource( mutateExpr( NO_OP_ID_GENERATOR, macroExpr, - CelExpr.newBuilder().setIdent(CelIdent.newBuilder().setName(mangledVarName).build()), + CelExpr.newBuilder() + .setIdent( + CelIdent.newBuilder().setName(mangledComprehensionName.iterVarName()).build()), identToMangle.id()); newSource.addMacroCalls(originalComprehensionId, macroExpr.build()); @@ -652,8 +709,8 @@ private static int countComprehensionNestingLevel(CelNavigableExpr comprehension } /** - * Intermediate value class to store the mangled identifiers for iteration variable in the - * comprehension. + * Intermediate value class to store the mangled identifiers for iteration variable and the + * comprehension result. */ @AutoValue public abstract static class MangledComprehensionAst { @@ -662,11 +719,49 @@ public abstract static class MangledComprehensionAst { public abstract CelAbstractSyntaxTree ast(); /** Map containing the mangled identifier names to their types. */ - public abstract ImmutableMap mangledComprehensionIdents(); + public abstract ImmutableMap + mangledComprehensionMap(); private static MangledComprehensionAst of( - CelAbstractSyntaxTree ast, ImmutableMap mangledComprehensionIdents) { - return new AutoValue_MutableAst_MangledComprehensionAst(ast, mangledComprehensionIdents); + CelAbstractSyntaxTree ast, + ImmutableMap mangledComprehensionMap) { + return new AutoValue_MutableAst_MangledComprehensionAst(ast, mangledComprehensionMap); + } + } + + /** + * Intermediate value class to store the types for iter_var and comprehension result of which its + * identifier names are being mangled. + */ + @AutoValue + public abstract static class MangledComprehensionType { + + /** Type of iter_var */ + public abstract CelType iterVarType(); + + /** Type of comprehension result */ + public abstract CelType resultType(); + + private static MangledComprehensionType of(CelType iterVarType, CelType resultType) { + return new AutoValue_MutableAst_MangledComprehensionType(iterVarType, resultType); + } + } + + /** + * Intermediate value class to store the mangled names for iteration variable and the + * comprehension result. + */ + @AutoValue + public abstract static class MangledComprehensionName { + + /** Mangled name for iter_var */ + public abstract String iterVarName(); + + /** Mangled name for comprehension result */ + public abstract String resultName(); + + private static MangledComprehensionName of(String iterVarName, String resultName) { + return new AutoValue_MutableAst_MangledComprehensionName(iterVarName, resultName); } } diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java index 4933b90d8..8cf71e753 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java @@ -85,6 +85,7 @@ public class SubexpressionOptimizer implements CelAstOptimizer { new SubexpressionOptimizer(SubexpressionOptimizerOptions.newBuilder().build()); private static final String BIND_IDENTIFIER_PREFIX = "@r"; private static final String MANGLED_COMPREHENSION_IDENTIFIER_PREFIX = "@c"; + private static final String MANGLED_COMPREHENSION_RESULT_PREFIX = "@x"; private static final String CEL_BLOCK_FUNCTION = "cel.@block"; private static final String BLOCK_INDEX_PREFIX = "@index"; private static final ImmutableSet CSE_ALLOWED_FUNCTIONS = @@ -127,7 +128,9 @@ private CelAbstractSyntaxTree optimizeUsingCelBlock( CelType resultType = navigableAst.getAst().getResultType(); MangledComprehensionAst mangledComprehensionAst = mutableAst.mangleComprehensionIdentifierNames( - navigableAst.getAst(), MANGLED_COMPREHENSION_IDENTIFIER_PREFIX); + navigableAst.getAst(), + MANGLED_COMPREHENSION_IDENTIFIER_PREFIX, + MANGLED_COMPREHENSION_RESULT_PREFIX); CelAbstractSyntaxTree astToModify = mangledComprehensionAst.ast(); CelSource sourceToModify = astToModify.getSource(); @@ -191,10 +194,12 @@ private CelAbstractSyntaxTree optimizeUsingCelBlock( // Add all mangled comprehension identifiers to the environment, so that the subexpressions can // retain context to them. mangledComprehensionAst - .mangledComprehensionIdents() + .mangledComprehensionMap() .forEach( - (identName, type) -> - celBuilder.addVarDeclarations(CelVarDecl.newVarDeclaration(identName, type))); + (name, type) -> + celBuilder.addVarDeclarations( + CelVarDecl.newVarDeclaration(name.iterVarName(), type.iterVarType()), + CelVarDecl.newVarDeclaration(name.resultName(), type.resultType()))); // Type-check all sub-expressions then add them as block identifiers to the CEL environment addBlockIdentsToEnv(celBuilder, subexpressions); @@ -266,7 +271,9 @@ private CelAbstractSyntaxTree optimizeUsingCelBind(CelNavigableAst navigableAst) CelAbstractSyntaxTree astToModify = mutableAst .mangleComprehensionIdentifierNames( - navigableAst.getAst(), MANGLED_COMPREHENSION_IDENTIFIER_PREFIX) + navigableAst.getAst(), + MANGLED_COMPREHENSION_IDENTIFIER_PREFIX, + MANGLED_COMPREHENSION_RESULT_PREFIX) .ast(); CelSource sourceToModify = astToModify.getSource(); @@ -432,7 +439,7 @@ private static boolean isWithinInlineableComprehension(CelNavigableExpr expr) { // result, loopStep or iterRange. While result is not human authored, it needs to be // included to extract subexpressions that are already in cel.bind macro. CelNavigableExpr.fromExpr(parent.expr().comprehension().result()).descendants(), - CelNavigableExpr.fromExpr(parent.expr().comprehension().loopStep()).descendants(), + CelNavigableExpr.fromExpr(parent.expr().comprehension().loopStep()).allNodes(), CelNavigableExpr.fromExpr(parent.expr().comprehension().iterRange()).allNodes()) .filter( node -> diff --git a/optimizer/src/test/java/dev/cel/optimizer/MutableAstTest.java b/optimizer/src/test/java/dev/cel/optimizer/MutableAstTest.java index 557302e40..da8ecfb7b 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/MutableAstTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/MutableAstTest.java @@ -682,7 +682,7 @@ public void mangleComprehensionVariable_singleMacro() throws Exception { CelAbstractSyntaxTree ast = CEL.compile("[false].exists(i, i)").getAst(); CelAbstractSyntaxTree mangledAst = - MUTABLE_AST.mangleComprehensionIdentifierNames(ast, "@c").ast(); + MUTABLE_AST.mangleComprehensionIdentifierNames(ast, "@c", "@x").ast(); assertThat(mangledAst.getExpr().toString()) .isEqualTo( @@ -695,7 +695,7 @@ public void mangleComprehensionVariable_singleMacro() throws Exception { + " }\n" + " }\n" + " }\n" - + " accu_var: __result__\n" + + " accu_var: @x0:0\n" + " accu_init: {\n" + " CONSTANT [6] { value: false }\n" + " }\n" @@ -707,7 +707,7 @@ public void mangleComprehensionVariable_singleMacro() throws Exception { + " function: !_\n" + " args: {\n" + " IDENT [7] {\n" - + " name: __result__\n" + + " name: @x0:0\n" + " }\n" + " }\n" + " }\n" @@ -719,7 +719,7 @@ public void mangleComprehensionVariable_singleMacro() throws Exception { + " function: _||_\n" + " args: {\n" + " IDENT [10] {\n" - + " name: __result__\n" + + " name: @x0:0\n" + " }\n" + " IDENT [5] {\n" + " name: @c0:0\n" @@ -729,7 +729,7 @@ public void mangleComprehensionVariable_singleMacro() throws Exception { + " }\n" + " result: {\n" + " IDENT [12] {\n" - + " name: __result__\n" + + " name: @x0:0\n" + " }\n" + " }\n" + "}"); @@ -743,7 +743,7 @@ public void mangleComprehensionVariable_nestedMacroWithShadowedVariables() throw CelAbstractSyntaxTree ast = CEL.compile("[x].exists(x, [x].exists(x, x == 1))").getAst(); CelAbstractSyntaxTree mangledAst = - MUTABLE_AST.mangleComprehensionIdentifierNames(ast, "@c").ast(); + MUTABLE_AST.mangleComprehensionIdentifierNames(ast, "@c", "@x").ast(); assertThat(mangledAst.getExpr().toString()) .isEqualTo( @@ -758,7 +758,7 @@ public void mangleComprehensionVariable_nestedMacroWithShadowedVariables() throw + " }\n" + " }\n" + " }\n" - + " accu_var: __result__\n" + + " accu_var: @x0:0\n" + " accu_init: {\n" + " CONSTANT [20] { value: false }\n" + " }\n" @@ -770,7 +770,7 @@ public void mangleComprehensionVariable_nestedMacroWithShadowedVariables() throw + " function: !_\n" + " args: {\n" + " IDENT [21] {\n" - + " name: __result__\n" + + " name: @x0:0\n" + " }\n" + " }\n" + " }\n" @@ -782,7 +782,7 @@ public void mangleComprehensionVariable_nestedMacroWithShadowedVariables() throw + " function: _||_\n" + " args: {\n" + " IDENT [24] {\n" - + " name: __result__\n" + + " name: @x0:0\n" + " }\n" + " COMPREHENSION [19] {\n" + " iter_var: @c1:0\n" @@ -795,7 +795,7 @@ public void mangleComprehensionVariable_nestedMacroWithShadowedVariables() throw + " }\n" + " }\n" + " }\n" - + " accu_var: __result__\n" + + " accu_var: @x1:0\n" + " accu_init: {\n" + " CONSTANT [12] { value: false }\n" + " }\n" @@ -807,7 +807,7 @@ public void mangleComprehensionVariable_nestedMacroWithShadowedVariables() throw + " function: !_\n" + " args: {\n" + " IDENT [13] {\n" - + " name: __result__\n" + + " name: @x1:0\n" + " }\n" + " }\n" + " }\n" @@ -819,7 +819,7 @@ public void mangleComprehensionVariable_nestedMacroWithShadowedVariables() throw + " function: _||_\n" + " args: {\n" + " IDENT [16] {\n" - + " name: __result__\n" + + " name: @x1:0\n" + " }\n" + " CALL [10] {\n" + " function: _==_\n" @@ -835,7 +835,7 @@ public void mangleComprehensionVariable_nestedMacroWithShadowedVariables() throw + " }\n" + " result: {\n" + " IDENT [18] {\n" - + " name: __result__\n" + + " name: @x1:0\n" + " }\n" + " }\n" + " }\n" @@ -844,11 +844,10 @@ public void mangleComprehensionVariable_nestedMacroWithShadowedVariables() throw + " }\n" + " result: {\n" + " IDENT [26] {\n" - + " name: __result__\n" + + " name: @x0:0\n" + " }\n" + " }\n" + "}"); - assertThat(CEL_UNPARSER.unparse(mangledAst)) .isEqualTo("[x].exists(@c0:0, [@c0:0].exists(@c1:0, @c1:0 == 1))"); assertThat(CEL.createProgram(CEL.check(mangledAst).getAst()).eval(ImmutableMap.of("x", 1))) @@ -861,7 +860,7 @@ public void mangleComprehensionVariable_hasMacro_noOp() throws Exception { CelAbstractSyntaxTree ast = CEL.compile("has(msg.single_int64)").getAst(); CelAbstractSyntaxTree mangledAst = - MUTABLE_AST.mangleComprehensionIdentifierNames(ast, "@c").ast(); + MUTABLE_AST.mangleComprehensionIdentifierNames(ast, "@c", "@x").ast(); assertThat(CEL_UNPARSER.unparse(mangledAst)).isEqualTo("has(msg.single_int64)"); assertThat( From a740bbd12930b7940941cfc3dccfa4a8afa4fc9c Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Wed, 21 Feb 2024 13:27:35 -0800 Subject: [PATCH 035/486] Mark type-checker implementation as internal PiperOrigin-RevId: 609103910 --- checker/src/main/java/dev/cel/checker/BUILD.bazel | 1 + .../src/main/java/dev/cel/checker/CelCheckerLegacyImpl.java | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/checker/src/main/java/dev/cel/checker/BUILD.bazel b/checker/src/main/java/dev/cel/checker/BUILD.bazel index d5832a4f8..0053d9061 100644 --- a/checker/src/main/java/dev/cel/checker/BUILD.bazel +++ b/checker/src/main/java/dev/cel/checker/BUILD.bazel @@ -73,6 +73,7 @@ java_library( "//common", "//common:compiler_common", "//common:options", + "//common/annotations", "//common/ast:expr_converter", "//common/internal:env_visitor", "//common/internal:errors", diff --git a/checker/src/main/java/dev/cel/checker/CelCheckerLegacyImpl.java b/checker/src/main/java/dev/cel/checker/CelCheckerLegacyImpl.java index 4ed263c11..950c919e3 100644 --- a/checker/src/main/java/dev/cel/checker/CelCheckerLegacyImpl.java +++ b/checker/src/main/java/dev/cel/checker/CelCheckerLegacyImpl.java @@ -40,6 +40,7 @@ import dev.cel.common.CelSourceLocation; import dev.cel.common.CelValidationResult; import dev.cel.common.CelVarDecl; +import dev.cel.common.annotations.Internal; import dev.cel.common.ast.CelExprConverter; import dev.cel.common.internal.EnvVisitable; import dev.cel.common.internal.EnvVisitor; @@ -57,8 +58,12 @@ /** * {@code CelChecker} implementation which uses the original CEL-Java APIs to provide a simple, * consistent interface for type-checking. + * + *

CEL Library Internals. Do Not Use. Consumers should use {@code CelCompilerFactory} to + * instantiate a type-checker. */ @Immutable +@Internal public final class CelCheckerLegacyImpl implements CelChecker, EnvVisitable { private final CelOptions celOptions; From 1e123053cc04493d7b2e7033c8fc6c32b2bcd9fb Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Wed, 21 Feb 2024 13:40:55 -0800 Subject: [PATCH 036/486] Create an enum for functions used in CelOptionalLibrary PiperOrigin-RevId: 609107977 --- .../cel/extensions/CelOptionalLibrary.java | 49 ++++++++++++------- .../dev/cel/optimizer/optimizers/BUILD.bazel | 1 + .../optimizers/ConstantFoldingOptimizer.java | 28 +++++------ 3 files changed, 47 insertions(+), 31 deletions(-) diff --git a/extensions/src/main/java/dev/cel/extensions/CelOptionalLibrary.java b/extensions/src/main/java/dev/cel/extensions/CelOptionalLibrary.java index 96796cde3..1da3e57d1 100644 --- a/extensions/src/main/java/dev/cel/extensions/CelOptionalLibrary.java +++ b/extensions/src/main/java/dev/cel/extensions/CelOptionalLibrary.java @@ -50,11 +50,26 @@ public final class CelOptionalLibrary implements CelCompilerLibrary, CelRuntimeLibrary { public static final CelOptionalLibrary INSTANCE = new CelOptionalLibrary(); - private static final String VALUE_FUNCTION = "value"; - private static final String HAS_VALUE_FUNCTION = "hasValue"; - private static final String OPTIONAL_NONE_FUNCTION = "optional.none"; - private static final String OPTIONAL_OF_FUNCTION = "optional.of"; - private static final String OPTIONAL_OF_NON_ZERO_VALUE_FUNCTION = "optional.ofNonZeroValue"; + /** Enumerations of function names used for supporting optionals. */ + public enum Function { + VALUE("value"), + HAS_VALUE("hasValue"), + OPTIONAL_NONE("optional.none"), + OPTIONAL_OF("optional.of"), + OPTIONAL_OF_NON_ZERO_VALUE("optional.ofNonZeroValue"), + OR("or"), + OR_VALUE("orValue"); + private final String functionName; + + public String getFunction() { + return functionName; + } + + Function(String functionName) { + this.functionName = functionName; + } + } + private static final String UNUSED_ITER_VAR = "#unused"; @Override @@ -80,20 +95,20 @@ public void setCheckerOptions(CelCheckerBuilder checkerBuilder) { MapType mapTypeKv = MapType.create(paramTypeK, paramTypeV); checkerBuilder.addFunctionDeclarations( CelFunctionDecl.newFunctionDeclaration( - OPTIONAL_OF_FUNCTION, + Function.OPTIONAL_OF.getFunction(), CelOverloadDecl.newGlobalOverload("optional_of", optionalTypeV, paramTypeV)), CelFunctionDecl.newFunctionDeclaration( - OPTIONAL_OF_NON_ZERO_VALUE_FUNCTION, + Function.OPTIONAL_OF_NON_ZERO_VALUE.getFunction(), CelOverloadDecl.newGlobalOverload( "optional_ofNonZeroValue", optionalTypeV, paramTypeV)), CelFunctionDecl.newFunctionDeclaration( - OPTIONAL_NONE_FUNCTION, + Function.OPTIONAL_NONE.getFunction(), CelOverloadDecl.newGlobalOverload("optional_none", optionalTypeV)), CelFunctionDecl.newFunctionDeclaration( - VALUE_FUNCTION, + Function.VALUE.getFunction(), CelOverloadDecl.newMemberOverload("optional_value", paramTypeV, optionalTypeV)), CelFunctionDecl.newFunctionDeclaration( - HAS_VALUE_FUNCTION, + Function.HAS_VALUE.getFunction(), CelOverloadDecl.newMemberOverload("optional_hasValue", SimpleType.BOOL, optionalTypeV)), // Note: Implementation of "or" and "orValue" are special-cased inside the interpreter. // Hence, their bindings are not provided here. @@ -218,18 +233,18 @@ private static Optional expandOptMap( return Optional.of( exprFactory.newGlobalCall( Operator.CONDITIONAL.getFunction(), - exprFactory.newReceiverCall(HAS_VALUE_FUNCTION, target), + exprFactory.newReceiverCall(Function.HAS_VALUE.getFunction(), target), exprFactory.newGlobalCall( - OPTIONAL_OF_FUNCTION, + Function.OPTIONAL_OF.getFunction(), exprFactory.fold( UNUSED_ITER_VAR, exprFactory.newList(), varName, - exprFactory.newReceiverCall(VALUE_FUNCTION, target), + exprFactory.newReceiverCall(Function.VALUE.getFunction(), target), exprFactory.newBoolLiteral(true), exprFactory.newIdentifier(varName), mapExpr)), - exprFactory.newGlobalCall(OPTIONAL_NONE_FUNCTION))); + exprFactory.newGlobalCall(Function.OPTIONAL_NONE.getFunction()))); } private static Optional expandOptFlatMap( @@ -252,16 +267,16 @@ private static Optional expandOptFlatMap( return Optional.of( exprFactory.newGlobalCall( Operator.CONDITIONAL.getFunction(), - exprFactory.newReceiverCall(HAS_VALUE_FUNCTION, target), + exprFactory.newReceiverCall(Function.HAS_VALUE.getFunction(), target), exprFactory.fold( UNUSED_ITER_VAR, exprFactory.newList(), varName, - exprFactory.newReceiverCall(VALUE_FUNCTION, target), + exprFactory.newReceiverCall(Function.VALUE.getFunction(), target), exprFactory.newBoolLiteral(true), exprFactory.newIdentifier(varName), mapExpr), - exprFactory.newGlobalCall(OPTIONAL_NONE_FUNCTION))); + exprFactory.newGlobalCall(Function.OPTIONAL_NONE.getFunction()))); } private CelOptionalLibrary() {} diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel b/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel index 77b3d289b..785ddf74a 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel @@ -21,6 +21,7 @@ java_library( "//common/ast", "//common/ast:expr_util", "//common/navigation", + "//extensions:optional_library", "//optimizer:ast_optimizer", "//optimizer:mutable_ast", "//optimizer:optimization_exception", diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java b/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java index 8ca19e941..6766ae3c4 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java @@ -32,6 +32,7 @@ import dev.cel.common.ast.CelExprUtil; import dev.cel.common.navigation.CelNavigableAst; import dev.cel.common.navigation.CelNavigableExpr; +import dev.cel.extensions.CelOptionalLibrary.Function; import dev.cel.optimizer.CelAstOptimizer; import dev.cel.optimizer.CelOptimizationException; import dev.cel.optimizer.MutableAst; @@ -68,10 +69,9 @@ public static ConstantFoldingOptimizer newInstance( // Use optional.of and optional.none as sentinel function names for folding optional calls. // TODO: Leverage CelValue representation of Optionals instead when available. - private static final String OPTIONAL_OF_FUNCTION = "optional.of"; - private static final String OPTIONAL_NONE_FUNCTION = "optional.none"; private static final CelExpr OPTIONAL_NONE_EXPR = - CelExpr.ofCallExpr(0, Optional.empty(), OPTIONAL_NONE_FUNCTION, ImmutableList.of()); + CelExpr.ofCallExpr( + 0, Optional.empty(), Function.OPTIONAL_NONE.getFunction(), ImmutableList.of()); private final ConstantFoldingOptions constantFoldingOptions; private final MutableAst mutableAst; @@ -130,8 +130,8 @@ private static boolean canFold(CelNavigableExpr navigableExpr) { String functionName = celCall.function(); // These are already folded or do not need to be folded. - if (functionName.equals(OPTIONAL_OF_FUNCTION) - || functionName.equals(OPTIONAL_NONE_FUNCTION)) { + if (functionName.equals(Function.OPTIONAL_OF.getFunction()) + || functionName.equals(Function.OPTIONAL_NONE.getFunction())) { return false; } @@ -264,13 +264,13 @@ private Optional maybeAdaptEvaluatedResult(Object result) { private Optional maybeRewriteOptional( Optional optResult, CelAbstractSyntaxTree ast, CelExpr expr) { if (!optResult.isPresent()) { - if (!expr.callOrDefault().function().equals(OPTIONAL_NONE_FUNCTION)) { + if (!expr.callOrDefault().function().equals(Function.OPTIONAL_NONE.getFunction())) { // An empty optional value was encountered. Rewrite the tree with optional.none call. // This is to account for other optional functions returning an empty optional value // e.g: optional.ofNonZeroValue(0) return Optional.of(mutableAst.replaceSubtree(ast, OPTIONAL_NONE_EXPR, expr.id())); } - } else if (!expr.callOrDefault().function().equals(OPTIONAL_OF_FUNCTION)) { + } else if (!expr.callOrDefault().function().equals(Function.OPTIONAL_OF.getFunction())) { Object unwrappedResult = optResult.get(); if (!CelConstant.isConstantValue(unwrappedResult)) { // Evaluated result is not a constant. Leave the optional as is. @@ -281,7 +281,7 @@ private Optional maybeRewriteOptional( CelExpr.newBuilder() .setCall( CelCall.newBuilder() - .setFunction(OPTIONAL_OF_FUNCTION) + .setFunction(Function.OPTIONAL_OF.getFunction()) .addArgs( CelExpr.newBuilder() .setConstant(CelConstant.ofObjectValue(unwrappedResult)) @@ -444,12 +444,12 @@ private CelAbstractSyntaxTree pruneOptionalListElements(CelAbstractSyntaxTree as if (element.exprKind().getKind().equals(Kind.CALL)) { CelCall call = element.call(); - if (call.function().equals(OPTIONAL_NONE_FUNCTION)) { + if (call.function().equals(Function.OPTIONAL_NONE.getFunction())) { // Skip optional.none. // Skipping causes the list to get smaller. newOptIndex--; continue; - } else if (call.function().equals(OPTIONAL_OF_FUNCTION)) { + } else if (call.function().equals(Function.OPTIONAL_OF.getFunction())) { CelExpr arg = call.args().get(0); if (arg.exprKind().getKind().equals(Kind.CONSTANT)) { updatedElemBuilder.add(call.args().get(0)); @@ -491,11 +491,11 @@ private CelAbstractSyntaxTree pruneOptionalMapElements(CelAbstractSyntaxTree ast } CelCall call = value.call(); - if (call.function().equals(OPTIONAL_NONE_FUNCTION)) { + if (call.function().equals(Function.OPTIONAL_NONE.getFunction())) { // Skip the element. This is resolving an optional.none: ex {?1: optional.none()}. modified = true; continue; - } else if (call.function().equals(OPTIONAL_OF_FUNCTION)) { + } else if (call.function().equals(Function.OPTIONAL_OF.getFunction())) { CelExpr arg = call.args().get(0); if (arg.exprKind().getKind().equals(Kind.CONSTANT)) { modified = true; @@ -537,11 +537,11 @@ private CelAbstractSyntaxTree pruneOptionalStructElements( } CelCall call = value.call(); - if (call.function().equals(OPTIONAL_NONE_FUNCTION)) { + if (call.function().equals(Function.OPTIONAL_NONE.getFunction())) { // Skip the element. This is resolving an optional.none: ex msg{?field: optional.none()}. modified = true; continue; - } else if (call.function().equals(OPTIONAL_OF_FUNCTION)) { + } else if (call.function().equals(Function.OPTIONAL_OF.getFunction())) { CelExpr arg = call.args().get(0); if (arg.exprKind().getKind().equals(Kind.CONSTANT)) { modified = true; From 5ebf44e3ffe2559609d5d8f45e7bbd27d6efc942 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Wed, 21 Feb 2024 14:02:08 -0800 Subject: [PATCH 037/486] Allow setting nesting limit for extractable subexpressions. PiperOrigin-RevId: 609114886 --- .../java/dev/cel/optimizer/MutableAst.java | 106 ++-- .../dev/cel/optimizer/optimizers/BUILD.bazel | 1 + .../optimizers/SubexpressionOptimizer.java | 153 +++-- .../SubexpressionOptimizerTest.java | 539 +++++++++++++++--- 4 files changed, 627 insertions(+), 172 deletions(-) diff --git a/optimizer/src/main/java/dev/cel/optimizer/MutableAst.java b/optimizer/src/main/java/dev/cel/optimizer/MutableAst.java index 9333726ac..1a466df67 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/MutableAst.java +++ b/optimizer/src/main/java/dev/cel/optimizer/MutableAst.java @@ -29,6 +29,7 @@ import dev.cel.common.CelAbstractSyntaxTree; import dev.cel.common.CelSource; import dev.cel.common.ast.CelExpr; +import dev.cel.common.ast.CelExpr.CelCall; import dev.cel.common.ast.CelExpr.CelComprehension; import dev.cel.common.ast.CelExpr.CelIdent; import dev.cel.common.ast.CelExpr.ExprKind.Kind; @@ -41,6 +42,7 @@ import dev.cel.common.navigation.CelNavigableExpr; import dev.cel.common.navigation.CelNavigableExpr.TraversalOrder; import dev.cel.common.types.CelType; +import java.util.Collection; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map.Entry; @@ -132,6 +134,26 @@ public CelAbstractSyntaxTree replaceSubtree( exprIdToReplace); } + /** Wraps the given AST and its subexpressions with a new cel.@block call. */ + public CelAbstractSyntaxTree wrapAstWithNewCelBlock( + String celBlockFunction, CelAbstractSyntaxTree ast, Collection subexpressions) { + long maxId = getMaxId(ast); + CelExpr blockExpr = + CelExpr.newBuilder() + .setId(++maxId) + .setCall( + CelCall.newBuilder() + .setFunction(celBlockFunction) + .addArgs( + CelExpr.ofCreateListExpr( + ++maxId, ImmutableList.copyOf(subexpressions), ImmutableList.of()), + ast.getExpr()) + .build()) + .build(); + + return CelAbstractSyntaxTree.newParsedAst(blockExpr, ast.getSource()); + } + /** * Generates a new bind macro using the provided initialization and result expression, then * replaces the subtree using the new bind expr at the designated expr ID. @@ -233,13 +255,17 @@ public MangledComprehensionAst mangleComprehensionIdentifierNames( .filter(comprehensionIdentifierPredicate) .filter( node -> { - // Ensure the iter_var is actually referenced in the loop_step. If it's not, we + // Ensure the iter_var or the comprehension result is actually referenced in the + // loop_step. If it's not, we // can skip mangling. String iterVar = node.expr().comprehension().iterVar(); + String result = node.expr().comprehension().result().ident().name(); return CelNavigableExpr.fromExpr(node.expr().comprehension().loopStep()) .allNodes() + .filter(subNode -> subNode.getKind().equals(Kind.IDENT)) + .map(subNode -> subNode.expr().ident()) .anyMatch( - subNode -> subNode.expr().identOrDefault().name().contains(iterVar)); + ident -> ident.name().contains(iterVar) || ident.name().contains(result)); }) .collect( Collectors.toMap( @@ -247,35 +273,29 @@ public MangledComprehensionAst mangleComprehensionIdentifierNames( v -> { CelComprehension comprehension = v.expr().comprehension(); String iterVar = comprehension.iterVar(); - long iterVarId = + // Identifiers to mangle could be the iteration variable, comprehension result + // or both, but at least one has to exist. + // As an example, [1,2].map(i, 3) would produce an optional.empty because `i` + // is not actually used. + Optional iterVarId = CelNavigableExpr.fromExpr(comprehension.loopStep()) .allNodes() .filter( loopStepNode -> loopStepNode.expr().identOrDefault().name().equals(iterVar)) .map(CelNavigableExpr::id) - .findAny() - .orElseThrow( - () -> { - throw new NoSuchElementException( - "Expected iteration variable to exist in expr id: " - + v.id()); - }); - - CelType iterVarType = - ast.getType(iterVarId) - .orElseThrow( - () -> - new NoSuchElementException( - "Checked type not present for iteration variable: " - + iterVarId)); - CelType resultType = - ast.getType(comprehension.result().id()) - .orElseThrow( - () -> - new NoSuchElementException( - "Checked type not present for result: " - + comprehension.result().id())); + .findAny(); + Optional iterVarType = + iterVarId.map( + id -> + ast.getType(id) + .orElseThrow( + () -> + new NoSuchElementException( + "Checked type not present for iteration variable:" + + " " + + iterVarId))); + Optional resultType = ast.getType(comprehension.result().id()); return MangledComprehensionType.of(iterVarType, resultType); }, @@ -487,24 +507,26 @@ private CelSource mangleIdentsInMacroSource( // Note that in the above example, the iteration variable is not replaced after normalization. // This is because populating a macro call map upon parse generates a new unique identifier // that does not exist in the main AST. Thus, we need to manually replace the identifier. + // Also note that this only applies when the macro is at leaf. For nested macros, the iteration + // variable actually exists in the main AST thus, this step isn't needed. + // ex: [1].map(x, [2].filter(y, x == y). Here, the variable declaration `x` exists in the AST + // but not `y`. CelExpr.Builder macroExpr = newSource.getMacroCalls().get(originalComprehensionId).toBuilder(); // By convention, the iteration variable is always the first argument of the // macro call expression. CelExpr identToMangle = macroExpr.call().args().get(0); - if (!identToMangle.identOrDefault().name().equals(originalIterVar)) { - throw new IllegalStateException( - String.format( - "Expected %s for iteration variable but got %s instead.", - identToMangle.identOrDefault().name(), originalIterVar)); + if (identToMangle.identOrDefault().name().equals(originalIterVar)) { + macroExpr = + mutateExpr( + NO_OP_ID_GENERATOR, + macroExpr, + CelExpr.newBuilder() + .setIdent( + CelIdent.newBuilder() + .setName(mangledComprehensionName.iterVarName()) + .build()), + identToMangle.id()); } - macroExpr = - mutateExpr( - NO_OP_ID_GENERATOR, - macroExpr, - CelExpr.newBuilder() - .setIdent( - CelIdent.newBuilder().setName(mangledComprehensionName.iterVarName()).build()), - identToMangle.id()); newSource.addMacroCalls(originalComprehensionId, macroExpr.build()); return newSource.build(); @@ -737,12 +759,14 @@ private static MangledComprehensionAst of( public abstract static class MangledComprehensionType { /** Type of iter_var */ - public abstract CelType iterVarType(); + public abstract Optional iterVarType(); /** Type of comprehension result */ - public abstract CelType resultType(); + public abstract Optional resultType(); - private static MangledComprehensionType of(CelType iterVarType, CelType resultType) { + private static MangledComprehensionType of( + Optional iterVarType, Optional resultType) { + Preconditions.checkArgument(iterVarType.isPresent() || resultType.isPresent()); return new AutoValue_MutableAst_MangledComprehensionType(iterVarType, resultType); } } diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel b/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel index 785ddf74a..279323603 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel @@ -48,6 +48,7 @@ java_library( "//common/navigation", "//common/types", "//common/types:type_providers", + "//extensions:optional_library", "//optimizer:ast_optimizer", "//optimizer:mutable_ast", "//parser:operator", diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java index 8cf71e753..4c7c081a9 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java @@ -20,8 +20,10 @@ import com.google.auto.value.AutoValue; import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; import com.google.common.collect.Streams; import dev.cel.bundle.CelBuilder; import dev.cel.checker.Standard; @@ -35,7 +37,6 @@ import dev.cel.common.CelValidationException; import dev.cel.common.CelVarDecl; import dev.cel.common.ast.CelExpr; -import dev.cel.common.ast.CelExpr.CelCall; import dev.cel.common.ast.CelExpr.CelIdent; import dev.cel.common.ast.CelExpr.ExprKind.Kind; import dev.cel.common.navigation.CelNavigableAst; @@ -44,6 +45,8 @@ import dev.cel.common.types.CelType; import dev.cel.common.types.ListType; import dev.cel.common.types.SimpleType; +import dev.cel.extensions.CelOptionalLibrary; +import dev.cel.extensions.CelOptionalLibrary.Function; import dev.cel.optimizer.CelAstOptimizer; import dev.cel.optimizer.MutableAst; import dev.cel.optimizer.MutableAst.MangledComprehensionAst; @@ -91,10 +94,13 @@ public class SubexpressionOptimizer implements CelAstOptimizer { private static final ImmutableSet CSE_ALLOWED_FUNCTIONS = Streams.concat( stream(Operator.values()).map(Operator::getFunction), - stream(Standard.Function.values()).map(Standard.Function::getFunction)) + stream(Standard.Function.values()).map(Standard.Function::getFunction), + stream(CelOptionalLibrary.Function.values()).map(Function::getFunction)) .collect(toImmutableSet()); + private static final Extension CEL_BLOCK_AST_EXTENSION_TAG = Extension.create("cel_block", Version.of(1L, 1L), Component.COMPONENT_RUNTIME); + private final SubexpressionOptimizerOptions cseOptions; private final MutableAst mutableAst; @@ -186,6 +192,11 @@ private CelAbstractSyntaxTree optimizeUsingCelBlock( throw new IllegalStateException("Max iteration count reached."); } + if (!cseOptions.populateMacroCalls()) { + astToModify = + CelAbstractSyntaxTree.newParsedAst(astToModify.getExpr(), CelSource.newBuilder().build()); + } + if (iterCount == 0) { // No modification has been made. return astToModify; @@ -196,36 +207,28 @@ private CelAbstractSyntaxTree optimizeUsingCelBlock( mangledComprehensionAst .mangledComprehensionMap() .forEach( - (name, type) -> - celBuilder.addVarDeclarations( - CelVarDecl.newVarDeclaration(name.iterVarName(), type.iterVarType()), - CelVarDecl.newVarDeclaration(name.resultName(), type.resultType()))); + (name, type) -> { + type.iterVarType() + .ifPresent( + iterVarType -> + celBuilder.addVarDeclarations( + CelVarDecl.newVarDeclaration(name.iterVarName(), iterVarType))); + type.resultType() + .ifPresent( + comprehensionResultType -> + celBuilder.addVarDeclarations( + CelVarDecl.newVarDeclaration( + name.resultName(), comprehensionResultType))); + }); + // Type-check all sub-expressions then add them as block identifiers to the CEL environment addBlockIdentsToEnv(celBuilder, subexpressions); // Wrap the optimized expression in cel.block celBuilder.addFunctionDeclarations(newCelBlockFunctionDecl(resultType)); - int newId = 0; - CelExpr blockExpr = - CelExpr.newBuilder() - .setId(++newId) - .setCall( - CelCall.newBuilder() - .setFunction(CEL_BLOCK_FUNCTION) - .addArgs( - CelExpr.ofCreateListExpr( - ++newId, ImmutableList.copyOf(subexpressions), ImmutableList.of()), - astToModify.getExpr()) - .build()) - .build(); astToModify = - mutableAst.renumberIdsConsecutively( - CelAbstractSyntaxTree.newParsedAst(blockExpr, astToModify.getSource())); - - if (!cseOptions.populateMacroCalls()) { - astToModify = - CelAbstractSyntaxTree.newParsedAst(astToModify.getExpr(), CelSource.newBuilder().build()); - } + mutableAst.wrapAstWithNewCelBlock(CEL_BLOCK_FUNCTION, astToModify, subexpressions); + astToModify = mutableAst.renumberIdsConsecutively(astToModify); // Restore the expected result type the environment had prior to optimization. celBuilder.setResultType(resultType); @@ -399,14 +402,47 @@ private static CelNavigableExpr getLca(CelAbstractSyntaxTree ast, String boundId } private Optional findCseCandidate(CelAbstractSyntaxTree ast) { - HashSet encounteredNodes = new HashSet<>(); + if (cseOptions.enableCelBlock() && cseOptions.subexpressionMaxRecursionDepth() > 0) { + return findCseCandidateWithRecursionDepth(ast, cseOptions.subexpressionMaxRecursionDepth()); + } else { + return findCseCandidateWithCommonSubexpr(ast); + } + } + + /** + * This retrieves a subexpr candidate based on the recursion limit even if there's no duplicate + * subexpr found. + * + *

TODO: Improve the extraction logic using a suffix tree. + */ + private Optional findCseCandidateWithRecursionDepth( + CelAbstractSyntaxTree ast, int recursionLimit) { + Preconditions.checkArgument(recursionLimit > 0); ImmutableList allNodes = CelNavigableAst.fromAst(ast) .getRoot() - .allNodes(TraversalOrder.PRE_ORDER) + .allNodes(TraversalOrder.POST_ORDER) .filter(SubexpressionOptimizer::canEliminate) + .filter(node -> node.height() <= recursionLimit) + .filter(node -> !areSemanticallyEqual(ast.getExpr(), node.expr())) .collect(toImmutableList()); + if (allNodes.isEmpty()) { + return Optional.empty(); + } + + Optional commonSubexpr = findCseCandidateWithCommonSubexpr(allNodes); + if (commonSubexpr.isPresent()) { + return commonSubexpr; + } + // If there's no common subexpr, just return the one with the highest height that's still below + // the recursion limit. + return Optional.of(Iterables.getLast(allNodes)); + } + + private Optional findCseCandidateWithCommonSubexpr( + ImmutableList allNodes) { + HashSet encounteredNodes = new HashSet<>(); for (CelNavigableExpr node : allNodes) { // Normalize the expr to test semantic equivalence. CelExpr celExpr = normalizeForEquality(node.expr()); @@ -420,12 +456,23 @@ private Optional findCseCandidate(CelAbstractSyntaxTree ast) { return Optional.empty(); } + private Optional findCseCandidateWithCommonSubexpr(CelAbstractSyntaxTree ast) { + ImmutableList allNodes = + CelNavigableAst.fromAst(ast) + .getRoot() + .allNodes(TraversalOrder.PRE_ORDER) + .filter(SubexpressionOptimizer::canEliminate) + .collect(toImmutableList()); + + return findCseCandidateWithCommonSubexpr(allNodes); + } + private static boolean canEliminate(CelNavigableExpr navigableExpr) { return !navigableExpr.getKind().equals(Kind.CONSTANT) && !navigableExpr.getKind().equals(Kind.IDENT) && !navigableExpr.expr().identOrDefault().name().startsWith(BIND_IDENTIFIER_PREFIX) && !navigableExpr.expr().selectOrDefault().testOnly() - && isAllowedFunction(navigableExpr) + && containsAllowedFunctionOnly(navigableExpr) && isWithinInlineableComprehension(navigableExpr); } @@ -459,12 +506,17 @@ private boolean areSemanticallyEqual(CelExpr expr1, CelExpr expr2) { return normalizeForEquality(expr1).equals(normalizeForEquality(expr2)); } - private static boolean isAllowedFunction(CelNavigableExpr navigableExpr) { - if (navigableExpr.getKind().equals(Kind.CALL)) { - return CSE_ALLOWED_FUNCTIONS.contains(navigableExpr.expr().call().function()); - } - - return true; + private static boolean containsAllowedFunctionOnly(CelNavigableExpr navigableExpr) { + return navigableExpr + .allNodes() + .allMatch( + node -> { + if (node.getKind().equals(Kind.CALL)) { + return CSE_ALLOWED_FUNCTIONS.contains(node.expr().call().function()); + } + + return true; + }); } /** @@ -525,6 +577,8 @@ public abstract static class SubexpressionOptimizerOptions { public abstract boolean enableCelBlock(); + public abstract int subexpressionMaxRecursionDepth(); + /** Builder for configuring the {@link SubexpressionOptimizerOptions}. */ @AutoValue.Builder public abstract static class Builder { @@ -549,6 +603,32 @@ public abstract static class Builder { */ public abstract Builder enableCelBlock(boolean value); + /** + * Ensures all extracted subexpressions do not exceed the maximum depth of designated value. + * The purpose of this is to guarantee evaluation and deserialization safety by preventing + * deeply nested ASTs. The trade-off is increased memory usage due to memoizing additional + * block indices during lazy evaluation. + * + *

As a general note, root of a node has a depth of 0. An expression `x.y.z` has a depth of + * 2. + * + *

Note that expressions containing no common subexpressions may become a candidate for + * extraction to satisfy the max depth requirement. + * + *

This is a no-op if {@link #enableCelBlock} is set to false, or the configured value is + * less than 1. + * + *

Examples: + * + *

    + *
  1. a.b.c with depth 1 -> cel.@block([x.b, @index0.c], @index1) + *
  2. a.b + a.b.c.d with depth 3 -> cel.@block([a.b, @index0.c.d], @index0 + @index1) + *
+ * + *

+ */ + public abstract Builder subexpressionMaxRecursionDepth(int value); + public abstract SubexpressionOptimizerOptions build(); Builder() {} @@ -559,7 +639,8 @@ public static Builder newBuilder() { return new AutoValue_SubexpressionOptimizer_SubexpressionOptimizerOptions.Builder() .iterationLimit(500) .populateMacroCalls(false) - .enableCelBlock(false); + .enableCelBlock(false) + .subexpressionMaxRecursionDepth(0); } SubexpressionOptimizerOptions() {} diff --git a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java index 4b99c325c..57a7485f7 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java @@ -331,22 +331,30 @@ private enum CseTestCase { SIZE_1( "size([1,2]) + size([1,2]) + 1 == 5", "cel.bind(@r0, size([1, 2]), @r0 + @r0) + 1 == 5", - "cel.@block([size([1, 2])], @index0 + @index0 + 1 == 5)"), + "cel.@block([size([1, 2])], @index0 + @index0 + 1 == 5)", + "cel.@block([[1, 2], size(@index0), @index1 + @index1, @index2 + 1], @index3 == 5)"), SIZE_2( "2 + size([1,2]) + size([1,2]) + 1 == 7", "cel.bind(@r0, size([1, 2]), 2 + @r0 + @r0) + 1 == 7", - "cel.@block([size([1, 2])], 2 + @index0 + @index0 + 1 == 7)"), + "cel.@block([size([1, 2])], 2 + @index0 + @index0 + 1 == 7)", + "cel.@block([[1, 2], size(@index0), 2 + @index1, @index2 + @index1, @index3 + 1], @index4" + + " == 7)"), SIZE_3( "size([0]) + size([0]) + size([1,2]) + size([1,2]) == 6", "cel.bind(@r1, size([1, 2]), cel.bind(@r0, size([0]), @r0 + @r0) + @r1 + @r1) == 6", - "cel.@block([size([0]), size([1, 2])], @index0 + @index0 + @index1 + @index1 == 6)"), + "cel.@block([size([0]), size([1, 2])], @index0 + @index0 + @index1 + @index1 == 6)", + "cel.@block([[0], size(@index0), [1, 2], size(@index2), @index1 + @index1, @index4 +" + + " @index3, @index5 + @index3], @index6 == 6)"), SIZE_4( "5 + size([0]) + size([0]) + size([1,2]) + size([1,2]) + " + "size([1,2,3]) + size([1,2,3]) == 17", "cel.bind(@r2, size([1, 2, 3]), cel.bind(@r1, size([1, 2]), cel.bind(@r0, size([0]), 5 +" + " @r0 + @r0) + @r1 + @r1) + @r2 + @r2) == 17", "cel.@block([size([0]), size([1, 2]), size([1, 2, 3])], 5 + @index0 + @index0 + @index1 +" - + " @index1 + @index2 + @index2 == 17)"), + + " @index1 + @index2 + @index2 == 17)", + "cel.@block([[0], size(@index0), [1, 2], size(@index2), [1, 2, 3], size(@index4), 5 +" + + " @index1, @index6 + @index1, @index7 + @index3, @index8 + @index3, @index9 +" + + " @index5, @index10 + @index5], @index11 == 17)"), /** * Unparsed form: * @@ -400,11 +408,21 @@ private enum CseTestCase { + " timestamp(int(timestamp(50))), timestamp(int(timestamp(200))).getFullYear()," + " timestamp(int(timestamp(75)))], @index0 + @index3.getFullYear() +" + " @index1.getFullYear() + @index0 + @index1.getSeconds() + @index2 + @index2 +" - + " @index3.getMinutes() + @index0 == 13934)"), + + " @index3.getMinutes() + @index0 == 13934)", + "cel.@block([timestamp(1000000000), int(@index0), timestamp(@index1)," + + " @index2.getFullYear(), timestamp(50), int(@index4), timestamp(@index5)," + + " timestamp(200), int(@index7), timestamp(@index8), @index9.getFullYear()," + + " timestamp(75), int(@index11), timestamp(@index12), @index13.getMinutes()," + + " @index6.getSeconds(), @index6.getFullYear(), @index13.getFullYear(), @index3 +" + + " @index17, @index18 + @index16, @index19 + @index3, @index20 + @index15, @index21 +" + + " @index10, @index22 + @index10, @index23 + @index14, @index24 + @index3], @index25" + + " == 13934)"), MAP_INDEX( "{\"a\": 2}[\"a\"] + {\"a\": 2}[\"a\"] * {\"a\": 2}[\"a\"] == 6", "cel.bind(@r0, {\"a\": 2}[\"a\"], @r0 + @r0 * @r0) == 6", - "cel.@block([{\"a\": 2}[\"a\"]], @index0 + @index0 * @index0 == 6)"), + "cel.@block([{\"a\": 2}[\"a\"]], @index0 + @index0 * @index0 == 6)", + "cel.@block([{\"a\": 2}, @index0[\"a\"], @index1 * @index1, @index1 + @index2], @index3 ==" + + " 6)"), /** * Input map is: * @@ -426,17 +444,22 @@ private enum CseTestCase { "size(cel.bind(@r0, {\"b\": 1}, cel.bind(@r1, {\"e\": @r0}, {\"a\": @r0, \"c\": @r0, \"d\":" + " @r1, \"e\": @r1}))) == 4", "cel.@block([{\"b\": 1}, {\"e\": @index0}], size({\"a\": @index0, \"c\": @index0, \"d\":" - + " @index1, \"e\": @index1}) == 4)"), + + " @index1, \"e\": @index1}) == 4)", + "cel.@block([{\"b\": 1}, {\"e\": @index0}, {\"a\": @index0, \"c\": @index0, \"d\": @index1," + + " \"e\": @index1}, size(@index2)], @index3 == 4)"), NESTED_LIST_CONSTRUCTION( "size([1, [1,2,3,4], 2, [1,2,3,4], 5, [1,2,3,4], 7, [[1,2], [1,2,3,4]], [1,2]]) == 9", "size(cel.bind(@r0, [1, 2, 3, 4], " + "cel.bind(@r1, [1, 2], [1, @r0, 2, @r0, 5, @r0, 7, [@r1, @r0], @r1]))) == 9", "cel.@block([[1, 2, 3, 4], [1, 2]], size([1, @index0, 2, @index0, 5, @index0, 7, [@index1," - + " @index0], @index1]) == 9)"), + + " @index0], @index1]) == 9)", + "cel.@block([[1, 2, 3, 4], [1, 2], [@index1, @index0], [1, @index0, 2, @index0, 5, @index0," + + " 7, @index2, @index1], size(@index3)], @index4 == 9)"), SELECT( "msg.single_int64 + msg.single_int64 == 6", "cel.bind(@r0, msg.single_int64, @r0 + @r0) == 6", - "cel.@block([msg.single_int64], @index0 + @index0 == 6)"), + "cel.@block([msg.single_int64], @index0 + @index0 == 6)", + "cel.@block([msg.single_int64, @index0 + @index0], @index1 == 6)"), SELECT_NESTED( "msg.oneof_type.payload.single_int64 + msg.oneof_type.payload.single_int32 + " + "msg.oneof_type.payload.single_int64 + " @@ -445,37 +468,50 @@ private enum CseTestCase { + "cel.bind(@r1, @r0.single_int64, @r1 + @r0.single_int32 + @r1) + " + "msg.single_int64 + @r0.oneof_type.payload.single_int64) == 31", "cel.@block([msg.oneof_type.payload, @index0.single_int64], @index1 + @index0.single_int32" - + " + @index1 + msg.single_int64 + @index0.oneof_type.payload.single_int64 == 31)"), + + " + @index1 + msg.single_int64 + @index0.oneof_type.payload.single_int64 == 31)", + "cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, @index1.oneof_type," + + " @index3.payload, @index4.single_int64, msg.single_int64, @index1.single_int32," + + " @index2 + @index7, @index8 + @index2, @index9 + @index6, @index10 + @index5]," + + " @index11 == 31)"), SELECT_NESTED_MESSAGE_MAP_INDEX_1( "msg.oneof_type.payload.map_int32_int64[1] + " + "msg.oneof_type.payload.map_int32_int64[1] + " + "msg.oneof_type.payload.map_int32_int64[1] == 15", "cel.bind(@r0, msg.oneof_type.payload.map_int32_int64[1], @r0 + @r0 + @r0) == 15", "cel.@block([msg.oneof_type.payload.map_int32_int64[1]], @index0 + @index0 + @index0 ==" - + " 15)"), + + " 15)", + "cel.@block([msg.oneof_type, @index0.payload, @index1.map_int32_int64, @index2[1], @index3" + + " + @index3, @index4 + @index3], @index5 == 15)"), SELECT_NESTED_MESSAGE_MAP_INDEX_2( "msg.oneof_type.payload.map_int32_int64[0] + " + "msg.oneof_type.payload.map_int32_int64[1] + " + "msg.oneof_type.payload.map_int32_int64[2] == 8", "cel.bind(@r0, msg.oneof_type.payload.map_int32_int64, @r0[0] + @r0[1] + @r0[2]) == 8", "cel.@block([msg.oneof_type.payload.map_int32_int64], @index0[0] + @index0[1] + @index0[2]" - + " == 8)"), + + " == 8)", + "cel.@block([msg.oneof_type, @index0.payload, @index1.map_int32_int64, @index2[2]," + + " @index2[1], @index2[0], @index5 + @index4, @index6 + @index3], @index7 == 8)"), TERNARY( "(msg.single_int64 > 0 ? msg.single_int64 : 0) == 3", "cel.bind(@r0, msg.single_int64, (@r0 > 0) ? @r0 : 0) == 3", - "cel.@block([msg.single_int64], ((@index0 > 0) ? @index0 : 0) == 3)"), + "cel.@block([msg.single_int64], ((@index0 > 0) ? @index0 : 0) == 3)", + "cel.@block([msg.single_int64, @index0 > 0, @index1 ? @index0 : 0], @index2 == 3)"), TERNARY_BIND_RHS_ONLY( "false ? false : (msg.single_int64) + ((msg.single_int64 + 1) * 2) == 11", "false ? false : (cel.bind(@r0, msg.single_int64, @r0 + (@r0 + 1) * 2) == 11)", - "cel.@block([msg.single_int64], false ? false : (@index0 + (@index0 + 1) * 2 == 11))"), + "cel.@block([msg.single_int64], false ? false : (@index0 + (@index0 + 1) * 2 == 11))", + "cel.@block([msg.single_int64, @index0 + 1, @index1 * 2, @index0 + @index2, @index3 == 11]," + + " false ? false : @index4)"), NESTED_TERNARY( "(msg.single_int64 > 0 ? (msg.single_int32 > 0 ? " + "msg.single_int64 + msg.single_int32 : 0) : 0) == 8", "cel.bind(@r0, msg.single_int64, (@r0 > 0) ? " + "cel.bind(@r1, msg.single_int32, (@r1 > 0) ? (@r0 + @r1) : 0) : 0) == 8", "cel.@block([msg.single_int64, msg.single_int32], ((@index0 > 0) ? ((@index1 > 0) ?" - + " (@index0 + @index1) : 0) : 0) == 8)"), - MULTIPLE_MACROS( + + " (@index0 + @index1) : 0) : 0) == 8)", + "cel.@block([msg.single_int64, msg.single_int32, @index0 + @index1, @index1 > 0, @index3 ?" + + " @index2 : 0, @index0 > 0, @index5 ? @index4 : 0], @index6 == 8)"), + MULTIPLE_MACROS_1( // Note that all of these have different iteration variables, but they are still logically // the same. "size([[1].exists(i, i > 0)]) + size([[1].exists(j, j > 0)]) + " @@ -483,66 +519,105 @@ private enum CseTestCase { "cel.bind(@r1, size([[2].exists(@c0:0, @c0:0 > 1)]), " + "cel.bind(@r0, size([[1].exists(@c0:0, @c0:0 > 0)]), @r0 + @r0) + @r1 + @r1) == 4", "cel.@block([size([[1].exists(@c0:0, @c0:0 > 0)]), size([[2].exists(@c0:0, @c0:0 > 1)])]," - + " @index0 + @index0 + @index1 + @index1 == 4)"), + + " @index0 + @index0 + @index1 + @index1 == 4)", + "cel.@block([[1], @c0:0 > 0, @x0:0 || @index1, [2], @c0:0 > 1, @x0:0 || @index4]," + + " size([@index0.exists(@c0:0, @index1)]) + size([@index0.exists(@c0:0, @index1)]) +" + + " size([@index3.exists(@c0:0, @index4)]) + size([@index3.exists(@c0:0, @index4)]) ==" + + " 4)"), MULTIPLE_MACROS_2( "[[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == 'a')] +" + " [['a'].exists(l, l == 'a')] == [true, true, true, true]", "cel.bind(@r1, [[\"a\"].exists(@c0:1, @c0:1 == \"a\")], cel.bind(@r0, [[1].exists(@c0:0," + " @c0:0 > 0)], @r0 + @r0) + @r1 + @r1) == [true, true, true, true]", "cel.@block([[[1].exists(@c0:0, @c0:0 > 0)], [[\"a\"].exists(@c0:1, @c0:1 == \"a\")]]," - + " @index0 + @index0 + @index1 + @index1 == [true, true, true, true])"), + + " @index0 + @index0 + @index1 + @index1 == [true, true, true, true])", + "cel.@block([[1], @c0:0 > 0, @x0:0 || @index1, [\"a\"], @c0:1 == \"a\", @x0:1 || @index4," + + " [true, true, true, true]], [@index0.exists(@c0:0, @index1)] +" + + " [@index0.exists(@c0:0, @index1)] + [@index3.exists(@c0:1, @index4)] +" + + " [@index3.exists(@c0:1, @index4)] == @index6)"), NESTED_MACROS( "[1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [[2, 3, 4], [2, 3, 4], [2, 3, 4]]", "cel.bind(@r0, [1, 2, 3], @r0.map(@c0:0, @r0.map(@c1:0, @c1:0 + 1))) == " + "cel.bind(@r1, [2, 3, 4], [@r1, @r1, @r1])", "cel.@block([[1, 2, 3], [2, 3, 4]], @index0.map(@c0:0, @index0.map(@c1:0, @c1:0 + 1)) ==" - + " [@index1, @index1, @index1])"), + + " [@index1, @index1, @index1])", + "cel.@block([[1, 2, 3], [2, 3, 4], [@index1, @index1, @index1], @c1:0 + 1, [@index3], @x1:0" + + " + @index4], @index0.map(@c0:0, @index0.map(@c1:0, @index3)) == @index2)"), + NESTED_MACROS_2( + "[1, 2].map(y, [1, 2, 3].filter(x, x == y)) == [[1], [2]]", + "[1, 2].map(@c0:0, [1, 2, 3].filter(@c1:0, @c1:0 == @c0:0)) == [[1], [2]]", + "[1, 2].map(@c0:0, [1, 2, 3].filter(@c1:0, @c1:0 == @c0:0)) == [[1], [2]]", + "cel.@block([[2], [1], [@index1, @index0], [@c1:0], @x1:0 + @index3, @c1:0 == @c0:0," + + " @index5 ? @index4 : @x1:0, [1, 2, 3], [1, 2]], @index8.map(@c0:0," + + " @index7.filter(@c1:0, @index5)) == @index2)"), INCLUSION_LIST( "1 in [1,2,3] && 2 in [1,2,3] && 3 in [3, [1,2,3]] && 1 in [1,2,3]", "cel.bind(@r0, [1, 2, 3], cel.bind(@r1, 1 in @r0, @r1 && 2 in @r0 && 3 in [3, @r0] &&" + " @r1))", "cel.@block([[1, 2, 3], 1 in @index0], @index1 && 2 in @index0 && 3 in [3, @index0] &&" - + " @index1)"), + + " @index1)", + "cel.@block([[1, 2, 3], 1 in @index0, [3, @index0], 3 in @index2, @index3 && @index1, 2 in" + + " @index0, @index1 && @index5], @index6 && @index4)"), INCLUSION_MAP( "2 in {'a': 1, 2: {true: false}, 3: {true: false}}", "2 in cel.bind(@r0, {true: false}, {\"a\": 1, 2: @r0, 3: @r0})", - "cel.@block([{true: false}], 2 in {\"a\": 1, 2: @index0, 3: @index0})"), + "cel.@block([{true: false}], 2 in {\"a\": 1, 2: @index0, 3: @index0})", + "cel.@block([{true: false}, {\"a\": 1, 2: @index0, 3: @index0}], 2 in @index1)"), + MACRO_ITER_VAR_NOT_REFERENCED( + "[1,2].map(i, [1, 2].map(i, [3,4])) == [[[3, 4], [3, 4]], [[3, 4], [3, 4]]]", + "cel.bind(@r1, [3, 4], cel.bind(@r0, [1, 2], @r0.map(@c0:0, @r0.map(@c1:0, @r1))) ==" + + " cel.bind(@r2, [@r1, @r1], [@r2, @r2]))", + "cel.@block([[1, 2], [3, 4], [@index1, @index1]], @index0.map(@c0:0, @index0.map(@c1:0," + + " @index1)) == [@index2, @index2])", + "cel.@block([[1, 2], [3, 4], [@index1, @index1], [@index2, @index2], [@index1], @x1:0 +" + + " @index4], @index0.map(@c0:0, @index0.map(@c1:0, @index1)) == @index3)"), MACRO_SHADOWED_VARIABLE( "[x - 1 > 3 ? x - 1 : 5].exists(x, x - 1 > 3) || x - 1 > 3", "cel.bind(@r0, x - 1, cel.bind(@r1, @r0 > 3, [@r1 ? @r0 : 5].exists(@c0:0, @c0:0 - 1 > 3)" + " || @r1))", "cel.@block([x - 1, @index0 > 3], [@index1 ? @index0 : 5].exists(@c0:0, @c0:0 - 1 > 3) ||" - + " @index1)"), + + " @index1)", + "cel.@block([x - 1, @index0 > 3, @c0:0 - 1, @index2 > 3, @x0:0 || @index3, @index1 ?" + + " @index0 : 5, [@index5]], @index6.exists(@c0:0, @index3) || @index1)"), MACRO_SHADOWED_VARIABLE_2( "size([\"foo\", \"bar\"].map(x, [x + x, x + x]).map(x, [x + x, x + x])) == 2", "size([\"foo\", \"bar\"].map(@c1:0, cel.bind(@r0, @c1:0 + @c1:0, [@r0, @r0]))" + ".map(@c0:0, cel.bind(@r1, @c0:0 + @c0:0, [@r1, @r1]))) == 2", - "cel.@block([@c1:0 + @c1:0, @c0:0 + @c0:0], " - + "size([\"foo\", \"bar\"].map(@c1:0, [@index0, @index0])" - + ".map(@c0:0, [@index1, @index1])) == 2)"), + "cel.@block([@c1:0 + @c1:0, @c0:0 + @c0:0], size([\"foo\", \"bar\"].map(@c1:0, [@index0," + + " @index0]).map(@c0:0, [@index1, @index1])) == 2)", + "cel.@block([@c1:0 + @c1:0, @c0:0 + @c0:0, [@index1, @index1], [@index2], @x0:0 + @index3," + + " [@index0, @index0], [@index5], @x1:0 + @index6, [\"foo\", \"bar\"]]," + + " size(@index8.map(@c1:0, @index5).map(@c0:0, @index2)) == 2)"), PRESENCE_TEST( "has({'a': true}.a) && {'a':true}['a']", "cel.bind(@r0, {\"a\": true}, has(@r0.a) && @r0[\"a\"])", - "cel.@block([{\"a\": true}], has(@index0.a) && @index0[\"a\"])"), + "cel.@block([{\"a\": true}], has(@index0.a) && @index0[\"a\"])", + "cel.@block([{\"a\": true}, @index0[\"a\"]], has(@index0.a) && @index1)"), PRESENCE_TEST_WITH_TERNARY( "(has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : 0) == 10", "cel.bind(@r0, msg.oneof_type, has(@r0.payload) ? @r0.payload.single_int64 : 0) == 10", "cel.@block([msg.oneof_type], (has(@index0.payload) ? @index0.payload.single_int64 : 0) ==" - + " 10)"), + + " 10)", + "cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64], (has(@index0.payload)" + + " ? @index2 : 0) == 10)"), PRESENCE_TEST_WITH_TERNARY_2( "(has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 :" + " msg.oneof_type.payload.single_int64 * 0) == 10", "cel.bind(@r0, msg.oneof_type, cel.bind(@r1, @r0.payload.single_int64, has(@r0.payload) ?" + " @r1 : (@r1 * 0))) == 10", "cel.@block([msg.oneof_type, @index0.payload.single_int64], (has(@index0.payload) ? @index1" - + " : (@index1 * 0)) == 10)"), + + " : (@index1 * 0)) == 10)", + "cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, @index2 * 0]," + + " (has(@index0.payload) ? @index2 : @index3) == 10)"), PRESENCE_TEST_WITH_TERNARY_3( "(has(msg.oneof_type.payload.single_int64) ? msg.oneof_type.payload.single_int64 :" + " msg.oneof_type.payload.single_int64 * 0) == 10", "cel.bind(@r0, msg.oneof_type.payload, cel.bind(@r1, @r0.single_int64," + " has(@r0.single_int64) ? @r1 : (@r1 * 0))) == 10", "cel.@block([msg.oneof_type.payload, @index0.single_int64], (has(@index0.single_int64) ?" - + " @index1 : (@index1 * 0)) == 10)"), + + " @index1 : (@index1 * 0)) == 10)", + "cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, @index2 * 0]," + + " (has(@index1.single_int64) ? @index2 : @index3) == 10)"), /** * Input: * @@ -610,21 +685,41 @@ private enum CseTestCase { "cel.@block([msg.oneof_type, @index0.payload, @index1.map_string_string]," + " (has(msg.oneof_type) && has(@index0.payload) && has(@index1.single_int64)) ?" + " ((has(@index1.map_string_string) && has(@index2.key)) ? (@index2.key == \"A\") :" - + " false) : false)"), + + " false) : false)", + "cel.@block([msg.oneof_type, @index0.payload, @index1.map_string_string, @index2.key," + + " @index3 == \"A\"], (has(msg.oneof_type) && has(@index0.payload) &&" + + " has(@index1.single_int64)) ? ((has(@index1.map_string_string) && has(@index2.key))" + + " ? @index4 : false) : false)"), OPTIONAL_LIST( "[10, ?optional.none(), [?optional.none(), ?opt_x], [?optional.none(), ?opt_x]] == [10," + " [5], [5]]", - "cel.bind(@r0, [?optional.none(), ?opt_x], [10, ?optional.none(), @r0, @r0]) ==" - + " cel.bind(@r1, [5], [10, @r1, @r1])", - "cel.@block([[?optional.none(), ?opt_x], [5]], [10, ?optional.none(), @index0, @index0] ==" - + " [10, @index1, @index1])"), + "cel.bind(@r0, optional.none(), cel.bind(@r1, [?@r0, ?opt_x], [10, ?@r0, @r1, @r1])) ==" + + " cel.bind(@r2, [5], [10, @r2, @r2])", + "cel.@block([optional.none(), [?@index0, ?opt_x], [5]], [10, ?@index0, @index1, @index1] ==" + + " [10, @index2, @index2])", + "cel.@block([optional.none(), [?@index0, ?opt_x], [5], [10, @index2, @index2], [10," + + " ?@index0, @index1, @index1]], @index4 == @index3)"), OPTIONAL_MAP( "{?'hello': optional.of('hello')}['hello'] + {?'hello': optional.of('hello')}['hello'] ==" + " 'hellohello'", "cel.bind(@r0, {?\"hello\": optional.of(\"hello\")}[\"hello\"], @r0 + @r0) ==" + " \"hellohello\"", "cel.@block([{?\"hello\": optional.of(\"hello\")}[\"hello\"]], @index0 + @index0 ==" - + " \"hellohello\")"), + + " \"hellohello\")", + "cel.@block([optional.of(\"hello\"), {?\"hello\": @index0}, @index1[\"hello\"], @index2 +" + + " @index2], @index3 == \"hellohello\")"), + OPTIONAL_MAP_CHAINED( + "{?'key': optional.of('test')}[?'bogus'].or({'key': 'test'}[?'bogus']).orValue({'key':" + + " 'test'}['key']) == 'test'", + "cel.bind(@r0, {\"key\": \"test\"}, {?\"key\":" + + " optional.of(\"test\")}[?\"bogus\"].or(@r0[?\"bogus\"]).orValue(@r0[\"key\"])) ==" + + " \"test\"", + "cel.@block([{\"key\": \"test\"}], {?\"key\":" + + " optional.of(\"test\")}[?\"bogus\"].or(@index0[?\"bogus\"]).orValue(@index0[\"key\"])" + + " == \"test\")", + "cel.@block([{\"key\": \"test\"}, @index0[\"key\"], @index0[?\"bogus\"], {?\"key\":" + + " optional.of(\"test\")}, @index3[?\"bogus\"], @index4.or(@index2)," + + " @index5.orValue(@index1)], @index6 == \"test\")"), OPTIONAL_MESSAGE( "TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32:" + " optional.of(4)}.single_int32 + TestAllTypes{?single_int64:" @@ -633,17 +728,23 @@ private enum CseTestCase { + "?single_int64: optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}, " + "@r0.single_int32 + @r0.single_int64) == 5", "cel.@block([TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32:" - + " optional.of(4)}], @index0.single_int32 + @index0.single_int64 == 5)"), + + " optional.of(4)}], @index0.single_int32 + @index0.single_int64 == 5)", + "cel.@block([optional.ofNonZeroValue(1), optional.of(4), TestAllTypes{?single_int64:" + + " @index0, ?single_int32: @index1}, @index2.single_int64, @index2.single_int32," + + " @index4 + @index3], @index5 == 5)"), ; private final String source; private final String unparsedBind; private final String unparsedBlock; + private final String unparsedBlockFlattened; - CseTestCase(String source, String unparsedBind, String unparsedBlock) { + CseTestCase( + String source, String unparsedBind, String unparsedBlock, String unparsedBlockFlattened) { this.source = source; this.unparsedBind = unparsedBind; this.unparsedBlock = unparsedBlock; + this.unparsedBlockFlattened = unparsedBlockFlattened; } } @@ -737,30 +838,283 @@ public void cse_withCelBlock_macroMapUnpopulated(@TestParameter CseTestCase test } @Test - public void celBlock_nestedComprehension_iterVarReferencedAcrossComprehensions() + public void cse_withCelBlockFlattened_macroMapPopulated(@TestParameter CseTestCase testCase) throws Exception { - String nestedComprehension = - "[\"foo\"].map(x, [[\"bar\"], [x + x, x + x]] + [\"bar\"].map(y, [x + y, [\"baz\"].map(z," - + " [x + y + z, x + y, x + y + z])])) == [[[\"bar\"], [\"foofoo\", \"foofoo\"]," - + " [\"foobar\", [[\"foobarbaz\", \"foobar\", \"foobarbaz\"]]]]]"; CelOptimizer celOptimizer = newCseOptimizer( SubexpressionOptimizerOptions.newBuilder() .populateMacroCalls(true) .enableCelBlock(true) + .subexpressionMaxRecursionDepth(1) .build()); - CelAbstractSyntaxTree ast = CEL.compile(nestedComprehension).getAst(); + CelAbstractSyntaxTree ast = CEL.compile(testCase.source).getAst(); + + CelAbstractSyntaxTree optimizedAst = celOptimizer.optimize(ast); + + assertThat( + CEL.createProgram(optimizedAst) + .eval( + ImmutableMap.of( + "msg", TEST_ALL_TYPES_INPUT, "x", 5L, "opt_x", Optional.of(5L)))) + .isEqualTo(true); + assertThat(CEL_UNPARSER.unparse(optimizedAst)).isEqualTo(testCase.unparsedBlockFlattened); + } + + @Test + public void cse_withVariousRecursionDepths_macroMapUnpopulated( + @TestParameter CseTestCase testCase, + @TestParameter({"1", "2", "3", "4", "5", "6", "7", "8", "9", "10"}) Integer maxRecursionDepth) + throws Exception { + CelOptimizer celOptimizer = + newCseOptimizer( + SubexpressionOptimizerOptions.newBuilder() + .populateMacroCalls(false) + .enableCelBlock(true) + .subexpressionMaxRecursionDepth(maxRecursionDepth) + .build()); + CelAbstractSyntaxTree ast = CEL.compile(testCase.source).getAst(); + + CelAbstractSyntaxTree optimizedAst = celOptimizer.optimize(ast); + + assertThat(optimizedAst.getSource().getMacroCalls()).isEmpty(); + assertThat( + CEL.createProgram(optimizedAst) + .eval( + ImmutableMap.of( + "msg", TEST_ALL_TYPES_INPUT, "x", 5L, "opt_x", Optional.of(5L)))) + .isEqualTo(true); + } + + @Test + @TestParameters( + "{recursionDepth: 0, unparsed: 'true ||" + + " msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload.single_int64" + + " == 1'}") + @TestParameters( + "{recursionDepth: 1, unparsed: 'cel.@block([msg.oneof_type, @index0.payload," + + " @index1.oneof_type, @index2.payload, @index3.oneof_type, @index4.payload," + + " @index5.oneof_type, @index6.payload, @index7.single_int64, @index8 == 1], true ||" + + " @index9)'}") + @TestParameters( + "{recursionDepth: 2, unparsed: 'cel.@block([msg.oneof_type.payload," + + " @index0.oneof_type.payload, @index1.oneof_type.payload, @index2.oneof_type.payload," + + " @index3.single_int64 == 1], true || @index4)'}") + @TestParameters( + "{recursionDepth: 3, unparsed: 'cel.@block([msg.oneof_type.payload.oneof_type," + + " @index0.payload.oneof_type.payload, @index1.oneof_type.payload.single_int64, @index2" + + " == 1], true || @index3)'}") + @TestParameters( + "{recursionDepth: 4, unparsed: 'cel.@block([msg.oneof_type.payload.oneof_type.payload," + + " @index0.oneof_type.payload.oneof_type.payload, @index1.single_int64 == 1], true ||" + + " @index2)'}") + @TestParameters( + "{recursionDepth: 5, unparsed:" + + " 'cel.@block([msg.oneof_type.payload.oneof_type.payload.oneof_type," + + " @index0.payload.oneof_type.payload.single_int64 == 1], true || @index1)'}") + @TestParameters( + "{recursionDepth: 6, unparsed:" + + " 'cel.@block([msg.oneof_type.payload.oneof_type.payload.oneof_type.payload," + + " @index0.oneof_type.payload.single_int64 == 1], true || @index1)'}") + @TestParameters( + "{recursionDepth: 7, unparsed:" + + " 'cel.@block([msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type," + + " @index0.payload.single_int64 == 1], true || @index1)'}") + @TestParameters( + "{recursionDepth: 8, unparsed:" + + " 'cel.@block([msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload," + + " @index0.single_int64 == 1], true || @index1)'}") + @TestParameters( + "{recursionDepth: 9, unparsed:" + + " 'cel.@block([msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload.single_int64," + + " @index0 == 1], true || @index1)'}") + @TestParameters( + "{recursionDepth: 10, unparsed:" + + " 'cel.@block([msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload.single_int64" + + " == 1], true || @index0)'}") + public void noCommonSubexpr_withRecursionDepth_deeplyNestedSelect( + int recursionDepth, String unparsed) throws Exception { + String expression = + "true ||" + + " msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload.single_int64" + + " == 1"; + CelOptimizer celOptimizer = + newCseOptimizer( + SubexpressionOptimizerOptions.newBuilder() + .populateMacroCalls(true) + .enableCelBlock(true) + .subexpressionMaxRecursionDepth(recursionDepth) + .build()); + CelAbstractSyntaxTree ast = CEL.compile(expression).getAst(); CelAbstractSyntaxTree optimizedAst = celOptimizer.optimize(ast); assertThat(CEL.createProgram(optimizedAst).eval()).isEqualTo(true); - assertThat(CEL_UNPARSER.unparse(optimizedAst)) - .isEqualTo( - "cel.@block([@c0:0 + @c0:0, [\"bar\"], @c0:0 + @c1:0, @index2 + @c2:0]," - + " [\"foo\"].map(@c0:0, [@index1, [@index0, @index0]] + @index1.map(@c1:0," - + " [@index2, [\"baz\"].map(@c2:0, [@index3, @index2, @index3])])) == [[@index1," - + " [\"foofoo\", \"foofoo\"], [\"foobar\", [[\"foobarbaz\", \"foobar\"," - + " \"foobarbaz\"]]]]])"); + assertThat(CEL_UNPARSER.unparse(optimizedAst)).isEqualTo(unparsed); + } + + @Test + @TestParameters( + "{recursionDepth: 1, unparsed: 'cel.@block([msg.oneof_type, @index0.payload," + + " @index1.oneof_type, @index2.payload, @index3.oneof_type, @index4.child," + + " @index5.child, @index6.payload, @index7.single_bool, @index4.payload," + + " @index9.oneof_type, @index10.payload, @index11.single_bool, true || @index12]," + + " @index13 || @index8)'}") + @TestParameters( + "{recursionDepth: 2, unparsed: 'cel.@block([msg.oneof_type, @index0.payload," + + " @index1.oneof_type, @index2.payload, @index3.oneof_type, @index4.child.child," + + " @index5.payload.single_bool, @index4.payload.oneof_type, @index7.payload.single_bool," + + " true || @index8], @index9 || @index6)'}") + @TestParameters( + "{recursionDepth: 3, unparsed: 'cel.@block([msg.oneof_type, @index0.payload," + + " @index1.oneof_type, @index2.payload, @index3.oneof_type, @index4.child.child.payload," + + " @index5.single_bool, @index4.payload.oneof_type.payload, true ||" + + " @index7.single_bool], @index8 || @index6)'}") + @TestParameters( + "{recursionDepth: 4, unparsed: 'cel.@block([msg.oneof_type, @index0.payload," + + " @index1.oneof_type, @index2.payload, @index3.oneof_type," + + " @index4.child.child.payload.single_bool," + + " @index4.payload.oneof_type.payload.single_bool, true || @index6], @index7 ||" + + " @index5)'}") + public void cse_withRecursionDepth_deeplyNestedSelect(int recursionDepth, String unparsed) + throws Exception { + String expression = + "true ||" + + " msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload.single_bool" + + " || msg.oneof_type.payload.oneof_type.payload.oneof_type.child.child.payload.single_bool"; + CelOptimizer celOptimizer = + newCseOptimizer( + SubexpressionOptimizerOptions.newBuilder() + .populateMacroCalls(true) + .enableCelBlock(true) + .subexpressionMaxRecursionDepth(recursionDepth) + .build()); + CelAbstractSyntaxTree ast = CEL.compile(expression).getAst(); + + CelAbstractSyntaxTree optimizedAst = celOptimizer.optimize(ast); + + assertThat(CEL.createProgram(optimizedAst).eval()).isEqualTo(true); + assertThat(CEL_UNPARSER.unparse(optimizedAst)).isEqualTo(unparsed); + } + + @Test + @TestParameters( + "{recursionDepth: 0, unparsed: '\"hello world\".matches(\"h\" + \"e\" + \"l\" + \"l\" +" + + " \"o\") == true'}") + @TestParameters( + "{recursionDepth: 1, unparsed: 'cel.@block([\"h\" + \"e\", @index0 + \"l\", @index1 + \"l\"," + + " @index2 + \"o\", \"hello world\".matches(@index3)], @index4 == true)'}") + @TestParameters( + "{recursionDepth: 2, unparsed: 'cel.@block([\"h\" + \"e\" + \"l\", @index0 + \"l\" + \"o\"," + + " \"hello world\".matches(@index1)], @index2 == true)'}") + @TestParameters( + "{recursionDepth: 3, unparsed: 'cel.@block([\"h\" + \"e\" + \"l\" + \"l\", \"hello" + + " world\".matches(@index0 + \"o\")], @index1 == true)'}") + @TestParameters( + "{recursionDepth: 4, unparsed: 'cel.@block([\"h\" + \"e\" + \"l\" + \"l\" + \"o\", \"hello" + + " world\".matches(@index0)], @index1 == true)'}") + @TestParameters( + "{recursionDepth: 5, unparsed: 'cel.@block([\"hello world\".matches(\"h\" + \"e\" + \"l\" +" + + " \"l\" + \"o\")], @index0 == true)'}") + public void noCommonSubexpr_withRecursionDepth_deeplyNestedCallOnArgs( + int recursionDepth, String unparsed) throws Exception { + String expression = "'hello world'.matches('h' + 'e' + 'l' + 'l' + 'o') == true"; + CelOptimizer celOptimizer = + newCseOptimizer( + SubexpressionOptimizerOptions.newBuilder() + .populateMacroCalls(true) + .enableCelBlock(true) + .subexpressionMaxRecursionDepth(recursionDepth) + .build()); + CelAbstractSyntaxTree ast = CEL.compile(expression).getAst(); + + CelAbstractSyntaxTree optimizedAst = celOptimizer.optimize(ast); + + assertThat(CEL.createProgram(optimizedAst).eval()).isEqualTo(true); + assertThat(CEL_UNPARSER.unparse(optimizedAst)).isEqualTo(unparsed); + } + + @Test + @TestParameters( + "{recursionDepth: 0, unparsed: '(\"h\" + \"e\" + \"l\" + \"l\" + \"o\" + \"" + + " world\").matches(\"hello\") == true'}") + @TestParameters( + "{recursionDepth: 1, unparsed: 'cel.@block([\"h\" + \"e\", @index0 + \"l\", @index1 + \"l\"," + + " @index2 + \"o\", @index3 + \" world\", @index4.matches(\"hello\")], @index5 ==" + + " true)'}") + @TestParameters( + "{recursionDepth: 2, unparsed: 'cel.@block([\"h\" + \"e\" + \"l\", @index0 + \"l\" + \"o\"," + + " (@index1 + \" world\").matches(\"hello\")], @index2 == true)'}") + @TestParameters( + "{recursionDepth: 3, unparsed: 'cel.@block([\"h\" + \"e\" + \"l\" + \"l\", (@index0 + \"o\" +" + + " \" world\").matches(\"hello\")], @index1 == true)'}") + @TestParameters( + "{recursionDepth: 4, unparsed: 'cel.@block([\"h\" + \"e\" + \"l\" + \"l\" + \"o\", (@index0 +" + + " \" world\").matches(\"hello\")], @index1 == true)'}") + @TestParameters( + "{recursionDepth: 5, unparsed: 'cel.@block([\"h\" + \"e\" + \"l\" + \"l\" + \"o\" + \"" + + " world\", @index0.matches(\"hello\")], @index1 == true)'}") + @TestParameters( + "{recursionDepth: 6, unparsed: 'cel.@block([(\"h\" + \"e\" + \"l\" + \"l\" + \"o\" + \"" + + " world\").matches(\"hello\")], @index0 == true)'}") + public void noCommonSubexpr_withRecursionDepth_deeplyNestedCallOnTarget( + int recursionDepth, String unparsed) throws Exception { + String expression = "('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('hello') == true"; + CelOptimizer celOptimizer = + newCseOptimizer( + SubexpressionOptimizerOptions.newBuilder() + .populateMacroCalls(true) + .enableCelBlock(true) + .subexpressionMaxRecursionDepth(recursionDepth) + .build()); + CelAbstractSyntaxTree ast = CEL.compile(expression).getAst(); + + CelAbstractSyntaxTree optimizedAst = celOptimizer.optimize(ast); + + assertThat(CEL.createProgram(optimizedAst).eval()).isEqualTo(true); + assertThat(CEL_UNPARSER.unparse(optimizedAst)).isEqualTo(unparsed); + } + + @Test + @TestParameters( + "{recursionDepth: 1, unparsed: 'cel.@block([\"w\" + \"o\", @index0 + \"r\", @index1 + \"l\"," + + " @index2 + \"d\", \"h\" + \"e\", @index4 + \"l\", @index5 + \"l\", @index6 + \"o\"," + + " @index7 + \" world\", @index8.matches(@index3)], @index9 == true)'}") + @TestParameters( + "{recursionDepth: 2, unparsed: 'cel.@block([\"w\" + \"o\" + \"r\", @index0 + \"l\" + \"d\"," + + " \"h\" + \"e\" + \"l\", @index2 + \"l\" + \"o\", (@index3 + \"" + + " world\").matches(@index1)], @index4 == true)'}") + @TestParameters( + "{recursionDepth: 3, unparsed: 'cel.@block([\"w\" + \"o\" + \"r\" + \"l\", @index0 + \"d\"," + + " \"h\" + \"e\" + \"l\" + \"l\", (@index2 + \"o\" + \" world\").matches(@index1)]," + + " @index3 == true)'}") + @TestParameters( + "{recursionDepth: 4, unparsed: 'cel.@block([\"w\" + \"o\" + \"r\" + \"l\" + \"d\", \"h\" +" + + " \"e\" + \"l\" + \"l\" + \"o\", (@index1 + \" world\").matches(@index0)], @index2 ==" + + " true)'}") + @TestParameters( + "{recursionDepth: 5, unparsed: 'cel.@block([\"w\" + \"o\" + \"r\" + \"l\" + \"d\", \"h\" +" + + " \"e\" + \"l\" + \"l\" + \"o\" + \" world\", @index1.matches(@index0)], @index2 ==" + + " true)'}") + @TestParameters( + "{recursionDepth: 6, unparsed: 'cel.@block([(\"h\" + \"e\" + \"l\" + \"l\" + \"o\" + \"" + + " world\").matches(\"w\" + \"o\" + \"r\" + \"l\" + \"d\")], @index0 == true)'}") + public void noCommonSubexpr_withRecursionDepth_deeplyNestedCallOnBothTargetAndArgs( + int recursionDepth, String unparsed) throws Exception { + String expression = + "('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('w' + 'o' + 'r' + 'l' + 'd') == true"; + CelOptimizer celOptimizer = + newCseOptimizer( + SubexpressionOptimizerOptions.newBuilder() + .populateMacroCalls(true) + .enableCelBlock(true) + .subexpressionMaxRecursionDepth(recursionDepth) + .build()); + CelAbstractSyntaxTree ast = CEL.compile(expression).getAst(); + + CelAbstractSyntaxTree optimizedAst = celOptimizer.optimize(ast); + + assertThat(CEL.createProgram(optimizedAst).eval()).isEqualTo(true); + assertThat(CEL_UNPARSER.unparse(optimizedAst)).isEqualTo(unparsed); } @Test @@ -781,25 +1135,35 @@ public void cse_resultTypeSet_celBlockOptimizationSuccess() throws Exception { .isEqualTo("cel.@block([size(\"a\")], @index0 + @index0 == 2)"); } + private enum CseNoOpTestCase { + // Nothing to optimize + NO_COMMON_SUBEXPR("size(\"hello\")"), + // Constants and identifiers + INT_CONST_ONLY("2 + 2 + 2 + 2"), + IDENT_ONLY("x + x + x + x"), + BOOL_CONST_ONLY("true == true && false == false"), + // Constants and identifiers within a function + CONST_WITHIN_FUNCTION("size(\"hello\" + \"hello\" + \"hello\")"), + IDENT_WITHIN_FUNCTION("string(x + x + x)"), + // Non-standard functions are considered non-pure for time being + NON_STANDARD_FUNCTION_1("custom_func(1) + custom_func(1)"), + NON_STANDARD_FUNCTION_2("1 + custom_func(1) + 1 + custom_func(1)"), + // Duplicated but nested calls. + NESTED_FUNCTION("int(timestamp(int(timestamp(1000000000))))"), + // This cannot be optimized. Extracting the common subexpression would presence test + // the bound identifier (e.g: has(@r0)), which is not valid. + UNOPTIMIZABLE_TERNARY("has(msg.single_any) ? msg.single_any : 10"); + + private final String source; + + CseNoOpTestCase(String source) { + this.source = source; + } + } + @Test - // Nothing to optimize - @TestParameters("{source: 'size(\"hello\")'}") - // Constants and identifiers - @TestParameters("{source: '2 + 2 + 2 + 2'}") - @TestParameters("{source: 'x + x + x + x'}") - @TestParameters("{source: 'true == true && false == false'}") - // Constants and identifiers within a function - @TestParameters("{source: 'size(\"hello\" + \"hello\" + \"hello\")'}") - @TestParameters("{source: 'string(x + x + x)'}") - // Non-standard functions are considered non-pure for time being - @TestParameters("{source: 'custom_func(1) + custom_func(1)'}") - // Duplicated but nested calls. - @TestParameters("{source: 'int(timestamp(int(timestamp(1000000000))))'}") - // This cannot be optimized. Extracting the common subexpression would presence test - // the bound identifier (e.g: has(@r0)), which is not valid. - @TestParameters("{source: 'has(msg.single_any) ? msg.single_any : 10'}") - public void cse_withCelBind_noop(String source) throws Exception { - CelAbstractSyntaxTree ast = CEL.compile(source).getAst(); + public void cse_withCelBind_noop(@TestParameter CseNoOpTestCase testCase) throws Exception { + CelAbstractSyntaxTree ast = CEL.compile(testCase.source).getAst(); CelAbstractSyntaxTree optimizedAst = newCseOptimizer( @@ -810,28 +1174,12 @@ public void cse_withCelBind_noop(String source) throws Exception { .optimize(ast); assertThat(ast.getExpr()).isEqualTo(optimizedAst.getExpr()); - assertThat(CEL_UNPARSER.unparse(optimizedAst)).isEqualTo(source); + assertThat(CEL_UNPARSER.unparse(optimizedAst)).isEqualTo(testCase.source); } @Test - // Nothing to optimize - @TestParameters("{source: 'size(\"hello\")'}") - // Constants and identifiers - @TestParameters("{source: '2 + 2 + 2 + 2'}") - @TestParameters("{source: 'x + x + x + x'}") - @TestParameters("{source: 'true == true && false == false'}") - // Constants and identifiers within a function - @TestParameters("{source: 'size(\"hello\" + \"hello\" + \"hello\")'}") - @TestParameters("{source: 'string(x + x + x)'}") - // Non-standard functions are considered non-pure for time being - @TestParameters("{source: 'custom_func(1) + custom_func(1)'}") - // Duplicated but nested calls. - @TestParameters("{source: 'int(timestamp(int(timestamp(1000000000))))'}") - // This cannot be optimized. Extracting the common subexpression would presence test - // the bound identifier (e.g: has(@r0)), which is not valid. - @TestParameters("{source: 'has(msg.single_any) ? msg.single_any : 10'}") - public void cse_withCelBlock_noop(String source) throws Exception { - CelAbstractSyntaxTree ast = CEL.compile(source).getAst(); + public void cse_withCelBlock_noop(@TestParameter CseNoOpTestCase testCase) throws Exception { + CelAbstractSyntaxTree ast = CEL.compile(testCase.source).getAst(); CelAbstractSyntaxTree optimizedAst = newCseOptimizer( @@ -842,7 +1190,7 @@ public void cse_withCelBlock_noop(String source) throws Exception { .optimize(ast); assertThat(ast.getExpr()).isEqualTo(optimizedAst.getExpr()); - assertThat(CEL_UNPARSER.unparse(optimizedAst)).isEqualTo(source); + assertThat(CEL_UNPARSER.unparse(optimizedAst)).isEqualTo(testCase.source); } @Test @@ -1024,9 +1372,10 @@ public void cse_withCelBind_largeNestedMacro() throws Exception { assertThat(CEL_UNPARSER.unparse(optimizedAst)) .isEqualTo( - "cel.bind(@r0, [1, 2, 3], cel.bind(@r1, size(@r0.map(i, @r0.map(i, @r0.map(i," - + " @r0.map(i, @r0.map(i, @r0.map(i, @r0.map(i, @r0.map(i, @r0))))))))), @r1 + @r1" - + " + @r1 + @r1 + @r1 + @r1 + @r1 + @r1 + @r1))"); + "cel.bind(@r0, [1, 2, 3], cel.bind(@r1, size(@r0.map(@c0:0, @r0.map(@c1:0," + + " @r0.map(@c2:0, @r0.map(@c3:0, @r0.map(@c4:0, @r0.map(@c5:0, @r0.map(@c6:0," + + " @r0.map(@c7:0, @r0))))))))), @r1 + @r1 + @r1 + @r1 + @r1 + @r1 + @r1 + @r1 +" + + " @r1))"); assertThat(CEL.createProgram(optimizedAst).eval()).isEqualTo(27); } @@ -1060,10 +1409,10 @@ public void cse_withCelBlock_largeNestedMacro() throws Exception { assertThat(CEL_UNPARSER.unparse(optimizedAst)) .isEqualTo( - "cel.@block([[1, 2, 3], size(@index0.map(i, @index0.map(i, @index0.map(i," - + " @index0.map(i, @index0.map(i, @index0.map(i, @index0.map(i, @index0.map(i," - + " @index0)))))))))], @index1 + @index1 + @index1 + @index1 + @index1 + @index1 +" - + " @index1 + @index1 + @index1)"); + "cel.@block([[1, 2, 3], size(@index0.map(@c0:0, @index0.map(@c1:0, @index0.map(@c2:0," + + " @index0.map(@c3:0, @index0.map(@c4:0, @index0.map(@c5:0, @index0.map(@c6:0," + + " @index0.map(@c7:0, @index0)))))))))], @index1 + @index1 + @index1 + @index1 +" + + " @index1 + @index1 + @index1 + @index1 + @index1)"); assertThat(CEL.createProgram(optimizedAst).eval()).isEqualTo(27); } From 4f8f4551a14fdea074c7c14077c1c3dd89b3d145 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Thu, 22 Feb 2024 10:20:58 -0800 Subject: [PATCH 038/486] Compute navigable expr heights in a separate pass PiperOrigin-RevId: 609416184 --- .../dev/cel/common/navigation/BUILD.bazel | 1 + .../common/navigation/CelNavigableExpr.java | 27 +--- .../navigation/CelNavigableExprVisitor.java | 114 +++++++-------- .../navigation/ExprHeightCalculator.java | 132 ++++++++++++++++++ .../CelNavigableExprVisitorTest.java | 33 +++-- .../SubexpressionOptimizerTest.java | 6 +- 6 files changed, 211 insertions(+), 102 deletions(-) create mode 100644 common/src/main/java/dev/cel/common/navigation/ExprHeightCalculator.java diff --git a/common/src/main/java/dev/cel/common/navigation/BUILD.bazel b/common/src/main/java/dev/cel/common/navigation/BUILD.bazel index 07604c5f7..5a3281e75 100644 --- a/common/src/main/java/dev/cel/common/navigation/BUILD.bazel +++ b/common/src/main/java/dev/cel/common/navigation/BUILD.bazel @@ -13,6 +13,7 @@ java_library( "CelNavigableAst.java", "CelNavigableExpr.java", "CelNavigableExprVisitor.java", + "ExprHeightCalculator.java", ], tags = [ ], diff --git a/common/src/main/java/dev/cel/common/navigation/CelNavigableExpr.java b/common/src/main/java/dev/cel/common/navigation/CelNavigableExpr.java index 249a31262..d0cd2ba74 100644 --- a/common/src/main/java/dev/cel/common/navigation/CelNavigableExpr.java +++ b/common/src/main/java/dev/cel/common/navigation/CelNavigableExpr.java @@ -15,8 +15,6 @@ package dev.cel.common.navigation; import com.google.auto.value.AutoValue; -import com.google.errorprone.annotations.CanIgnoreReturnValue; -import com.google.errorprone.annotations.CheckReturnValue; import dev.cel.common.ast.CelExpr; import dev.cel.common.ast.CelExpr.CelComprehension; import dev.cel.common.ast.CelExpr.ExprKind; @@ -69,7 +67,12 @@ public long id() { /** Constructs a new instance of {@link CelNavigableExpr} from {@link CelExpr}. */ public static CelNavigableExpr fromExpr(CelExpr expr) { - return CelNavigableExpr.builder().setExpr(expr).build(); + ExprHeightCalculator exprHeightCalculator = new ExprHeightCalculator(expr); + + return CelNavigableExpr.builder() + .setExpr(expr) + .setHeight(exprHeightCalculator.getHeight(expr.id())) + .build(); } /** @@ -136,8 +139,6 @@ public static Builder builder() { @AutoValue.Builder public abstract static class Builder { - private Builder parentBuilder; - public abstract CelExpr expr(); public abstract int depth(); @@ -150,25 +151,11 @@ public ExprKind.Kind getKind() { abstract Builder setParent(CelNavigableExpr value); - @CanIgnoreReturnValue - public Builder setParentBuilder(CelNavigableExpr.Builder value) { - parentBuilder = value; - return this; - } - public abstract Builder setDepth(int value); public abstract Builder setHeight(int value); - public abstract CelNavigableExpr autoBuild(); - - @CheckReturnValue - public CelNavigableExpr build() { - if (parentBuilder != null) { - setParent(parentBuilder.build()); - } - return autoBuild(); - } + public abstract CelNavigableExpr build(); } public abstract Builder toBuilder(); diff --git a/common/src/main/java/dev/cel/common/navigation/CelNavigableExprVisitor.java b/common/src/main/java/dev/cel/common/navigation/CelNavigableExprVisitor.java index cc49ffcec..afafd89c2 100644 --- a/common/src/main/java/dev/cel/common/navigation/CelNavigableExprVisitor.java +++ b/common/src/main/java/dev/cel/common/navigation/CelNavigableExprVisitor.java @@ -14,8 +14,6 @@ package dev.cel.common.navigation; -import static java.lang.Math.max; - import com.google.common.collect.ImmutableList; import dev.cel.common.ast.CelExpr; import dev.cel.common.ast.CelExpr.CelCall; @@ -31,12 +29,15 @@ final class CelNavigableExprVisitor { private static final int MAX_DESCENDANTS_RECURSION_DEPTH = 500; - private final Stream.Builder streamBuilder; + private final Stream.Builder streamBuilder; + private final ExprHeightCalculator exprHeightCalculator; private final TraversalOrder traversalOrder; private final int maxDepth; - private CelNavigableExprVisitor(int maxDepth, TraversalOrder traversalOrder) { + private CelNavigableExprVisitor( + int maxDepth, ExprHeightCalculator exprHeightCalculator, TraversalOrder traversalOrder) { this.maxDepth = maxDepth; + this.exprHeightCalculator = exprHeightCalculator; this.traversalOrder = traversalOrder; this.streamBuilder = Stream.builder(); } @@ -84,14 +85,16 @@ static Stream collect( */ static Stream collect( CelNavigableExpr navigableExpr, int maxDepth, TraversalOrder traversalOrder) { - CelNavigableExprVisitor visitor = new CelNavigableExprVisitor(maxDepth, traversalOrder); + ExprHeightCalculator exprHeightCalculator = new ExprHeightCalculator(navigableExpr.expr()); + CelNavigableExprVisitor visitor = + new CelNavigableExprVisitor(maxDepth, exprHeightCalculator, traversalOrder); - visitor.visit(navigableExpr.toBuilder()); + visitor.visit(navigableExpr); - return visitor.streamBuilder.build().map(CelNavigableExpr.Builder::build); + return visitor.streamBuilder.build(); } - private int visit(CelNavigableExpr.Builder navigableExpr) { + private void visit(CelNavigableExpr navigableExpr) { if (navigableExpr.depth() > MAX_DESCENDANTS_RECURSION_DEPTH - 1) { throw new IllegalStateException("Max recursion depth reached."); } @@ -101,108 +104,89 @@ private int visit(CelNavigableExpr.Builder navigableExpr) { streamBuilder.add(navigableExpr); } - int height = 1; switch (navigableExpr.getKind()) { case CALL: - height += visit(navigableExpr, navigableExpr.expr().call()); + visit(navigableExpr, navigableExpr.expr().call()); break; case CREATE_LIST: - height += visit(navigableExpr, navigableExpr.expr().createList()); + visit(navigableExpr, navigableExpr.expr().createList()); break; case SELECT: - height += visit(navigableExpr, navigableExpr.expr().select()); + visit(navigableExpr, navigableExpr.expr().select()); break; case CREATE_STRUCT: - height += visitStruct(navigableExpr, navigableExpr.expr().createStruct()); + visitStruct(navigableExpr, navigableExpr.expr().createStruct()); break; case CREATE_MAP: - height += visitMap(navigableExpr, navigableExpr.expr().createMap()); + visitMap(navigableExpr, navigableExpr.expr().createMap()); break; case COMPREHENSION: - height += visit(navigableExpr, navigableExpr.expr().comprehension()); + visit(navigableExpr, navigableExpr.expr().comprehension()); break; default: - // This is a leaf node - height = 0; break; } - navigableExpr.setHeight(height); if (addToStream && traversalOrder.equals(TraversalOrder.POST_ORDER)) { streamBuilder.add(navigableExpr); } - - return height; } - private int visit(CelNavigableExpr.Builder navigableExpr, CelCall call) { - int targetHeight = 0; + private void visit(CelNavigableExpr navigableExpr, CelCall call) { if (call.target().isPresent()) { - CelNavigableExpr.Builder target = newNavigableChild(navigableExpr, call.target().get()); - targetHeight = visit(target); + visit(newNavigableChild(navigableExpr, call.target().get())); } - int argumentHeight = visitExprList(call.args(), navigableExpr); - return max(targetHeight, argumentHeight); + visitExprList(call.args(), navigableExpr); } - private int visit(CelNavigableExpr.Builder navigableExpr, CelCreateList createList) { - return visitExprList(createList.elements(), navigableExpr); + private void visit(CelNavigableExpr navigableExpr, CelCreateList createList) { + visitExprList(createList.elements(), navigableExpr); } - private int visit(CelNavigableExpr.Builder navigableExpr, CelSelect selectExpr) { - CelNavigableExpr.Builder operand = newNavigableChild(navigableExpr, selectExpr.operand()); - return visit(operand); + private void visit(CelNavigableExpr navigableExpr, CelSelect selectExpr) { + CelNavigableExpr operand = newNavigableChild(navigableExpr, selectExpr.operand()); + visit(operand); } - private int visit(CelNavigableExpr.Builder navigableExpr, CelComprehension comprehension) { - int maxHeight = 0; - maxHeight = max(visit(newNavigableChild(navigableExpr, comprehension.iterRange())), maxHeight); - maxHeight = max(visit(newNavigableChild(navigableExpr, comprehension.accuInit())), maxHeight); - maxHeight = - max(visit(newNavigableChild(navigableExpr, comprehension.loopCondition())), maxHeight); - maxHeight = max(visit(newNavigableChild(navigableExpr, comprehension.loopStep())), maxHeight); - maxHeight = max(visit(newNavigableChild(navigableExpr, comprehension.result())), maxHeight); - - return maxHeight; + private void visit(CelNavigableExpr navigableExpr, CelComprehension comprehension) { + visit(newNavigableChild(navigableExpr, comprehension.iterRange())); + visit(newNavigableChild(navigableExpr, comprehension.accuInit())); + visit(newNavigableChild(navigableExpr, comprehension.loopCondition())); + visit(newNavigableChild(navigableExpr, comprehension.loopStep())); + visit(newNavigableChild(navigableExpr, comprehension.result())); } - private int visitStruct(CelNavigableExpr.Builder navigableExpr, CelCreateStruct struct) { - int maxHeight = 0; + private void visitStruct(CelNavigableExpr navigableExpr, CelCreateStruct struct) { for (CelCreateStruct.Entry entry : struct.entries()) { - CelNavigableExpr.Builder value = newNavigableChild(navigableExpr, entry.value()); - maxHeight = max(visit(value), maxHeight); + visit(newNavigableChild(navigableExpr, entry.value())); } - return maxHeight; } - private int visitMap(CelNavigableExpr.Builder navigableExpr, CelCreateMap map) { - int maxHeight = 0; + private void visitMap(CelNavigableExpr navigableExpr, CelCreateMap map) { for (CelCreateMap.Entry entry : map.entries()) { - CelNavigableExpr.Builder key = newNavigableChild(navigableExpr, entry.key()); - maxHeight = max(visit(key), maxHeight); + CelNavigableExpr key = newNavigableChild(navigableExpr, entry.key()); + visit(key); - CelNavigableExpr.Builder value = newNavigableChild(navigableExpr, entry.value()); - maxHeight = max(visit(value), maxHeight); + CelNavigableExpr value = newNavigableChild(navigableExpr, entry.value()); + visit(value); } - return 0; } - private int visitExprList( - ImmutableList createListExpr, CelNavigableExpr.Builder parent) { - int maxHeight = 0; + private void visitExprList(ImmutableList createListExpr, CelNavigableExpr parent) { for (CelExpr expr : createListExpr) { - CelNavigableExpr.Builder arg = newNavigableChild(parent, expr); - maxHeight = max(visit(arg), maxHeight); + visit(newNavigableChild(parent, expr)); } - return maxHeight; } - private CelNavigableExpr.Builder newNavigableChild( - CelNavigableExpr.Builder parent, CelExpr expr) { - return CelNavigableExpr.builder() - .setExpr(expr) - .setDepth(parent.depth() + 1) - .setParentBuilder(parent); + private CelNavigableExpr newNavigableChild(CelNavigableExpr parent, CelExpr expr) { + CelNavigableExpr.Builder navigableExpr = + CelNavigableExpr.builder() + .setExpr(expr) + .setDepth(parent.depth() + 1) + .setHeight(exprHeightCalculator.getHeight(expr.id())) + .setParent(parent); + + return navigableExpr.build(); } } diff --git a/common/src/main/java/dev/cel/common/navigation/ExprHeightCalculator.java b/common/src/main/java/dev/cel/common/navigation/ExprHeightCalculator.java new file mode 100644 index 000000000..f6555a09b --- /dev/null +++ b/common/src/main/java/dev/cel/common/navigation/ExprHeightCalculator.java @@ -0,0 +1,132 @@ +// Copyright 2024 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.common.navigation; + +import static java.lang.Math.max; + +import com.google.common.collect.ImmutableList; +import dev.cel.common.ast.CelExpr; +import dev.cel.common.ast.CelExpr.CelCall; +import dev.cel.common.ast.CelExpr.CelComprehension; +import dev.cel.common.ast.CelExpr.CelCreateList; +import dev.cel.common.ast.CelExpr.CelCreateMap; +import dev.cel.common.ast.CelExpr.CelCreateStruct; +import dev.cel.common.ast.CelExpr.CelSelect; +import java.util.HashMap; + +/** Package-private class to assist computing the height of expression nodes. */ +final class ExprHeightCalculator { + // Store hashmap instead of immutable map for performance, such that this helper class can be + // instantiated faster. + private final HashMap idToHeight; + + ExprHeightCalculator(CelExpr celExpr) { + this.idToHeight = new HashMap<>(); + visit(celExpr); + } + + int getHeight(Long exprId) { + if (!idToHeight.containsKey(exprId)) { + throw new IllegalStateException("Height not found for expression id: " + exprId); + } + + return idToHeight.get(exprId); + } + + private int visit(CelExpr celExpr) { + int height = 1; + switch (celExpr.exprKind().getKind()) { + case CALL: + height += visit(celExpr.call()); + break; + case CREATE_LIST: + height += visit(celExpr.createList()); + break; + case SELECT: + height += visit(celExpr.select()); + break; + case CREATE_STRUCT: + height += visitStruct(celExpr.createStruct()); + break; + case CREATE_MAP: + height += visitMap(celExpr.createMap()); + break; + case COMPREHENSION: + height += visit(celExpr.comprehension()); + break; + default: + // This is a leaf node + height = 0; + break; + } + + idToHeight.put(celExpr.id(), height); + return height; + } + + private int visit(CelCall call) { + int targetHeight = 0; + if (call.target().isPresent()) { + targetHeight = visit(call.target().get()); + } + + int argumentHeight = visitExprList(call.args()); + return max(targetHeight, argumentHeight); + } + + private int visit(CelCreateList createList) { + return visitExprList(createList.elements()); + } + + private int visit(CelSelect selectExpr) { + return visit(selectExpr.operand()); + } + + private int visit(CelComprehension comprehension) { + int maxHeight = 0; + maxHeight = max(visit(comprehension.iterRange()), maxHeight); + maxHeight = max(visit(comprehension.accuInit()), maxHeight); + maxHeight = max(visit(comprehension.loopCondition()), maxHeight); + maxHeight = max(visit(comprehension.loopStep()), maxHeight); + maxHeight = max(visit(comprehension.result()), maxHeight); + + return maxHeight; + } + + private int visitStruct(CelCreateStruct struct) { + int maxHeight = 0; + for (CelCreateStruct.Entry entry : struct.entries()) { + maxHeight = max(visit(entry.value()), maxHeight); + } + return maxHeight; + } + + private int visitMap(CelCreateMap map) { + int maxHeight = 0; + for (CelCreateMap.Entry entry : map.entries()) { + maxHeight = max(visit(entry.key()), maxHeight); + maxHeight = max(visit(entry.value()), maxHeight); + } + return maxHeight; + } + + private int visitExprList(ImmutableList createListExpr) { + int maxHeight = 0; + for (CelExpr expr : createListExpr) { + maxHeight = max(visit(expr), maxHeight); + } + return maxHeight; + } +} diff --git a/common/src/test/java/dev/cel/common/navigation/CelNavigableExprVisitorTest.java b/common/src/test/java/dev/cel/common/navigation/CelNavigableExprVisitorTest.java index e263020fb..710267e55 100644 --- a/common/src/test/java/dev/cel/common/navigation/CelNavigableExprVisitorTest.java +++ b/common/src/test/java/dev/cel/common/navigation/CelNavigableExprVisitorTest.java @@ -153,22 +153,28 @@ public void add_fromLeaf_heightSetForParents() throws Exception { CelCompiler compiler = CelCompilerFactory.standardCelCompilerBuilder().addVar("a", SimpleType.INT).build(); // Tree shape: - // + - // + 2 - // 1 a - CelAbstractSyntaxTree ast = compiler.compile("1 + a + 2").getAst(); + // + + // + 3 + // + 2 + // a 1 + CelAbstractSyntaxTree ast = compiler.compile("1 + a + 2 + 3").getAst(); CelNavigableAst navigableAst = CelNavigableAst.fromAst(ast); - CelNavigableExpr oneConst = + ImmutableList.Builder heights = ImmutableList.builder(); + CelNavigableExpr navigableExpr = navigableAst .getRoot() - .descendants() - .filter(node -> node.expr().constantOrDefault().int64Value() == 1) + .allNodes() + .filter(node -> node.expr().identOrDefault().name().equals("a")) .findAny() .get(); - assertThat(oneConst.height()).isEqualTo(0); // 1 - assertThat(oneConst.parent().get().height()).isEqualTo(1); // + - assertThat(oneConst.parent().get().parent().get().height()).isEqualTo(2); // root + heights.add(navigableExpr.height()); + while (navigableExpr.parent().isPresent()) { + navigableExpr = navigableExpr.parent().get(); + heights.add(navigableExpr.height()); + } + + assertThat(heights.build()).containsExactly(3, 2, 1, 0); } @Test @@ -178,9 +184,9 @@ public void add_children_heightSet(@TestParameter TraversalOrder traversalOrder) CelCompilerFactory.standardCelCompilerBuilder().addVar("a", SimpleType.INT).build(); // Tree shape: // + - // + 2 - // + a - // 3 + // + 3 + // + 2 + // a 1 CelAbstractSyntaxTree ast = compiler.compile("1 + a + 2 + 3").getAst(); CelNavigableAst navigableAst = CelNavigableAst.fromAst(ast); @@ -840,7 +846,6 @@ public void comprehension_allNodes_parentsPopulated() throws Exception { ImmutableList allNodes = navigableAst.getRoot().allNodes(TraversalOrder.PRE_ORDER).collect(toImmutableList()); - CelExpr iterRangeConstExpr = CelExpr.ofConstantExpr(2, CelConstant.ofValue(true)); CelExpr iterRange = CelExpr.ofCreateListExpr(1, ImmutableList.of(iterRangeConstExpr), ImmutableList.of()); diff --git a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java index 57a7485f7..bb677826f 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java @@ -717,9 +717,9 @@ private enum CseTestCase { "cel.@block([{\"key\": \"test\"}], {?\"key\":" + " optional.of(\"test\")}[?\"bogus\"].or(@index0[?\"bogus\"]).orValue(@index0[\"key\"])" + " == \"test\")", - "cel.@block([{\"key\": \"test\"}, @index0[\"key\"], @index0[?\"bogus\"], {?\"key\":" - + " optional.of(\"test\")}, @index3[?\"bogus\"], @index4.or(@index2)," - + " @index5.orValue(@index1)], @index6 == \"test\")"), + "cel.@block([{\"key\": \"test\"}, @index0[\"key\"], @index0[?\"bogus\"]," + + " optional.of(\"test\"), {?\"key\": @index3}, @index4[?\"bogus\"]," + + " @index5.or(@index2), @index6.orValue(@index1)], @index7 == \"test\")"), OPTIONAL_MESSAGE( "TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32:" + " optional.of(4)}.single_int32 + TestAllTypes{?single_int64:" From c18f2a379eae297972dd1be528398ee5aa293a5c Mon Sep 17 00:00:00 2001 From: Steven Parkes Date: Fri, 23 Feb 2024 14:32:01 -0800 Subject: [PATCH 039/486] don't include protos (and some other dependencies) in jars --- publish/BUILD.bazel | 3 +++ 1 file changed, 3 insertions(+) diff --git a/publish/BUILD.bazel b/publish/BUILD.bazel index 6f8cc71a0..5259bf4fc 100644 --- a/publish/BUILD.bazel +++ b/publish/BUILD.bazel @@ -75,6 +75,9 @@ java_export( maven_coordinates = "dev.cel:cel:%s" % CEL_VERSION, pom_template = ":cel_pom", runtime_deps = ALL_TARGETS, + deploy_env = [ + "@com_google_googleapis//google/api/expr/v1alpha1:expr_java_proto" + ], ) pom_file( From 99351132285cb87e1ef52d34840c1a724451fb32 Mon Sep 17 00:00:00 2001 From: Tawan Muadmuenwai Date: Sun, 25 Feb 2024 11:40:00 +0700 Subject: [PATCH 040/486] Add link to Protocol Buffers tutorials in codelab README.md --- codelab/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codelab/README.md b/codelab/README.md index 65e504215..29065f0b1 100644 --- a/codelab/README.md +++ b/codelab/README.md @@ -20,7 +20,7 @@ Some key areas covered are: ### Prerequisites This codelab builds upon a basic understanding of Protocol Buffers and Java. -If you're not familiar with Protocol Buffers, the first exercise will give you a sense of how CEL works, but because the more advanced examples use Protocol Buffers as the input into CEL, they may be harder to understand. Consider working through one of these tutorials, first. +If you're not familiar with Protocol Buffers, the first exercise will give you a sense of how CEL works, but because the more advanced examples use Protocol Buffers as the input into CEL, they may be harder to understand. Consider working through one of these [tutorials](https://developers.google.com/protocol-buffers/docs/tutorials?authuser=0), first. Note that Protocol Buffers are not required to use CEL, but they are used extensively in this codelab. From dc9083b0c7e50a7b1219fd8988abc069683db4c5 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Tue, 27 Feb 2024 12:16:22 -0800 Subject: [PATCH 041/486] Create baseline tests for SubexpressionOptimizer PiperOrigin-RevId: 610833955 --- .../optimizers/SubexpressionOptimizer.java | 9 +- .../dev/cel/optimizer/optimizers/BUILD.bazel | 3 + .../SubexpressionOptimizerBaselineTest.java | 563 +++ .../SubexpressionOptimizerTest.java | 1212 ----- optimizer/src/test/resources/BUILD.bazel | 15 + .../large_expressions_bind_cascaded.baseline | 17 + ..._expressions_block_common_subexpr.baseline | 17 + ...pressions_block_recursion_depth_1.baseline | 17 + ...pressions_block_recursion_depth_2.baseline | 17 + ...pressions_block_recursion_depth_3.baseline | 17 + ...ion_ast_block_common_subexpr_only.baseline | 2924 +++++++++++++ ...ssion_ast_block_recursion_depth_1.baseline | 3710 ++++++++++++++++ ...ssion_ast_block_recursion_depth_2.baseline | 3569 +++++++++++++++ ...ssion_ast_block_recursion_depth_3.baseline | 3359 ++++++++++++++ ...ssion_ast_block_recursion_depth_4.baseline | 3326 ++++++++++++++ ...ssion_ast_block_recursion_depth_5.baseline | 3299 ++++++++++++++ ...ssion_ast_block_recursion_depth_6.baseline | 3293 ++++++++++++++ ...ssion_ast_block_recursion_depth_7.baseline | 3287 ++++++++++++++ ...ssion_ast_block_recursion_depth_8.baseline | 3281 ++++++++++++++ ...ssion_ast_block_recursion_depth_9.baseline | 3278 ++++++++++++++ .../subexpression_ast_cascaded_binds.baseline | 3894 +++++++++++++++++ .../resources/subexpression_unparsed.baseline | 623 +++ 22 files changed, 38514 insertions(+), 1216 deletions(-) create mode 100644 optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerBaselineTest.java create mode 100644 optimizer/src/test/resources/BUILD.bazel create mode 100644 optimizer/src/test/resources/large_expressions_bind_cascaded.baseline create mode 100644 optimizer/src/test/resources/large_expressions_block_common_subexpr.baseline create mode 100644 optimizer/src/test/resources/large_expressions_block_recursion_depth_1.baseline create mode 100644 optimizer/src/test/resources/large_expressions_block_recursion_depth_2.baseline create mode 100644 optimizer/src/test/resources/large_expressions_block_recursion_depth_3.baseline create mode 100644 optimizer/src/test/resources/subexpression_ast_block_common_subexpr_only.baseline create mode 100644 optimizer/src/test/resources/subexpression_ast_block_recursion_depth_1.baseline create mode 100644 optimizer/src/test/resources/subexpression_ast_block_recursion_depth_2.baseline create mode 100644 optimizer/src/test/resources/subexpression_ast_block_recursion_depth_3.baseline create mode 100644 optimizer/src/test/resources/subexpression_ast_block_recursion_depth_4.baseline create mode 100644 optimizer/src/test/resources/subexpression_ast_block_recursion_depth_5.baseline create mode 100644 optimizer/src/test/resources/subexpression_ast_block_recursion_depth_6.baseline create mode 100644 optimizer/src/test/resources/subexpression_ast_block_recursion_depth_7.baseline create mode 100644 optimizer/src/test/resources/subexpression_ast_block_recursion_depth_8.baseline create mode 100644 optimizer/src/test/resources/subexpression_ast_block_recursion_depth_9.baseline create mode 100644 optimizer/src/test/resources/subexpression_ast_cascaded_binds.baseline create mode 100644 optimizer/src/test/resources/subexpression_unparsed.baseline diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java index 4c7c081a9..ee2ec067b 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java @@ -339,16 +339,17 @@ private CelAbstractSyntaxTree optimizeUsingCelBind(CelNavigableAst navigableAst) throw new IllegalStateException("Max iteration count reached."); } + if (!cseOptions.populateMacroCalls()) { + astToModify = + CelAbstractSyntaxTree.newParsedAst(astToModify.getExpr(), CelSource.newBuilder().build()); + } + if (iterCount == 0) { // No modification has been made. return astToModify; } astToModify = mutableAst.renumberIdsConsecutively(astToModify); - if (!cseOptions.populateMacroCalls()) { - astToModify = - CelAbstractSyntaxTree.newParsedAst(astToModify.getExpr(), CelSource.newBuilder().build()); - } return astToModify; } diff --git a/optimizer/src/test/java/dev/cel/optimizer/optimizers/BUILD.bazel b/optimizer/src/test/java/dev/cel/optimizer/optimizers/BUILD.bazel index e3861f73c..5973bca8e 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/optimizers/BUILD.bazel +++ b/optimizer/src/test/java/dev/cel/optimizer/optimizers/BUILD.bazel @@ -6,6 +6,7 @@ java_library( name = "tests", testonly = 1, srcs = glob(["*.java"]), + resources = ["//optimizer/src/test/resources:baselines"], deps = [ # "//java/com/google/testing/testsize:annotations", "//bundle:cel", @@ -28,6 +29,7 @@ java_library( "//parser:operator", "//parser:unparser", "//runtime", + "//testing:baseline_test_case", "@maven//:junit_junit", "@maven//:com_google_testparameterinjector_test_parameter_injector", "//:java_truth", @@ -37,6 +39,7 @@ java_library( junit4_test_suites( name = "test_suites", + shard_count = 4, sizes = [ "small", "medium", diff --git a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerBaselineTest.java b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerBaselineTest.java new file mode 100644 index 000000000..8590ff587 --- /dev/null +++ b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerBaselineTest.java @@ -0,0 +1,563 @@ +// Copyright 2024 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.optimizers; + +import static com.google.common.truth.Truth.assertThat; +import static dev.cel.common.CelOverloadDecl.newGlobalOverload; + +import com.google.common.base.Ascii; +import com.google.common.collect.ImmutableMap; +import com.google.testing.junit.testparameterinjector.TestParameter; +import com.google.testing.junit.testparameterinjector.TestParameterInjector; +// import com.google.testing.testsize.MediumTest; +import dev.cel.bundle.Cel; +import dev.cel.bundle.CelBuilder; +import dev.cel.bundle.CelFactory; +import dev.cel.common.CelAbstractSyntaxTree; +import dev.cel.common.CelFunctionDecl; +import dev.cel.common.CelOptions; +import dev.cel.common.types.OptionalType; +import dev.cel.common.types.SimpleType; +import dev.cel.common.types.StructTypeReference; +import dev.cel.extensions.CelExtensions; +import dev.cel.extensions.CelOptionalLibrary; +import dev.cel.optimizer.CelOptimizer; +import dev.cel.optimizer.CelOptimizerFactory; +import dev.cel.optimizer.optimizers.SubexpressionOptimizer.SubexpressionOptimizerOptions; +import dev.cel.parser.CelStandardMacro; +import dev.cel.parser.CelUnparser; +import dev.cel.parser.CelUnparserFactory; +import dev.cel.testing.BaselineTestCase; +import dev.cel.testing.testdata.proto3.TestAllTypesProto.NestedTestAllTypes; +import dev.cel.testing.testdata.proto3.TestAllTypesProto.TestAllTypes; +import java.util.Optional; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +// @MediumTest +@RunWith(TestParameterInjector.class) +public class SubexpressionOptimizerBaselineTest extends BaselineTestCase { + private static final CelUnparser CEL_UNPARSER = CelUnparserFactory.newUnparser(); + private static final TestAllTypes TEST_ALL_TYPES_INPUT = + TestAllTypes.newBuilder() + .setSingleInt64(3L) + .setSingleInt32(5) + .setOneofType( + NestedTestAllTypes.newBuilder() + .setPayload( + TestAllTypes.newBuilder() + .setSingleInt32(8) + .setSingleInt64(10L) + .putMapInt32Int64(0, 1) + .putMapInt32Int64(1, 5) + .putMapInt32Int64(2, 2) + .putMapStringString("key", "A"))) + .build(); + private static final Cel CEL = newCelBuilder().build(); + + private String overriddenBaseFilePath = ""; + + @Before + public void setUp() { + overriddenBaseFilePath = ""; + } + + @Override + protected String baselineFileName() { + if (overriddenBaseFilePath.isEmpty()) { + return super.baselineFileName(); + } + return overriddenBaseFilePath; + } + + @Test + public void allOptimizers_producesSameEvaluationResult( + @TestParameter CseTestOptimizer cseTestOptimizer, @TestParameter CseTestCase cseTestCase) + throws Exception { + skipBaselineVerification(); + CelAbstractSyntaxTree ast = CEL.compile(cseTestCase.source).getAst(); + Object expectedEvalResult = + CEL.createProgram(ast) + .eval(ImmutableMap.of("msg", TEST_ALL_TYPES_INPUT, "x", 5L, "opt_x", Optional.of(5L))); + + CelAbstractSyntaxTree optimizedAst = cseTestOptimizer.celOptimizer.optimize(ast); + + Object optimizedEvalResult = + CEL.createProgram(optimizedAst) + .eval(ImmutableMap.of("msg", TEST_ALL_TYPES_INPUT, "x", 5L, "opt_x", Optional.of(5L))); + assertThat(optimizedEvalResult).isEqualTo(expectedEvalResult); + } + + @Test + public void subexpression_unparsed() throws Exception { + for (CseTestCase cseTestCase : CseTestCase.values()) { + testOutput().println("Test case: " + cseTestCase.name()); + testOutput().println("Source: " + cseTestCase.source); + testOutput().println("=====>"); + CelAbstractSyntaxTree ast = CEL.compile(cseTestCase.source).getAst(); + boolean resultPrinted = false; + for (CseTestOptimizer cseTestOptimizer : CseTestOptimizer.values()) { + String optimizerName = cseTestOptimizer.name(); + CelAbstractSyntaxTree optimizedAst = cseTestOptimizer.celOptimizer.optimize(ast); + if (!resultPrinted) { + Object optimizedEvalResult = + CEL.createProgram(optimizedAst) + .eval( + ImmutableMap.of( + "msg", TEST_ALL_TYPES_INPUT, "x", 5L, "opt_x", Optional.of(5L))); + testOutput().println("Result: " + optimizedEvalResult); + resultPrinted = true; + } + try { + testOutput().printf("[%s]: %s", optimizerName, CEL_UNPARSER.unparse(optimizedAst)); + } catch (RuntimeException e) { + testOutput().printf("[%s]: Unparse Error: %s", optimizerName, e); + } + testOutput().println(); + } + testOutput().println(); + } + } + + @Test + public void subexpression_ast(@TestParameter CseTestOptimizer cseTestOptimizer) throws Exception { + String testBasefileName = "subexpression_ast_" + Ascii.toLowerCase(cseTestOptimizer.name()); + overriddenBaseFilePath = String.format("%s%s.baseline", testdataDir(), testBasefileName); + for (CseTestCase cseTestCase : CseTestCase.values()) { + testOutput().println("Test case: " + cseTestCase.name()); + testOutput().println("Source: " + cseTestCase.source); + testOutput().println("=====>"); + CelAbstractSyntaxTree ast = CEL.compile(cseTestCase.source).getAst(); + CelAbstractSyntaxTree optimizedAst = cseTestOptimizer.celOptimizer.optimize(ast); + testOutput().println(optimizedAst.getExpr()); + } + } + + @Test + public void populateMacroCallsDisabled_macroMapUnpopulated(@TestParameter CseTestCase testCase) + throws Exception { + skipBaselineVerification(); + Cel cel = newCelBuilder().build(); + CelOptimizer celOptimizerWithBinds = + newCseOptimizer( + cel, + SubexpressionOptimizerOptions.newBuilder() + .populateMacroCalls(false) + .enableCelBlock(false) + .build()); + CelOptimizer celOptimizerWithBlocks = + newCseOptimizer( + cel, + SubexpressionOptimizerOptions.newBuilder() + .populateMacroCalls(false) + .enableCelBlock(true) + .build()); + CelOptimizer celOptimizerWithFlattenedBlocks = + newCseOptimizer( + cel, + SubexpressionOptimizerOptions.newBuilder() + .populateMacroCalls(false) + .enableCelBlock(true) + .subexpressionMaxRecursionDepth(1) + .build()); + CelAbstractSyntaxTree originalAst = cel.compile(testCase.source).getAst(); + + CelAbstractSyntaxTree astOptimizedWithBinds = celOptimizerWithBinds.optimize(originalAst); + CelAbstractSyntaxTree astOptimizedWithBlocks = celOptimizerWithBlocks.optimize(originalAst); + CelAbstractSyntaxTree astOptimizedWithFlattenedBlocks = + celOptimizerWithFlattenedBlocks.optimize(originalAst); + + assertThat(astOptimizedWithBinds.getSource().getMacroCalls()).isEmpty(); + assertThat(astOptimizedWithBlocks.getSource().getMacroCalls()).isEmpty(); + assertThat(astOptimizedWithFlattenedBlocks.getSource().getMacroCalls()).isEmpty(); + } + + @Test + public void large_expressions_bind_cascaded() throws Exception { + CelOptimizer celOptimizer = + newCseOptimizer( + CEL, + SubexpressionOptimizerOptions.newBuilder() + .populateMacroCalls(true) + .enableCelBlock(false) + .build()); + + runLargeTestCases(celOptimizer); + } + + @Test + public void large_expressions_block_common_subexpr() throws Exception { + CelOptimizer celOptimizer = + newCseOptimizer( + CEL, + SubexpressionOptimizerOptions.newBuilder() + .populateMacroCalls(true) + .enableCelBlock(true) + .build()); + + runLargeTestCases(celOptimizer); + } + + @Test + public void large_expressions_block_recursion_depth_1() throws Exception { + CelOptimizer celOptimizer = + newCseOptimizer( + CEL, + SubexpressionOptimizerOptions.newBuilder() + .populateMacroCalls(true) + .enableCelBlock(true) + .subexpressionMaxRecursionDepth(1) + .build()); + + runLargeTestCases(celOptimizer); + } + + @Test + public void large_expressions_block_recursion_depth_2() throws Exception { + CelOptimizer celOptimizer = + newCseOptimizer( + CEL, + SubexpressionOptimizerOptions.newBuilder() + .populateMacroCalls(true) + .enableCelBlock(true) + .subexpressionMaxRecursionDepth(2) + .build()); + + runLargeTestCases(celOptimizer); + } + + @Test + public void large_expressions_block_recursion_depth_3() throws Exception { + CelOptimizer celOptimizer = + newCseOptimizer( + CEL, + SubexpressionOptimizerOptions.newBuilder() + .populateMacroCalls(true) + .enableCelBlock(true) + .subexpressionMaxRecursionDepth(3) + .build()); + + runLargeTestCases(celOptimizer); + } + + private void runLargeTestCases(CelOptimizer celOptimizer) throws Exception { + for (CseLargeTestCase cseTestCase : CseLargeTestCase.values()) { + testOutput().println("Test case: " + cseTestCase.name()); + testOutput().println("Source: " + cseTestCase.source); + testOutput().println("=====>"); + CelAbstractSyntaxTree ast = CEL.compile(cseTestCase.source).getAst(); + + CelAbstractSyntaxTree optimizedAst = celOptimizer.optimize(ast); + Object optimizedEvalResult = + CEL.createProgram(optimizedAst) + .eval( + ImmutableMap.of("msg", TEST_ALL_TYPES_INPUT, "x", 5L, "opt_x", Optional.of(5L))); + testOutput().println("Result: " + optimizedEvalResult); + try { + testOutput().printf("Unparsed: %s", CEL_UNPARSER.unparse(optimizedAst)); + } catch (RuntimeException e) { + testOutput().printf("Unparse Error: %s", e); + } + testOutput().println(); + testOutput().println(); + } + } + + private static CelBuilder newCelBuilder() { + return CelFactory.standardCelBuilder() + .addMessageTypes(TestAllTypes.getDescriptor()) + .setContainer("dev.cel.testing.testdata.proto3") + .setStandardMacros(CelStandardMacro.STANDARD_MACROS) + .setOptions( + CelOptions.current().enableTimestampEpoch(true).populateMacroCalls(true).build()) + .addCompilerLibraries(CelOptionalLibrary.INSTANCE, CelExtensions.bindings()) + .addRuntimeLibraries(CelOptionalLibrary.INSTANCE) + .addFunctionDeclarations( + CelFunctionDecl.newFunctionDeclaration( + "custom_func", + newGlobalOverload("custom_func_overload", SimpleType.INT, SimpleType.INT))) + .addVar("x", SimpleType.DYN) + .addVar("opt_x", OptionalType.create(SimpleType.DYN)) + .addVar("msg", StructTypeReference.create(TestAllTypes.getDescriptor().getFullName())); + } + + private static CelOptimizer newCseOptimizer(Cel cel, SubexpressionOptimizerOptions options) { + return CelOptimizerFactory.standardCelOptimizerBuilder(cel) + .addAstOptimizers(SubexpressionOptimizer.newInstance(options)) + .build(); + } + + @SuppressWarnings("Immutable") // Test only + private enum CseTestOptimizer { + CASCADED_BINDS( + SubexpressionOptimizerOptions.newBuilder() + .populateMacroCalls(true) + .enableCelBlock(false) + .build()), + BLOCK_COMMON_SUBEXPR_ONLY( + SubexpressionOptimizerOptions.newBuilder() + .populateMacroCalls(true) + .enableCelBlock(true) + .build()), + BLOCK_RECURSION_DEPTH_1( + SubexpressionOptimizerOptions.newBuilder() + .populateMacroCalls(true) + .enableCelBlock(true) + .subexpressionMaxRecursionDepth(1) + .build()), + BLOCK_RECURSION_DEPTH_2( + SubexpressionOptimizerOptions.newBuilder() + .populateMacroCalls(true) + .enableCelBlock(true) + .subexpressionMaxRecursionDepth(2) + .build()), + BLOCK_RECURSION_DEPTH_3( + SubexpressionOptimizerOptions.newBuilder() + .populateMacroCalls(true) + .enableCelBlock(true) + .subexpressionMaxRecursionDepth(3) + .build()), + BLOCK_RECURSION_DEPTH_4( + SubexpressionOptimizerOptions.newBuilder() + .populateMacroCalls(true) + .enableCelBlock(true) + .subexpressionMaxRecursionDepth(4) + .build()), + BLOCK_RECURSION_DEPTH_5( + SubexpressionOptimizerOptions.newBuilder() + .populateMacroCalls(true) + .enableCelBlock(true) + .subexpressionMaxRecursionDepth(5) + .build()), + BLOCK_RECURSION_DEPTH_6( + SubexpressionOptimizerOptions.newBuilder() + .populateMacroCalls(true) + .enableCelBlock(true) + .subexpressionMaxRecursionDepth(6) + .build()), + BLOCK_RECURSION_DEPTH_7( + SubexpressionOptimizerOptions.newBuilder() + .populateMacroCalls(true) + .enableCelBlock(true) + .subexpressionMaxRecursionDepth(7) + .build()), + BLOCK_RECURSION_DEPTH_8( + SubexpressionOptimizerOptions.newBuilder() + .populateMacroCalls(true) + .enableCelBlock(true) + .subexpressionMaxRecursionDepth(8) + .build()), + BLOCK_RECURSION_DEPTH_9( + SubexpressionOptimizerOptions.newBuilder() + .populateMacroCalls(true) + .enableCelBlock(true) + .subexpressionMaxRecursionDepth(9) + .build()); + + private final CelOptimizer celOptimizer; + + CseTestOptimizer(SubexpressionOptimizerOptions option) { + this.celOptimizer = newCseOptimizer(CEL, option); + } + } + + private enum CseTestCase { + SIZE_1("size([1,2]) + size([1,2]) + 1 == 5"), + SIZE_2("2 + size([1,2]) + size([1,2]) + 1 == 7"), + SIZE_3("size([0]) + size([0]) + size([1,2]) + size([1,2]) == 6"), + SIZE_4( + "5 + size([0]) + size([0]) + size([1,2]) + size([1,2]) + " + + "size([1,2,3]) + size([1,2,3]) == 17"), + TIMESTAMP( + "timestamp(int(timestamp(1000000000))).getFullYear() +" + + " timestamp(int(timestamp(75))).getFullYear() + " + + " timestamp(int(timestamp(50))).getFullYear() + " + + " timestamp(int(timestamp(1000000000))).getFullYear() + " + + " timestamp(int(timestamp(50))).getSeconds() + " + + " timestamp(int(timestamp(200))).getFullYear() + " + + " timestamp(int(timestamp(200))).getFullYear() + " + + " timestamp(int(timestamp(75))).getMinutes() + " + + " timestamp(int(timestamp(1000000000))).getFullYear() == 13934"), + MAP_INDEX("{\"a\": 2}[\"a\"] + {\"a\": 2}[\"a\"] * {\"a\": 2}[\"a\"] == 6"), + /** + * Input map is: + * + *

{@code
+     * {
+     *    "a": { "b": 1 },
+     *    "c": { "b": 1 },
+     *    "d": {
+     *       "e": { "b": 1 }
+     *    },
+     *    "e":{
+     *       "e": { "b": 1 }
+     *    }
+     * }
+     * }
+ */ + NESTED_MAP_CONSTRUCTION( + "{'a': {'b': 1}, 'c': {'b': 1}, 'd': {'e': {'b': 1}}, 'e': {'e': {'b': 1}}}"), + NESTED_LIST_CONSTRUCTION( + "[1, [1,2,3,4], 2, [1,2,3,4], 5, [1,2,3,4], 7, [[1,2], [1,2,3,4]], [1,2]]"), + SELECT("msg.single_int64 + msg.single_int64 == 6"), + SELECT_NESTED_1( + "msg.oneof_type.payload.single_int64 + msg.oneof_type.payload.single_int32 + " + + "msg.oneof_type.payload.single_int64 + " + + "msg.single_int64 + msg.oneof_type.payload.oneof_type.payload.single_int64 == 31"), + SELECT_NESTED_2( + "true ||" + + " msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload.single_bool" + + " || msg.oneof_type.payload.oneof_type.payload.oneof_type.child.child.payload.single_bool"), + SELECT_NESTED_MESSAGE_MAP_INDEX_1( + "msg.oneof_type.payload.map_int32_int64[1] + " + + "msg.oneof_type.payload.map_int32_int64[1] + " + + "msg.oneof_type.payload.map_int32_int64[1] == 15"), + SELECT_NESTED_MESSAGE_MAP_INDEX_2( + "msg.oneof_type.payload.map_int32_int64[0] + " + + "msg.oneof_type.payload.map_int32_int64[1] + " + + "msg.oneof_type.payload.map_int32_int64[2] == 8"), + SELECT_NESTED_NO_COMMON_SUBEXPR( + "msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload.single_int64"), + TERNARY("(msg.single_int64 > 0 ? msg.single_int64 : 0) == 3"), + TERNARY_BIND_RHS_ONLY( + "false ? false : (msg.single_int64) + ((msg.single_int64 + 1) * 2) == 11"), + NESTED_TERNARY( + "(msg.single_int64 > 0 ? (msg.single_int32 > 0 ? " + + "msg.single_int64 + msg.single_int32 : 0) : 0) == 8"), + MULTIPLE_MACROS_1( + // Note that all of these have different iteration variables, but they are still logically + // the same. + "size([[1].exists(i, i > 0)]) + size([[1].exists(j, j > 0)]) + " + + "size([[2].exists(k, k > 1)]) + size([[2].exists(l, l > 1)]) == 4"), + MULTIPLE_MACROS_2( + "[[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == 'a')] +" + + " [['a'].exists(l, l == 'a')] == [true, true, true, true]"), + NESTED_MACROS("[1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [[2, 3, 4], [2, 3, 4], [2, 3, 4]]"), + NESTED_MACROS_2("[1, 2].map(y, [1, 2, 3].filter(x, x == y)) == [[1], [2]]"), + INCLUSION_LIST("1 in [1,2,3] && 2 in [1,2,3] && 3 in [3, [1,2,3]] && 1 in [1,2,3]"), + INCLUSION_MAP("2 in {'a': 1, 2: {true: false}, 3: {true: false}}"), + MACRO_ITER_VAR_NOT_REFERENCED( + "[1,2].map(i, [1, 2].map(i, [3,4])) == [[[3, 4], [3, 4]], [[3, 4], [3, 4]]]"), + MACRO_SHADOWED_VARIABLE("[x - 1 > 3 ? x - 1 : 5].exists(x, x - 1 > 3) || x - 1 > 3"), + MACRO_SHADOWED_VARIABLE_2("[\"foo\", \"bar\"].map(x, [x + x, x + x]).map(x, [x + x, x + x])"), + PRESENCE_TEST("has({'a': true}.a) && {'a':true}['a']"), + PRESENCE_TEST_WITH_TERNARY( + "(has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : 0) == 10"), + PRESENCE_TEST_WITH_TERNARY_2( + "(has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 :" + + " msg.oneof_type.payload.single_int64 * 0) == 10"), + PRESENCE_TEST_WITH_TERNARY_3( + "(has(msg.oneof_type.payload.single_int64) ? msg.oneof_type.payload.single_int64 :" + + " msg.oneof_type.payload.single_int64 * 0) == 10"), + /** + * Input: + * + *
{@code
+     * (
+     *   has(msg.oneof_type) &&
+     *   has(msg.oneof_type.payload) &&
+     *   has(msg.oneof_type.payload.single_int64)
+     * ) ?
+     *   (
+     *     (
+     *       has(msg.oneof_type.payload.map_string_string) &&
+     *       has(msg.oneof_type.payload.map_string_string.key)
+     *     ) ?
+     *       msg.oneof_type.payload.map_string_string.key == "A"
+     *     : false
+     *   )
+     * : false
+     * }
+ */ + PRESENCE_TEST_WITH_TERNARY_NESTED( + "(has(msg.oneof_type) && has(msg.oneof_type.payload) &&" + + " has(msg.oneof_type.payload.single_int64)) ?" + + " ((has(msg.oneof_type.payload.map_string_string) &&" + + " has(msg.oneof_type.payload.map_string_string.key)) ?" + + " msg.oneof_type.payload.map_string_string.key == 'A' : false) : false"), + OPTIONAL_LIST( + "[10, ?optional.none(), [?optional.none(), ?opt_x], [?optional.none(), ?opt_x]] == [10," + + " [5], [5]]"), + OPTIONAL_MAP( + "{?'hello': optional.of('hello')}['hello'] + {?'hello': optional.of('hello')}['hello'] ==" + + " 'hellohello'"), + OPTIONAL_MAP_CHAINED( + "{?'key': optional.of('test')}[?'bogus'].or({'key': 'test'}[?'bogus']).orValue({'key':" + + " 'test'}['key']) == 'test'"), + OPTIONAL_MESSAGE( + "TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32:" + + " optional.of(4)}.single_int32 + TestAllTypes{?single_int64:" + + " optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}.single_int64 == 5"), + CALL("('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('h' + 'e' + 'l' + 'l' + 'o')"), + CALL_ARGUMENT_NESTED_NO_COMMON_SUBEXPR("'hello world'.matches('h' + 'e' + 'l' + 'l' + 'o')"), + CALL_TARGET_NESTED_NO_COMMON_SUBEXPR( + "('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('hello')"), + CALL_BOTH_ARGUMENT_TARGET_NESTED_NO_COMMON_SUBEXPR( + "('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('w' + 'o' + 'r' + 'l' + 'd')"), + ; + private final String source; + + CseTestCase(String source) { + this.source = source; + } + } + + private enum CseLargeTestCase { + CALC_FOUR_COMMON_SUBEXPR( + "[1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] +" + + " [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] +" + + " [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] +" + + " [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2]" + + " + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] +" + + " [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] +" + + " [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2]" + + " + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] +" + + " [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] +" + + " [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2]" + + " + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] +" + + " [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] +" + + " [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2]" + + " + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] +" + + " [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] +" + + " [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2]" + + " + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] +" + + " [1,2,3,4]"), + CALC_ALL_COMMON_SUBEXPR( + "[0, 1] + [0, 1] + [1, 2] + [1, 2] + [2, 3] + [2, 3] + [3, 4] + [3, 4] + [4, 5] + [4, 5] +" + + " [5, 6] + [5, 6] + [6, 7] + [6, 7] + [7, 8] + [7, 8] + [8, 9] + [8, 9] + [9, 10] +" + + " [9, 10] + [10, 11] + [10, 11] + [11, 12] + [11, 12] + [12, 13] + [12, 13] + [13," + + " 14] + [13, 14] + [14, 15] + [14, 15] + [15, 16] + [15, 16] + [16, 17] + [16, 17] +" + + " [17, 18] + [17, 18] + [18, 19] + [18, 19] + [19, 20] + [19, 20] + [20, 21] + [20," + + " 21] + [21, 22] + [21, 22] + [22, 23] + [22, 23] + [23, 24] + [23, 24] + [24, 25] +" + + " [24, 25] + [25, 26] + [25, 26] + [26, 27] + [26, 27] + [27, 28] + [27, 28] + [28," + + " 29] + [28, 29] + [29, 30] + [29, 30] + [30, 31] + [30, 31] + [31, 32] + [31, 32] +" + + " [32, 33] + [32, 33] + [33, 34] + [33, 34] + [34, 35] + [34, 35] + [35, 36] + [35," + + " 36] + [36, 37] + [36, 37] + [37, 38] + [37, 38] + [38, 39] + [38, 39] + [39, 40] +" + + " [39, 40] + [40, 41] + [40, 41] + [41, 42] + [41, 42] + [42, 43] + [42, 43] + [43," + + " 44] + [43, 44] + [44, 45] + [44, 45] + [45, 46] + [45, 46] + [46, 47] + [46, 47] +" + + " [47, 48] + [47, 48] + [48, 49] + [48, 49] + [49, 50] + [49, 50]"), + NESTED_MACROS( + "[1,2,3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i," + + " [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3]))))))))"); + ; + + private final String source; + + CseLargeTestCase(String source) { + this.source = source; + } + } +} diff --git a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java index bb677826f..f09a7e9c7 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java @@ -23,7 +23,6 @@ import com.google.testing.junit.testparameterinjector.TestParameter; import com.google.testing.junit.testparameterinjector.TestParameterInjector; import com.google.testing.junit.testparameterinjector.TestParameters; -// import com.google.testing.testsize.MediumTest; import dev.cel.bundle.Cel; import dev.cel.bundle.CelBuilder; import dev.cel.bundle.CelFactory; @@ -59,14 +58,12 @@ import dev.cel.runtime.CelRuntime; import dev.cel.runtime.CelRuntime.CelFunctionBinding; import dev.cel.runtime.CelRuntimeFactory; -import dev.cel.testing.testdata.proto3.TestAllTypesProto.NestedTestAllTypes; import dev.cel.testing.testdata.proto3.TestAllTypesProto.TestAllTypes; import java.util.Optional; import java.util.concurrent.atomic.AtomicInteger; import org.junit.Test; import org.junit.runner.RunWith; -// @MediumTest @RunWith(TestParameterInjector.class) public class SubexpressionOptimizerTest { @@ -107,22 +104,6 @@ public class SubexpressionOptimizerTest { private static final CelUnparser CEL_UNPARSER = CelUnparserFactory.newUnparser(); - private static final TestAllTypes TEST_ALL_TYPES_INPUT = - TestAllTypes.newBuilder() - .setSingleInt64(3L) - .setSingleInt32(5) - .setOneofType( - NestedTestAllTypes.newBuilder() - .setPayload( - TestAllTypes.newBuilder() - .setSingleInt32(8) - .setSingleInt64(10L) - .putMapInt32Int64(0, 1) - .putMapInt32Int64(1, 5) - .putMapInt32Int64(2, 2) - .putMapStringString("key", "A"))) - .build(); - private static CelBuilder newCelBuilder() { return CelFactory.standardCelBuilder() .addMessageTypes(TestAllTypes.getDescriptor()) @@ -147,976 +128,6 @@ private static CelOptimizer newCseOptimizer(SubexpressionOptimizerOptions option .build(); } - @Test - public void cse_withCelBind_producesOptimizedAst() throws Exception { - CelAbstractSyntaxTree ast = - CEL.compile("size([0]) + size([0]) + size([1,2]) + size([1,2])").getAst(); - - CelAbstractSyntaxTree optimizedAst = - newCseOptimizer( - SubexpressionOptimizerOptions.newBuilder() - .populateMacroCalls(false) - .enableCelBlock(false) - .build()) - .optimize(ast); - - assertThat(CEL.createProgram(optimizedAst).eval()).isEqualTo(6); - assertThat(optimizedAst.getExpr().toString()) - .isEqualTo( - "COMPREHENSION [1] {\n" - + " iter_var: #unused\n" - + " iter_range: {\n" - + " CREATE_LIST [2] {\n" - + " elements: {\n" - + " }\n" - + " }\n" - + " }\n" - + " accu_var: @r1\n" - + " accu_init: {\n" - + " CALL [3] {\n" - + " function: size\n" - + " args: {\n" - + " CREATE_LIST [4] {\n" - + " elements: {\n" - + " CONSTANT [5] { value: 1 }\n" - + " CONSTANT [6] { value: 2 }\n" - + " }\n" - + " }\n" - + " }\n" - + " }\n" - + " }\n" - + " loop_condition: {\n" - + " CONSTANT [7] { value: false }\n" - + " }\n" - + " loop_step: {\n" - + " IDENT [8] {\n" - + " name: @r1\n" - + " }\n" - + " }\n" - + " result: {\n" - + " CALL [9] {\n" - + " function: _+_\n" - + " args: {\n" - + " CALL [10] {\n" - + " function: _+_\n" - + " args: {\n" - + " COMPREHENSION [11] {\n" - + " iter_var: #unused\n" - + " iter_range: {\n" - + " CREATE_LIST [12] {\n" - + " elements: {\n" - + " }\n" - + " }\n" - + " }\n" - + " accu_var: @r0\n" - + " accu_init: {\n" - + " CALL [13] {\n" - + " function: size\n" - + " args: {\n" - + " CREATE_LIST [14] {\n" - + " elements: {\n" - + " CONSTANT [15] { value: 0 }\n" - + " }\n" - + " }\n" - + " }\n" - + " }\n" - + " }\n" - + " loop_condition: {\n" - + " CONSTANT [16] { value: false }\n" - + " }\n" - + " loop_step: {\n" - + " IDENT [17] {\n" - + " name: @r0\n" - + " }\n" - + " }\n" - + " result: {\n" - + " CALL [18] {\n" - + " function: _+_\n" - + " args: {\n" - + " IDENT [19] {\n" - + " name: @r0\n" - + " }\n" - + " IDENT [20] {\n" - + " name: @r0\n" - + " }\n" - + " }\n" - + " }\n" - + " }\n" - + " }\n" - + " IDENT [21] {\n" - + " name: @r1\n" - + " }\n" - + " }\n" - + " }\n" - + " IDENT [22] {\n" - + " name: @r1\n" - + " }\n" - + " }\n" - + " }\n" - + " }\n" - + "}"); - } - - @Test - public void cse_withCelBlock_producesOptimizedAst() throws Exception { - CelAbstractSyntaxTree ast = - CEL.compile("size([0]) + size([0]) + size([1,2]) + size([1,2])").getAst(); - CelOptimizer celOptimizer = - newCseOptimizer(SubexpressionOptimizerOptions.newBuilder().enableCelBlock(true).build()); - CelAbstractSyntaxTree optimizedAst = celOptimizer.optimize(ast); - - assertThat(CEL.createProgram(optimizedAst).eval()).isEqualTo(6); - assertThat(optimizedAst.getExpr().toString()) - .isEqualTo( - "CALL [1] {\n" - + " function: cel.@block\n" - + " args: {\n" - + " CREATE_LIST [2] {\n" - + " elements: {\n" - + " CALL [3] {\n" - + " function: size\n" - + " args: {\n" - + " CREATE_LIST [4] {\n" - + " elements: {\n" - + " CONSTANT [5] { value: 0 }\n" - + " }\n" - + " }\n" - + " }\n" - + " }\n" - + " CALL [6] {\n" - + " function: size\n" - + " args: {\n" - + " CREATE_LIST [7] {\n" - + " elements: {\n" - + " CONSTANT [8] { value: 1 }\n" - + " CONSTANT [9] { value: 2 }\n" - + " }\n" - + " }\n" - + " }\n" - + " }\n" - + " }\n" - + " }\n" - + " CALL [10] {\n" - + " function: _+_\n" - + " args: {\n" - + " CALL [11] {\n" - + " function: _+_\n" - + " args: {\n" - + " CALL [12] {\n" - + " function: _+_\n" - + " args: {\n" - + " IDENT [13] {\n" - + " name: @index0\n" - + " }\n" - + " IDENT [14] {\n" - + " name: @index0\n" - + " }\n" - + " }\n" - + " }\n" - + " IDENT [15] {\n" - + " name: @index1\n" - + " }\n" - + " }\n" - + " }\n" - + " IDENT [16] {\n" - + " name: @index1\n" - + " }\n" - + " }\n" - + " }\n" - + " }\n" - + "}"); - } - - private enum CseTestCase { - SIZE_1( - "size([1,2]) + size([1,2]) + 1 == 5", - "cel.bind(@r0, size([1, 2]), @r0 + @r0) + 1 == 5", - "cel.@block([size([1, 2])], @index0 + @index0 + 1 == 5)", - "cel.@block([[1, 2], size(@index0), @index1 + @index1, @index2 + 1], @index3 == 5)"), - SIZE_2( - "2 + size([1,2]) + size([1,2]) + 1 == 7", - "cel.bind(@r0, size([1, 2]), 2 + @r0 + @r0) + 1 == 7", - "cel.@block([size([1, 2])], 2 + @index0 + @index0 + 1 == 7)", - "cel.@block([[1, 2], size(@index0), 2 + @index1, @index2 + @index1, @index3 + 1], @index4" - + " == 7)"), - SIZE_3( - "size([0]) + size([0]) + size([1,2]) + size([1,2]) == 6", - "cel.bind(@r1, size([1, 2]), cel.bind(@r0, size([0]), @r0 + @r0) + @r1 + @r1) == 6", - "cel.@block([size([0]), size([1, 2])], @index0 + @index0 + @index1 + @index1 == 6)", - "cel.@block([[0], size(@index0), [1, 2], size(@index2), @index1 + @index1, @index4 +" - + " @index3, @index5 + @index3], @index6 == 6)"), - SIZE_4( - "5 + size([0]) + size([0]) + size([1,2]) + size([1,2]) + " - + "size([1,2,3]) + size([1,2,3]) == 17", - "cel.bind(@r2, size([1, 2, 3]), cel.bind(@r1, size([1, 2]), cel.bind(@r0, size([0]), 5 +" - + " @r0 + @r0) + @r1 + @r1) + @r2 + @r2) == 17", - "cel.@block([size([0]), size([1, 2]), size([1, 2, 3])], 5 + @index0 + @index0 + @index1 +" - + " @index1 + @index2 + @index2 == 17)", - "cel.@block([[0], size(@index0), [1, 2], size(@index2), [1, 2, 3], size(@index4), 5 +" - + " @index1, @index6 + @index1, @index7 + @index3, @index8 + @index3, @index9 +" - + " @index5, @index10 + @index5], @index11 == 17)"), - /** - * Unparsed form: - * - *
-     * {@code
-     * // With binds
-     * cel.bind(@r0, timestamp(int(timestamp(1000000000))).getFullYear(),
-     *    cel.bind(@r3, timestamp(int(timestamp(75))),
-     *      cel.bind(@r2, timestamp(int(timestamp(200))).getFullYear(),
-     *        cel.bind(@r1, timestamp(int(timestamp(50))),
-     *          @r0 + @r3.getFullYear() + @r1.getFullYear() + @r0 + @r1.getSeconds()
-     *        ) + @r2 + @r2
-     *      ) + @r3.getMinutes()
-     *    ) + @r0
-     *) == 13934
-     * }
-     * 
- *
-     * {@code
-     * // With block
-     * cel.@block(
-     *     [
-     *      timestamp(int(timestamp(1000000000))).getFullYear(),
-     *      timestamp(int(timestamp(50))),
-     *      timestamp(int(timestamp(200))).getFullYear(),
-     *      timestamp(int(timestamp(75)))
-     *     ],
-     *     @index0 + @index3.getFullYear() + @index1.getFullYear() + @index0 +
-     *     @index1.getSeconds() + @index2 + @index2 + @index3.getMinutes() + @index0 == 13934
-     * )
-     * 
- * } - */ - TIMESTAMP( - "timestamp(int(timestamp(1000000000))).getFullYear() +" - + " timestamp(int(timestamp(75))).getFullYear() + " - + " timestamp(int(timestamp(50))).getFullYear() + " - + " timestamp(int(timestamp(1000000000))).getFullYear() + " - + " timestamp(int(timestamp(50))).getSeconds() + " - + " timestamp(int(timestamp(200))).getFullYear() + " - + " timestamp(int(timestamp(200))).getFullYear() + " - + " timestamp(int(timestamp(75))).getMinutes() + " - + " timestamp(int(timestamp(1000000000))).getFullYear() == 13934", - "cel.bind(@r0, timestamp(int(timestamp(1000000000))).getFullYear(), " - + "cel.bind(@r3, timestamp(int(timestamp(75))), " - + "cel.bind(@r2, timestamp(int(timestamp(200))).getFullYear(), " - + "cel.bind(@r1, timestamp(int(timestamp(50))), " - + "@r0 + @r3.getFullYear() + @r1.getFullYear() + " - + "@r0 + @r1.getSeconds()) + @r2 + @r2) + @r3.getMinutes()) + @r0) == 13934", - "cel.@block([timestamp(int(timestamp(1000000000))).getFullYear()," - + " timestamp(int(timestamp(50))), timestamp(int(timestamp(200))).getFullYear()," - + " timestamp(int(timestamp(75)))], @index0 + @index3.getFullYear() +" - + " @index1.getFullYear() + @index0 + @index1.getSeconds() + @index2 + @index2 +" - + " @index3.getMinutes() + @index0 == 13934)", - "cel.@block([timestamp(1000000000), int(@index0), timestamp(@index1)," - + " @index2.getFullYear(), timestamp(50), int(@index4), timestamp(@index5)," - + " timestamp(200), int(@index7), timestamp(@index8), @index9.getFullYear()," - + " timestamp(75), int(@index11), timestamp(@index12), @index13.getMinutes()," - + " @index6.getSeconds(), @index6.getFullYear(), @index13.getFullYear(), @index3 +" - + " @index17, @index18 + @index16, @index19 + @index3, @index20 + @index15, @index21 +" - + " @index10, @index22 + @index10, @index23 + @index14, @index24 + @index3], @index25" - + " == 13934)"), - MAP_INDEX( - "{\"a\": 2}[\"a\"] + {\"a\": 2}[\"a\"] * {\"a\": 2}[\"a\"] == 6", - "cel.bind(@r0, {\"a\": 2}[\"a\"], @r0 + @r0 * @r0) == 6", - "cel.@block([{\"a\": 2}[\"a\"]], @index0 + @index0 * @index0 == 6)", - "cel.@block([{\"a\": 2}, @index0[\"a\"], @index1 * @index1, @index1 + @index2], @index3 ==" - + " 6)"), - /** - * Input map is: - * - *
{@code
-     * {
-     *    "a": { "b": 1 },
-     *    "c": { "b": 1 },
-     *    "d": {
-     *       "e": { "b": 1 }
-     *    },
-     *    "e":{
-     *       "e": { "b": 1 }
-     *    }
-     * }
-     * }
- */ - NESTED_MAP_CONSTRUCTION( - "size({'a': {'b': 1}, 'c': {'b': 1}, 'd': {'e': {'b': 1}}, 'e': {'e': {'b': 1}}}) == 4", - "size(cel.bind(@r0, {\"b\": 1}, cel.bind(@r1, {\"e\": @r0}, {\"a\": @r0, \"c\": @r0, \"d\":" - + " @r1, \"e\": @r1}))) == 4", - "cel.@block([{\"b\": 1}, {\"e\": @index0}], size({\"a\": @index0, \"c\": @index0, \"d\":" - + " @index1, \"e\": @index1}) == 4)", - "cel.@block([{\"b\": 1}, {\"e\": @index0}, {\"a\": @index0, \"c\": @index0, \"d\": @index1," - + " \"e\": @index1}, size(@index2)], @index3 == 4)"), - NESTED_LIST_CONSTRUCTION( - "size([1, [1,2,3,4], 2, [1,2,3,4], 5, [1,2,3,4], 7, [[1,2], [1,2,3,4]], [1,2]]) == 9", - "size(cel.bind(@r0, [1, 2, 3, 4], " - + "cel.bind(@r1, [1, 2], [1, @r0, 2, @r0, 5, @r0, 7, [@r1, @r0], @r1]))) == 9", - "cel.@block([[1, 2, 3, 4], [1, 2]], size([1, @index0, 2, @index0, 5, @index0, 7, [@index1," - + " @index0], @index1]) == 9)", - "cel.@block([[1, 2, 3, 4], [1, 2], [@index1, @index0], [1, @index0, 2, @index0, 5, @index0," - + " 7, @index2, @index1], size(@index3)], @index4 == 9)"), - SELECT( - "msg.single_int64 + msg.single_int64 == 6", - "cel.bind(@r0, msg.single_int64, @r0 + @r0) == 6", - "cel.@block([msg.single_int64], @index0 + @index0 == 6)", - "cel.@block([msg.single_int64, @index0 + @index0], @index1 == 6)"), - SELECT_NESTED( - "msg.oneof_type.payload.single_int64 + msg.oneof_type.payload.single_int32 + " - + "msg.oneof_type.payload.single_int64 + " - + "msg.single_int64 + msg.oneof_type.payload.oneof_type.payload.single_int64 == 31", - "cel.bind(@r0, msg.oneof_type.payload, " - + "cel.bind(@r1, @r0.single_int64, @r1 + @r0.single_int32 + @r1) + " - + "msg.single_int64 + @r0.oneof_type.payload.single_int64) == 31", - "cel.@block([msg.oneof_type.payload, @index0.single_int64], @index1 + @index0.single_int32" - + " + @index1 + msg.single_int64 + @index0.oneof_type.payload.single_int64 == 31)", - "cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, @index1.oneof_type," - + " @index3.payload, @index4.single_int64, msg.single_int64, @index1.single_int32," - + " @index2 + @index7, @index8 + @index2, @index9 + @index6, @index10 + @index5]," - + " @index11 == 31)"), - SELECT_NESTED_MESSAGE_MAP_INDEX_1( - "msg.oneof_type.payload.map_int32_int64[1] + " - + "msg.oneof_type.payload.map_int32_int64[1] + " - + "msg.oneof_type.payload.map_int32_int64[1] == 15", - "cel.bind(@r0, msg.oneof_type.payload.map_int32_int64[1], @r0 + @r0 + @r0) == 15", - "cel.@block([msg.oneof_type.payload.map_int32_int64[1]], @index0 + @index0 + @index0 ==" - + " 15)", - "cel.@block([msg.oneof_type, @index0.payload, @index1.map_int32_int64, @index2[1], @index3" - + " + @index3, @index4 + @index3], @index5 == 15)"), - SELECT_NESTED_MESSAGE_MAP_INDEX_2( - "msg.oneof_type.payload.map_int32_int64[0] + " - + "msg.oneof_type.payload.map_int32_int64[1] + " - + "msg.oneof_type.payload.map_int32_int64[2] == 8", - "cel.bind(@r0, msg.oneof_type.payload.map_int32_int64, @r0[0] + @r0[1] + @r0[2]) == 8", - "cel.@block([msg.oneof_type.payload.map_int32_int64], @index0[0] + @index0[1] + @index0[2]" - + " == 8)", - "cel.@block([msg.oneof_type, @index0.payload, @index1.map_int32_int64, @index2[2]," - + " @index2[1], @index2[0], @index5 + @index4, @index6 + @index3], @index7 == 8)"), - TERNARY( - "(msg.single_int64 > 0 ? msg.single_int64 : 0) == 3", - "cel.bind(@r0, msg.single_int64, (@r0 > 0) ? @r0 : 0) == 3", - "cel.@block([msg.single_int64], ((@index0 > 0) ? @index0 : 0) == 3)", - "cel.@block([msg.single_int64, @index0 > 0, @index1 ? @index0 : 0], @index2 == 3)"), - TERNARY_BIND_RHS_ONLY( - "false ? false : (msg.single_int64) + ((msg.single_int64 + 1) * 2) == 11", - "false ? false : (cel.bind(@r0, msg.single_int64, @r0 + (@r0 + 1) * 2) == 11)", - "cel.@block([msg.single_int64], false ? false : (@index0 + (@index0 + 1) * 2 == 11))", - "cel.@block([msg.single_int64, @index0 + 1, @index1 * 2, @index0 + @index2, @index3 == 11]," - + " false ? false : @index4)"), - NESTED_TERNARY( - "(msg.single_int64 > 0 ? (msg.single_int32 > 0 ? " - + "msg.single_int64 + msg.single_int32 : 0) : 0) == 8", - "cel.bind(@r0, msg.single_int64, (@r0 > 0) ? " - + "cel.bind(@r1, msg.single_int32, (@r1 > 0) ? (@r0 + @r1) : 0) : 0) == 8", - "cel.@block([msg.single_int64, msg.single_int32], ((@index0 > 0) ? ((@index1 > 0) ?" - + " (@index0 + @index1) : 0) : 0) == 8)", - "cel.@block([msg.single_int64, msg.single_int32, @index0 + @index1, @index1 > 0, @index3 ?" - + " @index2 : 0, @index0 > 0, @index5 ? @index4 : 0], @index6 == 8)"), - MULTIPLE_MACROS_1( - // Note that all of these have different iteration variables, but they are still logically - // the same. - "size([[1].exists(i, i > 0)]) + size([[1].exists(j, j > 0)]) + " - + "size([[2].exists(k, k > 1)]) + size([[2].exists(l, l > 1)]) == 4", - "cel.bind(@r1, size([[2].exists(@c0:0, @c0:0 > 1)]), " - + "cel.bind(@r0, size([[1].exists(@c0:0, @c0:0 > 0)]), @r0 + @r0) + @r1 + @r1) == 4", - "cel.@block([size([[1].exists(@c0:0, @c0:0 > 0)]), size([[2].exists(@c0:0, @c0:0 > 1)])]," - + " @index0 + @index0 + @index1 + @index1 == 4)", - "cel.@block([[1], @c0:0 > 0, @x0:0 || @index1, [2], @c0:0 > 1, @x0:0 || @index4]," - + " size([@index0.exists(@c0:0, @index1)]) + size([@index0.exists(@c0:0, @index1)]) +" - + " size([@index3.exists(@c0:0, @index4)]) + size([@index3.exists(@c0:0, @index4)]) ==" - + " 4)"), - MULTIPLE_MACROS_2( - "[[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == 'a')] +" - + " [['a'].exists(l, l == 'a')] == [true, true, true, true]", - "cel.bind(@r1, [[\"a\"].exists(@c0:1, @c0:1 == \"a\")], cel.bind(@r0, [[1].exists(@c0:0," - + " @c0:0 > 0)], @r0 + @r0) + @r1 + @r1) == [true, true, true, true]", - "cel.@block([[[1].exists(@c0:0, @c0:0 > 0)], [[\"a\"].exists(@c0:1, @c0:1 == \"a\")]]," - + " @index0 + @index0 + @index1 + @index1 == [true, true, true, true])", - "cel.@block([[1], @c0:0 > 0, @x0:0 || @index1, [\"a\"], @c0:1 == \"a\", @x0:1 || @index4," - + " [true, true, true, true]], [@index0.exists(@c0:0, @index1)] +" - + " [@index0.exists(@c0:0, @index1)] + [@index3.exists(@c0:1, @index4)] +" - + " [@index3.exists(@c0:1, @index4)] == @index6)"), - NESTED_MACROS( - "[1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [[2, 3, 4], [2, 3, 4], [2, 3, 4]]", - "cel.bind(@r0, [1, 2, 3], @r0.map(@c0:0, @r0.map(@c1:0, @c1:0 + 1))) == " - + "cel.bind(@r1, [2, 3, 4], [@r1, @r1, @r1])", - "cel.@block([[1, 2, 3], [2, 3, 4]], @index0.map(@c0:0, @index0.map(@c1:0, @c1:0 + 1)) ==" - + " [@index1, @index1, @index1])", - "cel.@block([[1, 2, 3], [2, 3, 4], [@index1, @index1, @index1], @c1:0 + 1, [@index3], @x1:0" - + " + @index4], @index0.map(@c0:0, @index0.map(@c1:0, @index3)) == @index2)"), - NESTED_MACROS_2( - "[1, 2].map(y, [1, 2, 3].filter(x, x == y)) == [[1], [2]]", - "[1, 2].map(@c0:0, [1, 2, 3].filter(@c1:0, @c1:0 == @c0:0)) == [[1], [2]]", - "[1, 2].map(@c0:0, [1, 2, 3].filter(@c1:0, @c1:0 == @c0:0)) == [[1], [2]]", - "cel.@block([[2], [1], [@index1, @index0], [@c1:0], @x1:0 + @index3, @c1:0 == @c0:0," - + " @index5 ? @index4 : @x1:0, [1, 2, 3], [1, 2]], @index8.map(@c0:0," - + " @index7.filter(@c1:0, @index5)) == @index2)"), - INCLUSION_LIST( - "1 in [1,2,3] && 2 in [1,2,3] && 3 in [3, [1,2,3]] && 1 in [1,2,3]", - "cel.bind(@r0, [1, 2, 3], cel.bind(@r1, 1 in @r0, @r1 && 2 in @r0 && 3 in [3, @r0] &&" - + " @r1))", - "cel.@block([[1, 2, 3], 1 in @index0], @index1 && 2 in @index0 && 3 in [3, @index0] &&" - + " @index1)", - "cel.@block([[1, 2, 3], 1 in @index0, [3, @index0], 3 in @index2, @index3 && @index1, 2 in" - + " @index0, @index1 && @index5], @index6 && @index4)"), - INCLUSION_MAP( - "2 in {'a': 1, 2: {true: false}, 3: {true: false}}", - "2 in cel.bind(@r0, {true: false}, {\"a\": 1, 2: @r0, 3: @r0})", - "cel.@block([{true: false}], 2 in {\"a\": 1, 2: @index0, 3: @index0})", - "cel.@block([{true: false}, {\"a\": 1, 2: @index0, 3: @index0}], 2 in @index1)"), - MACRO_ITER_VAR_NOT_REFERENCED( - "[1,2].map(i, [1, 2].map(i, [3,4])) == [[[3, 4], [3, 4]], [[3, 4], [3, 4]]]", - "cel.bind(@r1, [3, 4], cel.bind(@r0, [1, 2], @r0.map(@c0:0, @r0.map(@c1:0, @r1))) ==" - + " cel.bind(@r2, [@r1, @r1], [@r2, @r2]))", - "cel.@block([[1, 2], [3, 4], [@index1, @index1]], @index0.map(@c0:0, @index0.map(@c1:0," - + " @index1)) == [@index2, @index2])", - "cel.@block([[1, 2], [3, 4], [@index1, @index1], [@index2, @index2], [@index1], @x1:0 +" - + " @index4], @index0.map(@c0:0, @index0.map(@c1:0, @index1)) == @index3)"), - MACRO_SHADOWED_VARIABLE( - "[x - 1 > 3 ? x - 1 : 5].exists(x, x - 1 > 3) || x - 1 > 3", - "cel.bind(@r0, x - 1, cel.bind(@r1, @r0 > 3, [@r1 ? @r0 : 5].exists(@c0:0, @c0:0 - 1 > 3)" - + " || @r1))", - "cel.@block([x - 1, @index0 > 3], [@index1 ? @index0 : 5].exists(@c0:0, @c0:0 - 1 > 3) ||" - + " @index1)", - "cel.@block([x - 1, @index0 > 3, @c0:0 - 1, @index2 > 3, @x0:0 || @index3, @index1 ?" - + " @index0 : 5, [@index5]], @index6.exists(@c0:0, @index3) || @index1)"), - MACRO_SHADOWED_VARIABLE_2( - "size([\"foo\", \"bar\"].map(x, [x + x, x + x]).map(x, [x + x, x + x])) == 2", - "size([\"foo\", \"bar\"].map(@c1:0, cel.bind(@r0, @c1:0 + @c1:0, [@r0, @r0]))" - + ".map(@c0:0, cel.bind(@r1, @c0:0 + @c0:0, [@r1, @r1]))) == 2", - "cel.@block([@c1:0 + @c1:0, @c0:0 + @c0:0], size([\"foo\", \"bar\"].map(@c1:0, [@index0," - + " @index0]).map(@c0:0, [@index1, @index1])) == 2)", - "cel.@block([@c1:0 + @c1:0, @c0:0 + @c0:0, [@index1, @index1], [@index2], @x0:0 + @index3," - + " [@index0, @index0], [@index5], @x1:0 + @index6, [\"foo\", \"bar\"]]," - + " size(@index8.map(@c1:0, @index5).map(@c0:0, @index2)) == 2)"), - PRESENCE_TEST( - "has({'a': true}.a) && {'a':true}['a']", - "cel.bind(@r0, {\"a\": true}, has(@r0.a) && @r0[\"a\"])", - "cel.@block([{\"a\": true}], has(@index0.a) && @index0[\"a\"])", - "cel.@block([{\"a\": true}, @index0[\"a\"]], has(@index0.a) && @index1)"), - PRESENCE_TEST_WITH_TERNARY( - "(has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : 0) == 10", - "cel.bind(@r0, msg.oneof_type, has(@r0.payload) ? @r0.payload.single_int64 : 0) == 10", - "cel.@block([msg.oneof_type], (has(@index0.payload) ? @index0.payload.single_int64 : 0) ==" - + " 10)", - "cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64], (has(@index0.payload)" - + " ? @index2 : 0) == 10)"), - PRESENCE_TEST_WITH_TERNARY_2( - "(has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 :" - + " msg.oneof_type.payload.single_int64 * 0) == 10", - "cel.bind(@r0, msg.oneof_type, cel.bind(@r1, @r0.payload.single_int64, has(@r0.payload) ?" - + " @r1 : (@r1 * 0))) == 10", - "cel.@block([msg.oneof_type, @index0.payload.single_int64], (has(@index0.payload) ? @index1" - + " : (@index1 * 0)) == 10)", - "cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, @index2 * 0]," - + " (has(@index0.payload) ? @index2 : @index3) == 10)"), - PRESENCE_TEST_WITH_TERNARY_3( - "(has(msg.oneof_type.payload.single_int64) ? msg.oneof_type.payload.single_int64 :" - + " msg.oneof_type.payload.single_int64 * 0) == 10", - "cel.bind(@r0, msg.oneof_type.payload, cel.bind(@r1, @r0.single_int64," - + " has(@r0.single_int64) ? @r1 : (@r1 * 0))) == 10", - "cel.@block([msg.oneof_type.payload, @index0.single_int64], (has(@index0.single_int64) ?" - + " @index1 : (@index1 * 0)) == 10)", - "cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, @index2 * 0]," - + " (has(@index1.single_int64) ? @index2 : @index3) == 10)"), - /** - * Input: - * - *
{@code
-     * (
-     *   has(msg.oneof_type) &&
-     *   has(msg.oneof_type.payload) &&
-     *   has(msg.oneof_type.payload.single_int64)
-     * ) ?
-     *   (
-     *     (
-     *       has(msg.oneof_type.payload.map_string_string) &&
-     *       has(msg.oneof_type.payload.map_string_string.key)
-     *     ) ?
-     *       msg.oneof_type.payload.map_string_string.key == "A"
-     *     : false
-     *   )
-     * : false
-     * }
- * - * Unparsed: - * - *
{@code
-     * // With binds
-     * cel.bind(
-     *   @r0, msg.oneof_type,
-     *   cel.bind(
-     *     @r1, @r0.payload,
-     *     has(msg.oneof_type) && has(@r0.payload) && has(@r1.single_int64) ?
-     *       cel.bind(
-     *         @r2, @r1.map_string_string,
-     *         has(@r1.map_string_string) && has(@r2.key) ? @r2.key == "A" : false,
-     *       )
-     *     : false,
-     *   ),
-     * )
-     * }
- *
{@code
-     * // With block
-     * cel.@block(
-     *   [
-     *     msg.oneof_type,
-     *     @index0.payload,
-     *     @index1.map_string_string
-     *   ],
-     *   (has(msg.oneof_type) && has(@index0.payload) && has(@index1.single_int64)) ?
-     *     (
-     *       (has(@index1.map_string_string) && has(@index2.key)) ?
-     *         (@index2.key == "A") : false
-     *     )
-     *     : false
-     *   )
-     * }
- */ - PRESENCE_TEST_WITH_TERNARY_NESTED( - "(has(msg.oneof_type) && has(msg.oneof_type.payload) &&" - + " has(msg.oneof_type.payload.single_int64)) ?" - + " ((has(msg.oneof_type.payload.map_string_string) &&" - + " has(msg.oneof_type.payload.map_string_string.key)) ?" - + " msg.oneof_type.payload.map_string_string.key == 'A' : false) : false", - "cel.bind(@r0, msg.oneof_type, cel.bind(@r1, @r0.payload, (has(msg.oneof_type) &&" - + " has(@r0.payload) && has(@r1.single_int64)) ? cel.bind(@r2, @r1.map_string_string," - + " (has(@r1.map_string_string) && has(@r2.key)) ? (@r2.key == \"A\") : false) :" - + " false))", - "cel.@block([msg.oneof_type, @index0.payload, @index1.map_string_string]," - + " (has(msg.oneof_type) && has(@index0.payload) && has(@index1.single_int64)) ?" - + " ((has(@index1.map_string_string) && has(@index2.key)) ? (@index2.key == \"A\") :" - + " false) : false)", - "cel.@block([msg.oneof_type, @index0.payload, @index1.map_string_string, @index2.key," - + " @index3 == \"A\"], (has(msg.oneof_type) && has(@index0.payload) &&" - + " has(@index1.single_int64)) ? ((has(@index1.map_string_string) && has(@index2.key))" - + " ? @index4 : false) : false)"), - OPTIONAL_LIST( - "[10, ?optional.none(), [?optional.none(), ?opt_x], [?optional.none(), ?opt_x]] == [10," - + " [5], [5]]", - "cel.bind(@r0, optional.none(), cel.bind(@r1, [?@r0, ?opt_x], [10, ?@r0, @r1, @r1])) ==" - + " cel.bind(@r2, [5], [10, @r2, @r2])", - "cel.@block([optional.none(), [?@index0, ?opt_x], [5]], [10, ?@index0, @index1, @index1] ==" - + " [10, @index2, @index2])", - "cel.@block([optional.none(), [?@index0, ?opt_x], [5], [10, @index2, @index2], [10," - + " ?@index0, @index1, @index1]], @index4 == @index3)"), - OPTIONAL_MAP( - "{?'hello': optional.of('hello')}['hello'] + {?'hello': optional.of('hello')}['hello'] ==" - + " 'hellohello'", - "cel.bind(@r0, {?\"hello\": optional.of(\"hello\")}[\"hello\"], @r0 + @r0) ==" - + " \"hellohello\"", - "cel.@block([{?\"hello\": optional.of(\"hello\")}[\"hello\"]], @index0 + @index0 ==" - + " \"hellohello\")", - "cel.@block([optional.of(\"hello\"), {?\"hello\": @index0}, @index1[\"hello\"], @index2 +" - + " @index2], @index3 == \"hellohello\")"), - OPTIONAL_MAP_CHAINED( - "{?'key': optional.of('test')}[?'bogus'].or({'key': 'test'}[?'bogus']).orValue({'key':" - + " 'test'}['key']) == 'test'", - "cel.bind(@r0, {\"key\": \"test\"}, {?\"key\":" - + " optional.of(\"test\")}[?\"bogus\"].or(@r0[?\"bogus\"]).orValue(@r0[\"key\"])) ==" - + " \"test\"", - "cel.@block([{\"key\": \"test\"}], {?\"key\":" - + " optional.of(\"test\")}[?\"bogus\"].or(@index0[?\"bogus\"]).orValue(@index0[\"key\"])" - + " == \"test\")", - "cel.@block([{\"key\": \"test\"}, @index0[\"key\"], @index0[?\"bogus\"]," - + " optional.of(\"test\"), {?\"key\": @index3}, @index4[?\"bogus\"]," - + " @index5.or(@index2), @index6.orValue(@index1)], @index7 == \"test\")"), - OPTIONAL_MESSAGE( - "TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32:" - + " optional.of(4)}.single_int32 + TestAllTypes{?single_int64:" - + " optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}.single_int64 == 5", - "cel.bind(@r0, TestAllTypes{" - + "?single_int64: optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}, " - + "@r0.single_int32 + @r0.single_int64) == 5", - "cel.@block([TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32:" - + " optional.of(4)}], @index0.single_int32 + @index0.single_int64 == 5)", - "cel.@block([optional.ofNonZeroValue(1), optional.of(4), TestAllTypes{?single_int64:" - + " @index0, ?single_int32: @index1}, @index2.single_int64, @index2.single_int32," - + " @index4 + @index3], @index5 == 5)"), - ; - - private final String source; - private final String unparsedBind; - private final String unparsedBlock; - private final String unparsedBlockFlattened; - - CseTestCase( - String source, String unparsedBind, String unparsedBlock, String unparsedBlockFlattened) { - this.source = source; - this.unparsedBind = unparsedBind; - this.unparsedBlock = unparsedBlock; - this.unparsedBlockFlattened = unparsedBlockFlattened; - } - } - - @Test - public void cse_withCelBind_macroMapPopulated(@TestParameter CseTestCase testCase) - throws Exception { - CelAbstractSyntaxTree ast = CEL.compile(testCase.source).getAst(); - - CelAbstractSyntaxTree optimizedAst = - newCseOptimizer( - SubexpressionOptimizerOptions.newBuilder() - .populateMacroCalls(true) - .enableCelBlock(false) - .build()) - .optimize(ast); - - assertThat( - CEL.createProgram(optimizedAst) - .eval( - ImmutableMap.of( - "msg", TEST_ALL_TYPES_INPUT, "x", 5L, "opt_x", Optional.of(5L)))) - .isEqualTo(true); - assertThat(CEL_UNPARSER.unparse(optimizedAst)).isEqualTo(testCase.unparsedBind); - } - - @Test - public void cse_withCelBind_macroMapUnpopulated(@TestParameter CseTestCase testCase) - throws Exception { - CelBuilder celWithoutMacroMap = - newCelBuilder().setOptions(CelOptions.current().enableTimestampEpoch(true).build()); - CelAbstractSyntaxTree ast = celWithoutMacroMap.build().compile(testCase.source).getAst(); - - CelAbstractSyntaxTree optimizedAst = - newCseOptimizer( - SubexpressionOptimizerOptions.newBuilder().populateMacroCalls(false).build()) - .optimize(ast); - - assertThat(optimizedAst.getSource().getMacroCalls()).isEmpty(); - assertThat( - celWithoutMacroMap - .build() - .createProgram(optimizedAst) - .eval( - ImmutableMap.of( - "msg", TEST_ALL_TYPES_INPUT, "x", 5L, "opt_x", Optional.of(5L)))) - .isEqualTo(true); - } - - @Test - public void cse_withCelBlock_macroMapPopulated(@TestParameter CseTestCase testCase) - throws Exception { - CelOptimizer celOptimizer = - newCseOptimizer( - SubexpressionOptimizerOptions.newBuilder() - .populateMacroCalls(true) - .enableCelBlock(true) - .build()); - CelAbstractSyntaxTree ast = CEL.compile(testCase.source).getAst(); - - CelAbstractSyntaxTree optimizedAst = celOptimizer.optimize(ast); - - assertThat( - CEL.createProgram(optimizedAst) - .eval( - ImmutableMap.of( - "msg", TEST_ALL_TYPES_INPUT, "x", 5L, "opt_x", Optional.of(5L)))) - .isEqualTo(true); - assertThat(CEL_UNPARSER.unparse(optimizedAst)).isEqualTo(testCase.unparsedBlock); - } - - @Test - public void cse_withCelBlock_macroMapUnpopulated(@TestParameter CseTestCase testCase) - throws Exception { - CelOptimizer celOptimizer = - newCseOptimizer( - SubexpressionOptimizerOptions.newBuilder() - .populateMacroCalls(false) - .enableCelBlock(true) - .build()); - CelAbstractSyntaxTree ast = CEL.compile(testCase.source).getAst(); - - CelAbstractSyntaxTree optimizedAst = celOptimizer.optimize(ast); - - assertThat(optimizedAst.getSource().getMacroCalls()).isEmpty(); - assertThat( - CEL.createProgram(optimizedAst) - .eval( - ImmutableMap.of( - "msg", TEST_ALL_TYPES_INPUT, "x", 5L, "opt_x", Optional.of(5L)))) - .isEqualTo(true); - } - - @Test - public void cse_withCelBlockFlattened_macroMapPopulated(@TestParameter CseTestCase testCase) - throws Exception { - CelOptimizer celOptimizer = - newCseOptimizer( - SubexpressionOptimizerOptions.newBuilder() - .populateMacroCalls(true) - .enableCelBlock(true) - .subexpressionMaxRecursionDepth(1) - .build()); - CelAbstractSyntaxTree ast = CEL.compile(testCase.source).getAst(); - - CelAbstractSyntaxTree optimizedAst = celOptimizer.optimize(ast); - - assertThat( - CEL.createProgram(optimizedAst) - .eval( - ImmutableMap.of( - "msg", TEST_ALL_TYPES_INPUT, "x", 5L, "opt_x", Optional.of(5L)))) - .isEqualTo(true); - assertThat(CEL_UNPARSER.unparse(optimizedAst)).isEqualTo(testCase.unparsedBlockFlattened); - } - - @Test - public void cse_withVariousRecursionDepths_macroMapUnpopulated( - @TestParameter CseTestCase testCase, - @TestParameter({"1", "2", "3", "4", "5", "6", "7", "8", "9", "10"}) Integer maxRecursionDepth) - throws Exception { - CelOptimizer celOptimizer = - newCseOptimizer( - SubexpressionOptimizerOptions.newBuilder() - .populateMacroCalls(false) - .enableCelBlock(true) - .subexpressionMaxRecursionDepth(maxRecursionDepth) - .build()); - CelAbstractSyntaxTree ast = CEL.compile(testCase.source).getAst(); - - CelAbstractSyntaxTree optimizedAst = celOptimizer.optimize(ast); - - assertThat(optimizedAst.getSource().getMacroCalls()).isEmpty(); - assertThat( - CEL.createProgram(optimizedAst) - .eval( - ImmutableMap.of( - "msg", TEST_ALL_TYPES_INPUT, "x", 5L, "opt_x", Optional.of(5L)))) - .isEqualTo(true); - } - - @Test - @TestParameters( - "{recursionDepth: 0, unparsed: 'true ||" - + " msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload.single_int64" - + " == 1'}") - @TestParameters( - "{recursionDepth: 1, unparsed: 'cel.@block([msg.oneof_type, @index0.payload," - + " @index1.oneof_type, @index2.payload, @index3.oneof_type, @index4.payload," - + " @index5.oneof_type, @index6.payload, @index7.single_int64, @index8 == 1], true ||" - + " @index9)'}") - @TestParameters( - "{recursionDepth: 2, unparsed: 'cel.@block([msg.oneof_type.payload," - + " @index0.oneof_type.payload, @index1.oneof_type.payload, @index2.oneof_type.payload," - + " @index3.single_int64 == 1], true || @index4)'}") - @TestParameters( - "{recursionDepth: 3, unparsed: 'cel.@block([msg.oneof_type.payload.oneof_type," - + " @index0.payload.oneof_type.payload, @index1.oneof_type.payload.single_int64, @index2" - + " == 1], true || @index3)'}") - @TestParameters( - "{recursionDepth: 4, unparsed: 'cel.@block([msg.oneof_type.payload.oneof_type.payload," - + " @index0.oneof_type.payload.oneof_type.payload, @index1.single_int64 == 1], true ||" - + " @index2)'}") - @TestParameters( - "{recursionDepth: 5, unparsed:" - + " 'cel.@block([msg.oneof_type.payload.oneof_type.payload.oneof_type," - + " @index0.payload.oneof_type.payload.single_int64 == 1], true || @index1)'}") - @TestParameters( - "{recursionDepth: 6, unparsed:" - + " 'cel.@block([msg.oneof_type.payload.oneof_type.payload.oneof_type.payload," - + " @index0.oneof_type.payload.single_int64 == 1], true || @index1)'}") - @TestParameters( - "{recursionDepth: 7, unparsed:" - + " 'cel.@block([msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type," - + " @index0.payload.single_int64 == 1], true || @index1)'}") - @TestParameters( - "{recursionDepth: 8, unparsed:" - + " 'cel.@block([msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload," - + " @index0.single_int64 == 1], true || @index1)'}") - @TestParameters( - "{recursionDepth: 9, unparsed:" - + " 'cel.@block([msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload.single_int64," - + " @index0 == 1], true || @index1)'}") - @TestParameters( - "{recursionDepth: 10, unparsed:" - + " 'cel.@block([msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload.single_int64" - + " == 1], true || @index0)'}") - public void noCommonSubexpr_withRecursionDepth_deeplyNestedSelect( - int recursionDepth, String unparsed) throws Exception { - String expression = - "true ||" - + " msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload.single_int64" - + " == 1"; - CelOptimizer celOptimizer = - newCseOptimizer( - SubexpressionOptimizerOptions.newBuilder() - .populateMacroCalls(true) - .enableCelBlock(true) - .subexpressionMaxRecursionDepth(recursionDepth) - .build()); - CelAbstractSyntaxTree ast = CEL.compile(expression).getAst(); - - CelAbstractSyntaxTree optimizedAst = celOptimizer.optimize(ast); - - assertThat(CEL.createProgram(optimizedAst).eval()).isEqualTo(true); - assertThat(CEL_UNPARSER.unparse(optimizedAst)).isEqualTo(unparsed); - } - - @Test - @TestParameters( - "{recursionDepth: 1, unparsed: 'cel.@block([msg.oneof_type, @index0.payload," - + " @index1.oneof_type, @index2.payload, @index3.oneof_type, @index4.child," - + " @index5.child, @index6.payload, @index7.single_bool, @index4.payload," - + " @index9.oneof_type, @index10.payload, @index11.single_bool, true || @index12]," - + " @index13 || @index8)'}") - @TestParameters( - "{recursionDepth: 2, unparsed: 'cel.@block([msg.oneof_type, @index0.payload," - + " @index1.oneof_type, @index2.payload, @index3.oneof_type, @index4.child.child," - + " @index5.payload.single_bool, @index4.payload.oneof_type, @index7.payload.single_bool," - + " true || @index8], @index9 || @index6)'}") - @TestParameters( - "{recursionDepth: 3, unparsed: 'cel.@block([msg.oneof_type, @index0.payload," - + " @index1.oneof_type, @index2.payload, @index3.oneof_type, @index4.child.child.payload," - + " @index5.single_bool, @index4.payload.oneof_type.payload, true ||" - + " @index7.single_bool], @index8 || @index6)'}") - @TestParameters( - "{recursionDepth: 4, unparsed: 'cel.@block([msg.oneof_type, @index0.payload," - + " @index1.oneof_type, @index2.payload, @index3.oneof_type," - + " @index4.child.child.payload.single_bool," - + " @index4.payload.oneof_type.payload.single_bool, true || @index6], @index7 ||" - + " @index5)'}") - public void cse_withRecursionDepth_deeplyNestedSelect(int recursionDepth, String unparsed) - throws Exception { - String expression = - "true ||" - + " msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload.single_bool" - + " || msg.oneof_type.payload.oneof_type.payload.oneof_type.child.child.payload.single_bool"; - CelOptimizer celOptimizer = - newCseOptimizer( - SubexpressionOptimizerOptions.newBuilder() - .populateMacroCalls(true) - .enableCelBlock(true) - .subexpressionMaxRecursionDepth(recursionDepth) - .build()); - CelAbstractSyntaxTree ast = CEL.compile(expression).getAst(); - - CelAbstractSyntaxTree optimizedAst = celOptimizer.optimize(ast); - - assertThat(CEL.createProgram(optimizedAst).eval()).isEqualTo(true); - assertThat(CEL_UNPARSER.unparse(optimizedAst)).isEqualTo(unparsed); - } - - @Test - @TestParameters( - "{recursionDepth: 0, unparsed: '\"hello world\".matches(\"h\" + \"e\" + \"l\" + \"l\" +" - + " \"o\") == true'}") - @TestParameters( - "{recursionDepth: 1, unparsed: 'cel.@block([\"h\" + \"e\", @index0 + \"l\", @index1 + \"l\"," - + " @index2 + \"o\", \"hello world\".matches(@index3)], @index4 == true)'}") - @TestParameters( - "{recursionDepth: 2, unparsed: 'cel.@block([\"h\" + \"e\" + \"l\", @index0 + \"l\" + \"o\"," - + " \"hello world\".matches(@index1)], @index2 == true)'}") - @TestParameters( - "{recursionDepth: 3, unparsed: 'cel.@block([\"h\" + \"e\" + \"l\" + \"l\", \"hello" - + " world\".matches(@index0 + \"o\")], @index1 == true)'}") - @TestParameters( - "{recursionDepth: 4, unparsed: 'cel.@block([\"h\" + \"e\" + \"l\" + \"l\" + \"o\", \"hello" - + " world\".matches(@index0)], @index1 == true)'}") - @TestParameters( - "{recursionDepth: 5, unparsed: 'cel.@block([\"hello world\".matches(\"h\" + \"e\" + \"l\" +" - + " \"l\" + \"o\")], @index0 == true)'}") - public void noCommonSubexpr_withRecursionDepth_deeplyNestedCallOnArgs( - int recursionDepth, String unparsed) throws Exception { - String expression = "'hello world'.matches('h' + 'e' + 'l' + 'l' + 'o') == true"; - CelOptimizer celOptimizer = - newCseOptimizer( - SubexpressionOptimizerOptions.newBuilder() - .populateMacroCalls(true) - .enableCelBlock(true) - .subexpressionMaxRecursionDepth(recursionDepth) - .build()); - CelAbstractSyntaxTree ast = CEL.compile(expression).getAst(); - - CelAbstractSyntaxTree optimizedAst = celOptimizer.optimize(ast); - - assertThat(CEL.createProgram(optimizedAst).eval()).isEqualTo(true); - assertThat(CEL_UNPARSER.unparse(optimizedAst)).isEqualTo(unparsed); - } - - @Test - @TestParameters( - "{recursionDepth: 0, unparsed: '(\"h\" + \"e\" + \"l\" + \"l\" + \"o\" + \"" - + " world\").matches(\"hello\") == true'}") - @TestParameters( - "{recursionDepth: 1, unparsed: 'cel.@block([\"h\" + \"e\", @index0 + \"l\", @index1 + \"l\"," - + " @index2 + \"o\", @index3 + \" world\", @index4.matches(\"hello\")], @index5 ==" - + " true)'}") - @TestParameters( - "{recursionDepth: 2, unparsed: 'cel.@block([\"h\" + \"e\" + \"l\", @index0 + \"l\" + \"o\"," - + " (@index1 + \" world\").matches(\"hello\")], @index2 == true)'}") - @TestParameters( - "{recursionDepth: 3, unparsed: 'cel.@block([\"h\" + \"e\" + \"l\" + \"l\", (@index0 + \"o\" +" - + " \" world\").matches(\"hello\")], @index1 == true)'}") - @TestParameters( - "{recursionDepth: 4, unparsed: 'cel.@block([\"h\" + \"e\" + \"l\" + \"l\" + \"o\", (@index0 +" - + " \" world\").matches(\"hello\")], @index1 == true)'}") - @TestParameters( - "{recursionDepth: 5, unparsed: 'cel.@block([\"h\" + \"e\" + \"l\" + \"l\" + \"o\" + \"" - + " world\", @index0.matches(\"hello\")], @index1 == true)'}") - @TestParameters( - "{recursionDepth: 6, unparsed: 'cel.@block([(\"h\" + \"e\" + \"l\" + \"l\" + \"o\" + \"" - + " world\").matches(\"hello\")], @index0 == true)'}") - public void noCommonSubexpr_withRecursionDepth_deeplyNestedCallOnTarget( - int recursionDepth, String unparsed) throws Exception { - String expression = "('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('hello') == true"; - CelOptimizer celOptimizer = - newCseOptimizer( - SubexpressionOptimizerOptions.newBuilder() - .populateMacroCalls(true) - .enableCelBlock(true) - .subexpressionMaxRecursionDepth(recursionDepth) - .build()); - CelAbstractSyntaxTree ast = CEL.compile(expression).getAst(); - - CelAbstractSyntaxTree optimizedAst = celOptimizer.optimize(ast); - - assertThat(CEL.createProgram(optimizedAst).eval()).isEqualTo(true); - assertThat(CEL_UNPARSER.unparse(optimizedAst)).isEqualTo(unparsed); - } - - @Test - @TestParameters( - "{recursionDepth: 1, unparsed: 'cel.@block([\"w\" + \"o\", @index0 + \"r\", @index1 + \"l\"," - + " @index2 + \"d\", \"h\" + \"e\", @index4 + \"l\", @index5 + \"l\", @index6 + \"o\"," - + " @index7 + \" world\", @index8.matches(@index3)], @index9 == true)'}") - @TestParameters( - "{recursionDepth: 2, unparsed: 'cel.@block([\"w\" + \"o\" + \"r\", @index0 + \"l\" + \"d\"," - + " \"h\" + \"e\" + \"l\", @index2 + \"l\" + \"o\", (@index3 + \"" - + " world\").matches(@index1)], @index4 == true)'}") - @TestParameters( - "{recursionDepth: 3, unparsed: 'cel.@block([\"w\" + \"o\" + \"r\" + \"l\", @index0 + \"d\"," - + " \"h\" + \"e\" + \"l\" + \"l\", (@index2 + \"o\" + \" world\").matches(@index1)]," - + " @index3 == true)'}") - @TestParameters( - "{recursionDepth: 4, unparsed: 'cel.@block([\"w\" + \"o\" + \"r\" + \"l\" + \"d\", \"h\" +" - + " \"e\" + \"l\" + \"l\" + \"o\", (@index1 + \" world\").matches(@index0)], @index2 ==" - + " true)'}") - @TestParameters( - "{recursionDepth: 5, unparsed: 'cel.@block([\"w\" + \"o\" + \"r\" + \"l\" + \"d\", \"h\" +" - + " \"e\" + \"l\" + \"l\" + \"o\" + \" world\", @index1.matches(@index0)], @index2 ==" - + " true)'}") - @TestParameters( - "{recursionDepth: 6, unparsed: 'cel.@block([(\"h\" + \"e\" + \"l\" + \"l\" + \"o\" + \"" - + " world\").matches(\"w\" + \"o\" + \"r\" + \"l\" + \"d\")], @index0 == true)'}") - public void noCommonSubexpr_withRecursionDepth_deeplyNestedCallOnBothTargetAndArgs( - int recursionDepth, String unparsed) throws Exception { - String expression = - "('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('w' + 'o' + 'r' + 'l' + 'd') == true"; - CelOptimizer celOptimizer = - newCseOptimizer( - SubexpressionOptimizerOptions.newBuilder() - .populateMacroCalls(true) - .enableCelBlock(true) - .subexpressionMaxRecursionDepth(recursionDepth) - .build()); - CelAbstractSyntaxTree ast = CEL.compile(expression).getAst(); - - CelAbstractSyntaxTree optimizedAst = celOptimizer.optimize(ast); - - assertThat(CEL.createProgram(optimizedAst).eval()).isEqualTo(true); - assertThat(CEL_UNPARSER.unparse(optimizedAst)).isEqualTo(unparsed); - } - @Test public void cse_resultTypeSet_celBlockOptimizationSuccess() throws Exception { Cel cel = newCelBuilder().setResultType(SimpleType.BOOL).build(); @@ -1193,229 +204,6 @@ public void cse_withCelBlock_noop(@TestParameter CseNoOpTestCase testCase) throw assertThat(CEL_UNPARSER.unparse(optimizedAst)).isEqualTo(testCase.source); } - @Test - public void cse_largeCalcExpr() throws Exception { - StringBuilder sb = new StringBuilder(); - int limit = 40; - for (int i = 0; i < limit; i++) { - sb.append("size([1]) + "); - sb.append("size([1,2]) + "); - sb.append("size([1,2,3]) +"); - sb.append("size([1,2,3,4])"); - if (i < limit - 1) { - sb.append("+"); - } - } - CelAbstractSyntaxTree ast = CEL.compile(sb.toString()).getAst(); - - CelAbstractSyntaxTree optimizedAst = - newCseOptimizer( - SubexpressionOptimizerOptions.newBuilder() - .populateMacroCalls(true) - .enableCelBlock(false) - .build()) - .optimize(ast); - - assertThat(CEL_UNPARSER.unparse(optimizedAst)) - .isEqualTo( - "cel.bind(@r3, size([1, 2, 3, 4]), cel.bind(@r2, size([1, 2, 3]), cel.bind(@r1," - + " size([1, 2]), cel.bind(@r0, size([1]), @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2" - + " + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 +" - + " @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 +" - + " @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 +" - + " @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 +" - + " @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 +" - + " @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 +" - + " @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 +" - + " @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 +" - + " @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 +" - + " @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 +" - + " @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 +" - + " @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0) + @r1) + @r2) + @r3)"); - assertThat(CEL.createProgram(optimizedAst).eval()).isEqualTo(400L); - } - - @Test - public void cse_largeNestedBinds() throws Exception { - StringBuilder sb = new StringBuilder(); - int limit = 50; - for (int i = 0; i < limit; i++) { - sb.append(String.format("size([%d, %d]) + ", i, i + 1)); - sb.append(String.format("size([%d, %d]) ", i, i + 1)); - if (i < limit - 1) { - sb.append("+"); - } - } - CelAbstractSyntaxTree ast = CEL.compile(sb.toString()).getAst(); - - CelAbstractSyntaxTree optimizedAst = - newCseOptimizer( - SubexpressionOptimizerOptions.newBuilder() - .populateMacroCalls(true) - .enableCelBlock(false) - .build()) - .optimize(ast); - - assertThat(CEL_UNPARSER.unparse(optimizedAst)) - .isEqualTo( - "cel.bind(@r49, size([49, 50]), cel.bind(@r48, size([48, 49]), cel.bind(@r47, size([47," - + " 48]), cel.bind(@r46, size([46, 47]), cel.bind(@r45, size([45, 46])," - + " cel.bind(@r44, size([44, 45]), cel.bind(@r43, size([43, 44]), cel.bind(@r42," - + " size([42, 43]), cel.bind(@r41, size([41, 42]), cel.bind(@r40, size([40, 41])," - + " cel.bind(@r39, size([39, 40]), cel.bind(@r38, size([38, 39]), cel.bind(@r37," - + " size([37, 38]), cel.bind(@r36, size([36, 37]), cel.bind(@r35, size([35, 36])," - + " cel.bind(@r34, size([34, 35]), cel.bind(@r33, size([33, 34]), cel.bind(@r32," - + " size([32, 33]), cel.bind(@r31, size([31, 32]), cel.bind(@r30, size([30, 31])," - + " cel.bind(@r29, size([29, 30]), cel.bind(@r28, size([28, 29]), cel.bind(@r27," - + " size([27, 28]), cel.bind(@r26, size([26, 27]), cel.bind(@r25, size([25, 26])," - + " cel.bind(@r24, size([24, 25]), cel.bind(@r23, size([23, 24]), cel.bind(@r22," - + " size([22, 23]), cel.bind(@r21, size([21, 22]), cel.bind(@r20, size([20, 21])," - + " cel.bind(@r19, size([19, 20]), cel.bind(@r18, size([18, 19]), cel.bind(@r17," - + " size([17, 18]), cel.bind(@r16, size([16, 17]), cel.bind(@r15, size([15, 16])," - + " cel.bind(@r14, size([14, 15]), cel.bind(@r13, size([13, 14]), cel.bind(@r12," - + " size([12, 13]), cel.bind(@r11, size([11, 12]), cel.bind(@r10, size([10, 11])," - + " cel.bind(@r9, size([9, 10]), cel.bind(@r8, size([8, 9]), cel.bind(@r7, size([7," - + " 8]), cel.bind(@r6, size([6, 7]), cel.bind(@r5, size([5, 6]), cel.bind(@r4," - + " size([4, 5]), cel.bind(@r3, size([3, 4]), cel.bind(@r2, size([2, 3])," - + " cel.bind(@r1, size([1, 2]), cel.bind(@r0, size([0, 1]), @r0 + @r0) + @r1 + @r1)" - + " + @r2 + @r2) + @r3 + @r3) + @r4 + @r4) + @r5 + @r5) + @r6 + @r6) + @r7 + @r7) +" - + " @r8 + @r8) + @r9 + @r9) + @r10 + @r10) + @r11 + @r11) + @r12 + @r12) + @r13 +" - + " @r13) + @r14 + @r14) + @r15 + @r15) + @r16 + @r16) + @r17 + @r17) + @r18 +" - + " @r18) + @r19 + @r19) + @r20 + @r20) + @r21 + @r21) + @r22 + @r22) + @r23 +" - + " @r23) + @r24 + @r24) + @r25 + @r25) + @r26 + @r26) + @r27 + @r27) + @r28 +" - + " @r28) + @r29 + @r29) + @r30 + @r30) + @r31 + @r31) + @r32 + @r32) + @r33 +" - + " @r33) + @r34 + @r34) + @r35 + @r35) + @r36 + @r36) + @r37 + @r37) + @r38 +" - + " @r38) + @r39 + @r39) + @r40 + @r40) + @r41 + @r41) + @r42 + @r42) + @r43 +" - + " @r43) + @r44 + @r44) + @r45 + @r45) + @r46 + @r46) + @r47 + @r47) + @r48 +" - + " @r48) + @r49 + @r49)"); - assertThat(CEL.createProgram(optimizedAst).eval()).isEqualTo(200L); - } - - @Test - public void cse_largeFlattenedBlocks() throws Exception { - StringBuilder sb = new StringBuilder(); - int limit = 50; - for (int i = 0; i < limit; i++) { - sb.append(String.format("size([%d, %d]) + ", i, i + 1)); - sb.append(String.format("size([%d, %d]) ", i, i + 1)); - if (i < limit - 1) { - sb.append("+"); - } - } - CelAbstractSyntaxTree ast = CEL.compile(sb.toString()).getAst(); - - CelAbstractSyntaxTree optimizedAst = - newCseOptimizer( - SubexpressionOptimizerOptions.newBuilder() - .populateMacroCalls(true) - .enableCelBlock(true) - .build()) - .optimize(ast); - - assertThat(CEL_UNPARSER.unparse(optimizedAst)) - .isEqualTo( - "cel.@block([size([0, 1]), size([1, 2]), size([2, 3]), size([3, 4]), size([4, 5])," - + " size([5, 6]), size([6, 7]), size([7, 8]), size([8, 9]), size([9, 10])," - + " size([10, 11]), size([11, 12]), size([12, 13]), size([13, 14]), size([14, 15])," - + " size([15, 16]), size([16, 17]), size([17, 18]), size([18, 19]), size([19, 20])," - + " size([20, 21]), size([21, 22]), size([22, 23]), size([23, 24]), size([24, 25])," - + " size([25, 26]), size([26, 27]), size([27, 28]), size([28, 29]), size([29, 30])," - + " size([30, 31]), size([31, 32]), size([32, 33]), size([33, 34]), size([34, 35])," - + " size([35, 36]), size([36, 37]), size([37, 38]), size([38, 39]), size([39, 40])," - + " size([40, 41]), size([41, 42]), size([42, 43]), size([43, 44]), size([44, 45])," - + " size([45, 46]), size([46, 47]), size([47, 48]), size([48, 49]), size([49," - + " 50])], @index0 + @index0 + @index1 + @index1 + @index2 + @index2 + @index3 +" - + " @index3 + @index4 + @index4 + @index5 + @index5 + @index6 + @index6 + @index7 +" - + " @index7 + @index8 + @index8 + @index9 + @index9 + @index10 + @index10 +" - + " @index11 + @index11 + @index12 + @index12 + @index13 + @index13 + @index14 +" - + " @index14 + @index15 + @index15 + @index16 + @index16 + @index17 + @index17 +" - + " @index18 + @index18 + @index19 + @index19 + @index20 + @index20 + @index21 +" - + " @index21 + @index22 + @index22 + @index23 + @index23 + @index24 + @index24 +" - + " @index25 + @index25 + @index26 + @index26 + @index27 + @index27 + @index28 +" - + " @index28 + @index29 + @index29 + @index30 + @index30 + @index31 + @index31 +" - + " @index32 + @index32 + @index33 + @index33 + @index34 + @index34 + @index35 +" - + " @index35 + @index36 + @index36 + @index37 + @index37 + @index38 + @index38 +" - + " @index39 + @index39 + @index40 + @index40 + @index41 + @index41 + @index42 +" - + " @index42 + @index43 + @index43 + @index44 + @index44 + @index45 + @index45 +" - + " @index46 + @index46 + @index47 + @index47 + @index48 + @index48 + @index49 +" - + " @index49)"); - assertThat(CEL.createProgram(optimizedAst).eval()).isEqualTo(200L); - } - - @Test - public void cse_withCelBind_largeNestedMacro() throws Exception { - StringBuilder sb = new StringBuilder(); - sb.append("size([1,2,3]"); - int limit = 8; - for (int i = 0; i < limit; i++) { - sb.append(".map(i, [1, 2, 3]"); - } - for (int i = 0; i < limit; i++) { - sb.append(")"); - } - sb.append(")"); - String nestedMapCallExpr = sb.toString(); // size([1,2,3].map(i, [1,2,3].map(i, [1,2,3].map(... - // Add this large macro call 8 times - for (int i = 0; i < limit; i++) { - sb.append("+"); - sb.append(nestedMapCallExpr); - } - CelAbstractSyntaxTree ast = CEL.compile(sb.toString()).getAst(); - - CelAbstractSyntaxTree optimizedAst = - newCseOptimizer( - SubexpressionOptimizerOptions.newBuilder() - .populateMacroCalls(true) - .enableCelBlock(false) - .build()) - .optimize(ast); - - assertThat(CEL_UNPARSER.unparse(optimizedAst)) - .isEqualTo( - "cel.bind(@r0, [1, 2, 3], cel.bind(@r1, size(@r0.map(@c0:0, @r0.map(@c1:0," - + " @r0.map(@c2:0, @r0.map(@c3:0, @r0.map(@c4:0, @r0.map(@c5:0, @r0.map(@c6:0," - + " @r0.map(@c7:0, @r0))))))))), @r1 + @r1 + @r1 + @r1 + @r1 + @r1 + @r1 + @r1 +" - + " @r1))"); - assertThat(CEL.createProgram(optimizedAst).eval()).isEqualTo(27); - } - - @Test - public void cse_withCelBlock_largeNestedMacro() throws Exception { - StringBuilder sb = new StringBuilder(); - sb.append("size([1,2,3]"); - int limit = 8; - for (int i = 0; i < limit; i++) { - sb.append(".map(i, [1, 2, 3]"); - } - for (int i = 0; i < limit; i++) { - sb.append(")"); - } - sb.append(")"); - String nestedMapCallExpr = sb.toString(); // size([1,2,3].map(i, [1,2,3].map(i, [1,2,3].map(... - // Add this large macro call 8 times - for (int i = 0; i < limit; i++) { - sb.append("+"); - sb.append(nestedMapCallExpr); - } - CelAbstractSyntaxTree ast = CEL.compile(sb.toString()).getAst(); - - CelAbstractSyntaxTree optimizedAst = - newCseOptimizer( - SubexpressionOptimizerOptions.newBuilder() - .populateMacroCalls(true) - .enableCelBlock(true) - .build()) - .optimize(ast); - - assertThat(CEL_UNPARSER.unparse(optimizedAst)) - .isEqualTo( - "cel.@block([[1, 2, 3], size(@index0.map(@c0:0, @index0.map(@c1:0, @index0.map(@c2:0," - + " @index0.map(@c3:0, @index0.map(@c4:0, @index0.map(@c5:0, @index0.map(@c6:0," - + " @index0.map(@c7:0, @index0)))))))))], @index1 + @index1 + @index1 + @index1 +" - + " @index1 + @index1 + @index1 + @index1 + @index1)"); - assertThat(CEL.createProgram(optimizedAst).eval()).isEqualTo(27); - } - @Test public void cse_applyConstFoldingAfter() throws Exception { CelAbstractSyntaxTree ast = diff --git a/optimizer/src/test/resources/BUILD.bazel b/optimizer/src/test/resources/BUILD.bazel new file mode 100644 index 000000000..10fb339f9 --- /dev/null +++ b/optimizer/src/test/resources/BUILD.bazel @@ -0,0 +1,15 @@ +package( + default_applicable_licenses = [ + "//:license", + ], + default_testonly = True, + default_visibility = [ + "//optimizer:__subpackages__", + ], +) + +filegroup( + name = "baselines", + testonly = True, + srcs = glob(["*.baseline"]), +) diff --git a/optimizer/src/test/resources/large_expressions_bind_cascaded.baseline b/optimizer/src/test/resources/large_expressions_bind_cascaded.baseline new file mode 100644 index 000000000..b39eebd06 --- /dev/null +++ b/optimizer/src/test/resources/large_expressions_bind_cascaded.baseline @@ -0,0 +1,17 @@ +Test case: CALC_FOUR_COMMON_SUBEXPR +Source: [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] +=====> +Result: [1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4] +Unparsed: cel.bind(@r3, [1, 2, 3, 4], cel.bind(@r2, [1, 2, 3], cel.bind(@r1, [1, 2], cel.bind(@r0, [1], @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0 + @r1 + @r2 + @r3 + @r0) + @r1) + @r2) + @r3) + +Test case: CALC_ALL_COMMON_SUBEXPR +Source: [0, 1] + [0, 1] + [1, 2] + [1, 2] + [2, 3] + [2, 3] + [3, 4] + [3, 4] + [4, 5] + [4, 5] + [5, 6] + [5, 6] + [6, 7] + [6, 7] + [7, 8] + [7, 8] + [8, 9] + [8, 9] + [9, 10] + [9, 10] + [10, 11] + [10, 11] + [11, 12] + [11, 12] + [12, 13] + [12, 13] + [13, 14] + [13, 14] + [14, 15] + [14, 15] + [15, 16] + [15, 16] + [16, 17] + [16, 17] + [17, 18] + [17, 18] + [18, 19] + [18, 19] + [19, 20] + [19, 20] + [20, 21] + [20, 21] + [21, 22] + [21, 22] + [22, 23] + [22, 23] + [23, 24] + [23, 24] + [24, 25] + [24, 25] + [25, 26] + [25, 26] + [26, 27] + [26, 27] + [27, 28] + [27, 28] + [28, 29] + [28, 29] + [29, 30] + [29, 30] + [30, 31] + [30, 31] + [31, 32] + [31, 32] + [32, 33] + [32, 33] + [33, 34] + [33, 34] + [34, 35] + [34, 35] + [35, 36] + [35, 36] + [36, 37] + [36, 37] + [37, 38] + [37, 38] + [38, 39] + [38, 39] + [39, 40] + [39, 40] + [40, 41] + [40, 41] + [41, 42] + [41, 42] + [42, 43] + [42, 43] + [43, 44] + [43, 44] + [44, 45] + [44, 45] + [45, 46] + [45, 46] + [46, 47] + [46, 47] + [47, 48] + [47, 48] + [48, 49] + [48, 49] + [49, 50] + [49, 50] +=====> +Result: [0, 1, 0, 1, 1, 2, 1, 2, 2, 3, 2, 3, 3, 4, 3, 4, 4, 5, 4, 5, 5, 6, 5, 6, 6, 7, 6, 7, 7, 8, 7, 8, 8, 9, 8, 9, 9, 10, 9, 10, 10, 11, 10, 11, 11, 12, 11, 12, 12, 13, 12, 13, 13, 14, 13, 14, 14, 15, 14, 15, 15, 16, 15, 16, 16, 17, 16, 17, 17, 18, 17, 18, 18, 19, 18, 19, 19, 20, 19, 20, 20, 21, 20, 21, 21, 22, 21, 22, 22, 23, 22, 23, 23, 24, 23, 24, 24, 25, 24, 25, 25, 26, 25, 26, 26, 27, 26, 27, 27, 28, 27, 28, 28, 29, 28, 29, 29, 30, 29, 30, 30, 31, 30, 31, 31, 32, 31, 32, 32, 33, 32, 33, 33, 34, 33, 34, 34, 35, 34, 35, 35, 36, 35, 36, 36, 37, 36, 37, 37, 38, 37, 38, 38, 39, 38, 39, 39, 40, 39, 40, 40, 41, 40, 41, 41, 42, 41, 42, 42, 43, 42, 43, 43, 44, 43, 44, 44, 45, 44, 45, 45, 46, 45, 46, 46, 47, 46, 47, 47, 48, 47, 48, 48, 49, 48, 49, 49, 50, 49, 50] +Unparsed: cel.bind(@r49, [49, 50], cel.bind(@r48, [48, 49], cel.bind(@r47, [47, 48], cel.bind(@r46, [46, 47], cel.bind(@r45, [45, 46], cel.bind(@r44, [44, 45], cel.bind(@r43, [43, 44], cel.bind(@r42, [42, 43], cel.bind(@r41, [41, 42], cel.bind(@r40, [40, 41], cel.bind(@r39, [39, 40], cel.bind(@r38, [38, 39], cel.bind(@r37, [37, 38], cel.bind(@r36, [36, 37], cel.bind(@r35, [35, 36], cel.bind(@r34, [34, 35], cel.bind(@r33, [33, 34], cel.bind(@r32, [32, 33], cel.bind(@r31, [31, 32], cel.bind(@r30, [30, 31], cel.bind(@r29, [29, 30], cel.bind(@r28, [28, 29], cel.bind(@r27, [27, 28], cel.bind(@r26, [26, 27], cel.bind(@r25, [25, 26], cel.bind(@r24, [24, 25], cel.bind(@r23, [23, 24], cel.bind(@r22, [22, 23], cel.bind(@r21, [21, 22], cel.bind(@r20, [20, 21], cel.bind(@r19, [19, 20], cel.bind(@r18, [18, 19], cel.bind(@r17, [17, 18], cel.bind(@r16, [16, 17], cel.bind(@r15, [15, 16], cel.bind(@r14, [14, 15], cel.bind(@r13, [13, 14], cel.bind(@r12, [12, 13], cel.bind(@r11, [11, 12], cel.bind(@r10, [10, 11], cel.bind(@r9, [9, 10], cel.bind(@r8, [8, 9], cel.bind(@r7, [7, 8], cel.bind(@r6, [6, 7], cel.bind(@r5, [5, 6], cel.bind(@r4, [4, 5], cel.bind(@r3, [3, 4], cel.bind(@r2, [2, 3], cel.bind(@r1, [1, 2], cel.bind(@r0, [0, 1], @r0 + @r0) + @r1 + @r1) + @r2 + @r2) + @r3 + @r3) + @r4 + @r4) + @r5 + @r5) + @r6 + @r6) + @r7 + @r7) + @r8 + @r8) + @r9 + @r9) + @r10 + @r10) + @r11 + @r11) + @r12 + @r12) + @r13 + @r13) + @r14 + @r14) + @r15 + @r15) + @r16 + @r16) + @r17 + @r17) + @r18 + @r18) + @r19 + @r19) + @r20 + @r20) + @r21 + @r21) + @r22 + @r22) + @r23 + @r23) + @r24 + @r24) + @r25 + @r25) + @r26 + @r26) + @r27 + @r27) + @r28 + @r28) + @r29 + @r29) + @r30 + @r30) + @r31 + @r31) + @r32 + @r32) + @r33 + @r33) + @r34 + @r34) + @r35 + @r35) + @r36 + @r36) + @r37 + @r37) + @r38 + @r38) + @r39 + @r39) + @r40 + @r40) + @r41 + @r41) + @r42 + @r42) + @r43 + @r43) + @r44 + @r44) + @r45 + @r45) + @r46 + @r46) + @r47 + @r47) + @r48 + @r48) + @r49 + @r49) + +Test case: NESTED_MACROS +Source: [1,2,3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3])))))))) +=====> +Result: [[[[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]]], [[[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]]], [[[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]]]] +Unparsed: cel.bind(@r0, [1, 2, 3], @r0.map(@c0:0, @r0.map(@c1:0, @r0.map(@c2:0, @r0.map(@c3:0, @r0.map(@c4:0, @r0.map(@c5:0, @r0.map(@c6:0, @r0.map(@c7:0, @r0))))))))) diff --git a/optimizer/src/test/resources/large_expressions_block_common_subexpr.baseline b/optimizer/src/test/resources/large_expressions_block_common_subexpr.baseline new file mode 100644 index 000000000..42c6e9e1a --- /dev/null +++ b/optimizer/src/test/resources/large_expressions_block_common_subexpr.baseline @@ -0,0 +1,17 @@ +Test case: CALC_FOUR_COMMON_SUBEXPR +Source: [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] +=====> +Result: [1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4] +Unparsed: cel.@block([[1], [1, 2], [1, 2, 3], [1, 2, 3, 4]], @index0 + @index1 + @index2 + @index3 + @index0 + @index1 + @index2 + @index3 + @index0 + @index1 + @index2 + @index3 + @index0 + @index1 + @index2 + @index3 + @index0 + @index1 + @index2 + @index3 + @index0 + @index1 + @index2 + @index3 + @index0 + @index1 + @index2 + @index3 + @index0 + @index1 + @index2 + @index3 + @index0 + @index1 + @index2 + @index3 + @index0 + @index1 + @index2 + @index3 + @index0 + @index1 + @index2 + @index3 + @index0 + @index1 + @index2 + @index3 + @index0 + @index1 + @index2 + @index3 + @index0 + @index1 + @index2 + @index3 + @index0 + @index1 + @index2 + @index3 + @index0 + @index1 + @index2 + @index3 + @index0 + @index1 + @index2 + @index3 + @index0 + @index1 + @index2 + @index3 + @index0 + @index1 + @index2 + @index3 + @index0 + @index1 + @index2 + @index3 + @index0 + @index1 + @index2 + @index3 + @index0 + @index1 + @index2 + @index3 + @index0 + @index1 + @index2 + @index3 + @index0 + @index1 + @index2 + @index3 + @index0 + @index1 + @index2 + @index3 + @index0 + @index1 + @index2 + @index3 + @index0 + @index1 + @index2 + @index3 + @index0 + @index1 + @index2 + @index3 + @index0 + @index1 + @index2 + @index3 + @index0 + @index1 + @index2 + @index3 + @index0 + @index1 + @index2 + @index3 + @index0 + @index1 + @index2 + @index3 + @index0 + @index1 + @index2 + @index3 + @index0 + @index1 + @index2 + @index3 + @index0 + @index1 + @index2 + @index3 + @index0 + @index1 + @index2 + @index3 + @index0 + @index1 + @index2 + @index3 + @index0 + @index1 + @index2 + @index3 + @index0 + @index1 + @index2 + @index3 + @index0 + @index1 + @index2 + @index3) + +Test case: CALC_ALL_COMMON_SUBEXPR +Source: [0, 1] + [0, 1] + [1, 2] + [1, 2] + [2, 3] + [2, 3] + [3, 4] + [3, 4] + [4, 5] + [4, 5] + [5, 6] + [5, 6] + [6, 7] + [6, 7] + [7, 8] + [7, 8] + [8, 9] + [8, 9] + [9, 10] + [9, 10] + [10, 11] + [10, 11] + [11, 12] + [11, 12] + [12, 13] + [12, 13] + [13, 14] + [13, 14] + [14, 15] + [14, 15] + [15, 16] + [15, 16] + [16, 17] + [16, 17] + [17, 18] + [17, 18] + [18, 19] + [18, 19] + [19, 20] + [19, 20] + [20, 21] + [20, 21] + [21, 22] + [21, 22] + [22, 23] + [22, 23] + [23, 24] + [23, 24] + [24, 25] + [24, 25] + [25, 26] + [25, 26] + [26, 27] + [26, 27] + [27, 28] + [27, 28] + [28, 29] + [28, 29] + [29, 30] + [29, 30] + [30, 31] + [30, 31] + [31, 32] + [31, 32] + [32, 33] + [32, 33] + [33, 34] + [33, 34] + [34, 35] + [34, 35] + [35, 36] + [35, 36] + [36, 37] + [36, 37] + [37, 38] + [37, 38] + [38, 39] + [38, 39] + [39, 40] + [39, 40] + [40, 41] + [40, 41] + [41, 42] + [41, 42] + [42, 43] + [42, 43] + [43, 44] + [43, 44] + [44, 45] + [44, 45] + [45, 46] + [45, 46] + [46, 47] + [46, 47] + [47, 48] + [47, 48] + [48, 49] + [48, 49] + [49, 50] + [49, 50] +=====> +Result: [0, 1, 0, 1, 1, 2, 1, 2, 2, 3, 2, 3, 3, 4, 3, 4, 4, 5, 4, 5, 5, 6, 5, 6, 6, 7, 6, 7, 7, 8, 7, 8, 8, 9, 8, 9, 9, 10, 9, 10, 10, 11, 10, 11, 11, 12, 11, 12, 12, 13, 12, 13, 13, 14, 13, 14, 14, 15, 14, 15, 15, 16, 15, 16, 16, 17, 16, 17, 17, 18, 17, 18, 18, 19, 18, 19, 19, 20, 19, 20, 20, 21, 20, 21, 21, 22, 21, 22, 22, 23, 22, 23, 23, 24, 23, 24, 24, 25, 24, 25, 25, 26, 25, 26, 26, 27, 26, 27, 27, 28, 27, 28, 28, 29, 28, 29, 29, 30, 29, 30, 30, 31, 30, 31, 31, 32, 31, 32, 32, 33, 32, 33, 33, 34, 33, 34, 34, 35, 34, 35, 35, 36, 35, 36, 36, 37, 36, 37, 37, 38, 37, 38, 38, 39, 38, 39, 39, 40, 39, 40, 40, 41, 40, 41, 41, 42, 41, 42, 42, 43, 42, 43, 43, 44, 43, 44, 44, 45, 44, 45, 45, 46, 45, 46, 46, 47, 46, 47, 47, 48, 47, 48, 48, 49, 48, 49, 49, 50, 49, 50] +Unparsed: cel.@block([[0, 1], [1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7], [7, 8], [8, 9], [9, 10], [10, 11], [11, 12], [12, 13], [13, 14], [14, 15], [15, 16], [16, 17], [17, 18], [18, 19], [19, 20], [20, 21], [21, 22], [22, 23], [23, 24], [24, 25], [25, 26], [26, 27], [27, 28], [28, 29], [29, 30], [30, 31], [31, 32], [32, 33], [33, 34], [34, 35], [35, 36], [36, 37], [37, 38], [38, 39], [39, 40], [40, 41], [41, 42], [42, 43], [43, 44], [44, 45], [45, 46], [46, 47], [47, 48], [48, 49], [49, 50]], @index0 + @index0 + @index1 + @index1 + @index2 + @index2 + @index3 + @index3 + @index4 + @index4 + @index5 + @index5 + @index6 + @index6 + @index7 + @index7 + @index8 + @index8 + @index9 + @index9 + @index10 + @index10 + @index11 + @index11 + @index12 + @index12 + @index13 + @index13 + @index14 + @index14 + @index15 + @index15 + @index16 + @index16 + @index17 + @index17 + @index18 + @index18 + @index19 + @index19 + @index20 + @index20 + @index21 + @index21 + @index22 + @index22 + @index23 + @index23 + @index24 + @index24 + @index25 + @index25 + @index26 + @index26 + @index27 + @index27 + @index28 + @index28 + @index29 + @index29 + @index30 + @index30 + @index31 + @index31 + @index32 + @index32 + @index33 + @index33 + @index34 + @index34 + @index35 + @index35 + @index36 + @index36 + @index37 + @index37 + @index38 + @index38 + @index39 + @index39 + @index40 + @index40 + @index41 + @index41 + @index42 + @index42 + @index43 + @index43 + @index44 + @index44 + @index45 + @index45 + @index46 + @index46 + @index47 + @index47 + @index48 + @index48 + @index49 + @index49) + +Test case: NESTED_MACROS +Source: [1,2,3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3])))))))) +=====> +Result: [[[[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]]], [[[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]]], [[[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]]]] +Unparsed: cel.@block([[1, 2, 3]], @index0.map(@c0:0, @index0.map(@c1:0, @index0.map(@c2:0, @index0.map(@c3:0, @index0.map(@c4:0, @index0.map(@c5:0, @index0.map(@c6:0, @index0.map(@c7:0, @index0))))))))) diff --git a/optimizer/src/test/resources/large_expressions_block_recursion_depth_1.baseline b/optimizer/src/test/resources/large_expressions_block_recursion_depth_1.baseline new file mode 100644 index 000000000..f391e5f87 --- /dev/null +++ b/optimizer/src/test/resources/large_expressions_block_recursion_depth_1.baseline @@ -0,0 +1,17 @@ +Test case: CALC_FOUR_COMMON_SUBEXPR +Source: [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] +=====> +Result: [1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4] +Unparsed: cel.@block([[1], [1, 2], [1, 2, 3], [1, 2, 3, 4], @index0 + @index1, @index4 + @index2, @index5 + @index3, @index6 + @index0, @index7 + @index1, @index8 + @index2, @index9 + @index3, @index10 + @index0, @index11 + @index1, @index12 + @index2, @index13 + @index3, @index14 + @index0, @index15 + @index1, @index16 + @index2, @index17 + @index3, @index18 + @index0, @index19 + @index1, @index20 + @index2, @index21 + @index3, @index22 + @index0, @index23 + @index1, @index24 + @index2, @index25 + @index3, @index26 + @index0, @index27 + @index1, @index28 + @index2, @index29 + @index3, @index30 + @index0, @index31 + @index1, @index32 + @index2, @index33 + @index3, @index34 + @index0, @index35 + @index1, @index36 + @index2, @index37 + @index3, @index38 + @index0, @index39 + @index1, @index40 + @index2, @index41 + @index3, @index42 + @index0, @index43 + @index1, @index44 + @index2, @index45 + @index3, @index46 + @index0, @index47 + @index1, @index48 + @index2, @index49 + @index3, @index50 + @index0, @index51 + @index1, @index52 + @index2, @index53 + @index3, @index54 + @index0, @index55 + @index1, @index56 + @index2, @index57 + @index3, @index58 + @index0, @index59 + @index1, @index60 + @index2, @index61 + @index3, @index62 + @index0, @index63 + @index1, @index64 + @index2, @index65 + @index3, @index66 + @index0, @index67 + @index1, @index68 + @index2, @index69 + @index3, @index70 + @index0, @index71 + @index1, @index72 + @index2, @index73 + @index3, @index74 + @index0, @index75 + @index1, @index76 + @index2, @index77 + @index3, @index78 + @index0, @index79 + @index1, @index80 + @index2, @index81 + @index3, @index82 + @index0, @index83 + @index1, @index84 + @index2, @index85 + @index3, @index86 + @index0, @index87 + @index1, @index88 + @index2, @index89 + @index3, @index90 + @index0, @index91 + @index1, @index92 + @index2, @index93 + @index3, @index94 + @index0, @index95 + @index1, @index96 + @index2, @index97 + @index3, @index98 + @index0, @index99 + @index1, @index100 + @index2, @index101 + @index3, @index102 + @index0, @index103 + @index1, @index104 + @index2, @index105 + @index3, @index106 + @index0, @index107 + @index1, @index108 + @index2, @index109 + @index3, @index110 + @index0, @index111 + @index1, @index112 + @index2, @index113 + @index3, @index114 + @index0, @index115 + @index1, @index116 + @index2, @index117 + @index3, @index118 + @index0, @index119 + @index1, @index120 + @index2, @index121 + @index3, @index122 + @index0, @index123 + @index1, @index124 + @index2, @index125 + @index3, @index126 + @index0, @index127 + @index1, @index128 + @index2, @index129 + @index3, @index130 + @index0, @index131 + @index1, @index132 + @index2, @index133 + @index3, @index134 + @index0, @index135 + @index1, @index136 + @index2, @index137 + @index3, @index138 + @index0, @index139 + @index1, @index140 + @index2, @index141 + @index3, @index142 + @index0, @index143 + @index1, @index144 + @index2, @index145 + @index3, @index146 + @index0, @index147 + @index1, @index148 + @index2, @index149 + @index3, @index150 + @index0, @index151 + @index1, @index152 + @index2, @index153 + @index3, @index154 + @index0, @index155 + @index1, @index156 + @index2, @index157 + @index3, @index158 + @index0, @index159 + @index1, @index160 + @index2], @index161 + @index3) + +Test case: CALC_ALL_COMMON_SUBEXPR +Source: [0, 1] + [0, 1] + [1, 2] + [1, 2] + [2, 3] + [2, 3] + [3, 4] + [3, 4] + [4, 5] + [4, 5] + [5, 6] + [5, 6] + [6, 7] + [6, 7] + [7, 8] + [7, 8] + [8, 9] + [8, 9] + [9, 10] + [9, 10] + [10, 11] + [10, 11] + [11, 12] + [11, 12] + [12, 13] + [12, 13] + [13, 14] + [13, 14] + [14, 15] + [14, 15] + [15, 16] + [15, 16] + [16, 17] + [16, 17] + [17, 18] + [17, 18] + [18, 19] + [18, 19] + [19, 20] + [19, 20] + [20, 21] + [20, 21] + [21, 22] + [21, 22] + [22, 23] + [22, 23] + [23, 24] + [23, 24] + [24, 25] + [24, 25] + [25, 26] + [25, 26] + [26, 27] + [26, 27] + [27, 28] + [27, 28] + [28, 29] + [28, 29] + [29, 30] + [29, 30] + [30, 31] + [30, 31] + [31, 32] + [31, 32] + [32, 33] + [32, 33] + [33, 34] + [33, 34] + [34, 35] + [34, 35] + [35, 36] + [35, 36] + [36, 37] + [36, 37] + [37, 38] + [37, 38] + [38, 39] + [38, 39] + [39, 40] + [39, 40] + [40, 41] + [40, 41] + [41, 42] + [41, 42] + [42, 43] + [42, 43] + [43, 44] + [43, 44] + [44, 45] + [44, 45] + [45, 46] + [45, 46] + [46, 47] + [46, 47] + [47, 48] + [47, 48] + [48, 49] + [48, 49] + [49, 50] + [49, 50] +=====> +Result: [0, 1, 0, 1, 1, 2, 1, 2, 2, 3, 2, 3, 3, 4, 3, 4, 4, 5, 4, 5, 5, 6, 5, 6, 6, 7, 6, 7, 7, 8, 7, 8, 8, 9, 8, 9, 9, 10, 9, 10, 10, 11, 10, 11, 11, 12, 11, 12, 12, 13, 12, 13, 13, 14, 13, 14, 14, 15, 14, 15, 15, 16, 15, 16, 16, 17, 16, 17, 17, 18, 17, 18, 18, 19, 18, 19, 19, 20, 19, 20, 20, 21, 20, 21, 21, 22, 21, 22, 22, 23, 22, 23, 23, 24, 23, 24, 24, 25, 24, 25, 25, 26, 25, 26, 26, 27, 26, 27, 27, 28, 27, 28, 28, 29, 28, 29, 29, 30, 29, 30, 30, 31, 30, 31, 31, 32, 31, 32, 32, 33, 32, 33, 33, 34, 33, 34, 34, 35, 34, 35, 35, 36, 35, 36, 36, 37, 36, 37, 37, 38, 37, 38, 38, 39, 38, 39, 39, 40, 39, 40, 40, 41, 40, 41, 41, 42, 41, 42, 42, 43, 42, 43, 43, 44, 43, 44, 44, 45, 44, 45, 45, 46, 45, 46, 46, 47, 46, 47, 47, 48, 47, 48, 48, 49, 48, 49, 49, 50, 49, 50] +Unparsed: cel.@block([[0, 1], [1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7], [7, 8], [8, 9], [9, 10], [10, 11], [11, 12], [12, 13], [13, 14], [14, 15], [15, 16], [16, 17], [17, 18], [18, 19], [19, 20], [20, 21], [21, 22], [22, 23], [23, 24], [24, 25], [25, 26], [26, 27], [27, 28], [28, 29], [29, 30], [30, 31], [31, 32], [32, 33], [33, 34], [34, 35], [35, 36], [36, 37], [37, 38], [38, 39], [39, 40], [40, 41], [41, 42], [42, 43], [43, 44], [44, 45], [45, 46], [46, 47], [47, 48], [48, 49], [49, 50], @index0 + @index0, @index50 + @index1, @index51 + @index1, @index52 + @index2, @index53 + @index2, @index54 + @index3, @index55 + @index3, @index56 + @index4, @index57 + @index4, @index58 + @index5, @index59 + @index5, @index60 + @index6, @index61 + @index6, @index62 + @index7, @index63 + @index7, @index64 + @index8, @index65 + @index8, @index66 + @index9, @index67 + @index9, @index68 + @index10, @index69 + @index10, @index70 + @index11, @index71 + @index11, @index72 + @index12, @index73 + @index12, @index74 + @index13, @index75 + @index13, @index76 + @index14, @index77 + @index14, @index78 + @index15, @index79 + @index15, @index80 + @index16, @index81 + @index16, @index82 + @index17, @index83 + @index17, @index84 + @index18, @index85 + @index18, @index86 + @index19, @index87 + @index19, @index88 + @index20, @index89 + @index20, @index90 + @index21, @index91 + @index21, @index92 + @index22, @index93 + @index22, @index94 + @index23, @index95 + @index23, @index96 + @index24, @index97 + @index24, @index98 + @index25, @index99 + @index25, @index100 + @index26, @index101 + @index26, @index102 + @index27, @index103 + @index27, @index104 + @index28, @index105 + @index28, @index106 + @index29, @index107 + @index29, @index108 + @index30, @index109 + @index30, @index110 + @index31, @index111 + @index31, @index112 + @index32, @index113 + @index32, @index114 + @index33, @index115 + @index33, @index116 + @index34, @index117 + @index34, @index118 + @index35, @index119 + @index35, @index120 + @index36, @index121 + @index36, @index122 + @index37, @index123 + @index37, @index124 + @index38, @index125 + @index38, @index126 + @index39, @index127 + @index39, @index128 + @index40, @index129 + @index40, @index130 + @index41, @index131 + @index41, @index132 + @index42, @index133 + @index42, @index134 + @index43, @index135 + @index43, @index136 + @index44, @index137 + @index44, @index138 + @index45, @index139 + @index45, @index140 + @index46, @index141 + @index46, @index142 + @index47, @index143 + @index47, @index144 + @index48, @index145 + @index48, @index146 + @index49], @index147 + @index49) + +Test case: NESTED_MACROS +Source: [1,2,3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3])))))))) +=====> +Result: [[[[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]]], [[[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]]], [[[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]]]] +Unparsed: cel.@block([[1, 2, 3], [@index0], @x7:0 + @index1], @index0.map(@c0:0, @index0.map(@c1:0, @index0.map(@c2:0, @index0.map(@c3:0, @index0.map(@c4:0, @index0.map(@c5:0, @index0.map(@c6:0, @index0.map(@c7:0, @index0))))))))) diff --git a/optimizer/src/test/resources/large_expressions_block_recursion_depth_2.baseline b/optimizer/src/test/resources/large_expressions_block_recursion_depth_2.baseline new file mode 100644 index 000000000..d77db7b6f --- /dev/null +++ b/optimizer/src/test/resources/large_expressions_block_recursion_depth_2.baseline @@ -0,0 +1,17 @@ +Test case: CALC_FOUR_COMMON_SUBEXPR +Source: [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] +=====> +Result: [1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4] +Unparsed: cel.@block([[1], [1, 2], [1, 2, 3], [1, 2, 3, 4], @index0 + @index1 + @index2, @index4 + @index3 + @index0, @index5 + @index1 + @index2, @index6 + @index3 + @index0, @index7 + @index1 + @index2, @index8 + @index3 + @index0, @index9 + @index1 + @index2, @index10 + @index3 + @index0, @index11 + @index1 + @index2, @index12 + @index3 + @index0, @index13 + @index1 + @index2, @index14 + @index3 + @index0, @index15 + @index1 + @index2, @index16 + @index3 + @index0, @index17 + @index1 + @index2, @index18 + @index3 + @index0, @index19 + @index1 + @index2, @index20 + @index3 + @index0, @index21 + @index1 + @index2, @index22 + @index3 + @index0, @index23 + @index1 + @index2, @index24 + @index3 + @index0, @index25 + @index1 + @index2, @index26 + @index3 + @index0, @index27 + @index1 + @index2, @index28 + @index3 + @index0, @index29 + @index1 + @index2, @index30 + @index3 + @index0, @index31 + @index1 + @index2, @index32 + @index3 + @index0, @index33 + @index1 + @index2, @index34 + @index3 + @index0, @index35 + @index1 + @index2, @index36 + @index3 + @index0, @index37 + @index1 + @index2, @index38 + @index3 + @index0, @index39 + @index1 + @index2, @index40 + @index3 + @index0, @index41 + @index1 + @index2, @index42 + @index3 + @index0, @index43 + @index1 + @index2, @index44 + @index3 + @index0, @index45 + @index1 + @index2, @index46 + @index3 + @index0, @index47 + @index1 + @index2, @index48 + @index3 + @index0, @index49 + @index1 + @index2, @index50 + @index3 + @index0, @index51 + @index1 + @index2, @index52 + @index3 + @index0, @index53 + @index1 + @index2, @index54 + @index3 + @index0, @index55 + @index1 + @index2, @index56 + @index3 + @index0, @index57 + @index1 + @index2, @index58 + @index3 + @index0, @index59 + @index1 + @index2, @index60 + @index3 + @index0, @index61 + @index1 + @index2, @index62 + @index3 + @index0, @index63 + @index1 + @index2, @index64 + @index3 + @index0, @index65 + @index1 + @index2, @index66 + @index3 + @index0, @index67 + @index1 + @index2, @index68 + @index3 + @index0, @index69 + @index1 + @index2, @index70 + @index3 + @index0, @index71 + @index1 + @index2, @index72 + @index3 + @index0, @index73 + @index1 + @index2, @index74 + @index3 + @index0, @index75 + @index1 + @index2, @index76 + @index3 + @index0, @index77 + @index1 + @index2, @index78 + @index3 + @index0, @index79 + @index1 + @index2, @index80 + @index3 + @index0, @index81 + @index1 + @index2], @index82 + @index3) + +Test case: CALC_ALL_COMMON_SUBEXPR +Source: [0, 1] + [0, 1] + [1, 2] + [1, 2] + [2, 3] + [2, 3] + [3, 4] + [3, 4] + [4, 5] + [4, 5] + [5, 6] + [5, 6] + [6, 7] + [6, 7] + [7, 8] + [7, 8] + [8, 9] + [8, 9] + [9, 10] + [9, 10] + [10, 11] + [10, 11] + [11, 12] + [11, 12] + [12, 13] + [12, 13] + [13, 14] + [13, 14] + [14, 15] + [14, 15] + [15, 16] + [15, 16] + [16, 17] + [16, 17] + [17, 18] + [17, 18] + [18, 19] + [18, 19] + [19, 20] + [19, 20] + [20, 21] + [20, 21] + [21, 22] + [21, 22] + [22, 23] + [22, 23] + [23, 24] + [23, 24] + [24, 25] + [24, 25] + [25, 26] + [25, 26] + [26, 27] + [26, 27] + [27, 28] + [27, 28] + [28, 29] + [28, 29] + [29, 30] + [29, 30] + [30, 31] + [30, 31] + [31, 32] + [31, 32] + [32, 33] + [32, 33] + [33, 34] + [33, 34] + [34, 35] + [34, 35] + [35, 36] + [35, 36] + [36, 37] + [36, 37] + [37, 38] + [37, 38] + [38, 39] + [38, 39] + [39, 40] + [39, 40] + [40, 41] + [40, 41] + [41, 42] + [41, 42] + [42, 43] + [42, 43] + [43, 44] + [43, 44] + [44, 45] + [44, 45] + [45, 46] + [45, 46] + [46, 47] + [46, 47] + [47, 48] + [47, 48] + [48, 49] + [48, 49] + [49, 50] + [49, 50] +=====> +Result: [0, 1, 0, 1, 1, 2, 1, 2, 2, 3, 2, 3, 3, 4, 3, 4, 4, 5, 4, 5, 5, 6, 5, 6, 6, 7, 6, 7, 7, 8, 7, 8, 8, 9, 8, 9, 9, 10, 9, 10, 10, 11, 10, 11, 11, 12, 11, 12, 12, 13, 12, 13, 13, 14, 13, 14, 14, 15, 14, 15, 15, 16, 15, 16, 16, 17, 16, 17, 17, 18, 17, 18, 18, 19, 18, 19, 19, 20, 19, 20, 20, 21, 20, 21, 21, 22, 21, 22, 22, 23, 22, 23, 23, 24, 23, 24, 24, 25, 24, 25, 25, 26, 25, 26, 26, 27, 26, 27, 27, 28, 27, 28, 28, 29, 28, 29, 29, 30, 29, 30, 30, 31, 30, 31, 31, 32, 31, 32, 32, 33, 32, 33, 33, 34, 33, 34, 34, 35, 34, 35, 35, 36, 35, 36, 36, 37, 36, 37, 37, 38, 37, 38, 38, 39, 38, 39, 39, 40, 39, 40, 40, 41, 40, 41, 41, 42, 41, 42, 42, 43, 42, 43, 43, 44, 43, 44, 44, 45, 44, 45, 45, 46, 45, 46, 46, 47, 46, 47, 47, 48, 47, 48, 48, 49, 48, 49, 49, 50, 49, 50] +Unparsed: cel.@block([[0, 1], [1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7], [7, 8], [8, 9], [9, 10], [10, 11], [11, 12], [12, 13], [13, 14], [14, 15], [15, 16], [16, 17], [17, 18], [18, 19], [19, 20], [20, 21], [21, 22], [22, 23], [23, 24], [24, 25], [25, 26], [26, 27], [27, 28], [28, 29], [29, 30], [30, 31], [31, 32], [32, 33], [33, 34], [34, 35], [35, 36], [36, 37], [37, 38], [38, 39], [39, 40], [40, 41], [41, 42], [42, 43], [43, 44], [44, 45], [45, 46], [46, 47], [47, 48], [48, 49], [49, 50], @index0 + @index0 + @index1, @index50 + @index1 + @index2, @index51 + @index2 + @index3, @index52 + @index3 + @index4, @index53 + @index4 + @index5, @index54 + @index5 + @index6, @index55 + @index6 + @index7, @index56 + @index7 + @index8, @index57 + @index8 + @index9, @index58 + @index9 + @index10, @index59 + @index10 + @index11, @index60 + @index11 + @index12, @index61 + @index12 + @index13, @index62 + @index13 + @index14, @index63 + @index14 + @index15, @index64 + @index15 + @index16, @index65 + @index16 + @index17, @index66 + @index17 + @index18, @index67 + @index18 + @index19, @index68 + @index19 + @index20, @index69 + @index20 + @index21, @index70 + @index21 + @index22, @index71 + @index22 + @index23, @index72 + @index23 + @index24, @index73 + @index24 + @index25, @index74 + @index25 + @index26, @index75 + @index26 + @index27, @index76 + @index27 + @index28, @index77 + @index28 + @index29, @index78 + @index29 + @index30, @index79 + @index30 + @index31, @index80 + @index31 + @index32, @index81 + @index32 + @index33, @index82 + @index33 + @index34, @index83 + @index34 + @index35, @index84 + @index35 + @index36, @index85 + @index36 + @index37, @index86 + @index37 + @index38, @index87 + @index38 + @index39, @index88 + @index39 + @index40, @index89 + @index40 + @index41, @index90 + @index41 + @index42, @index91 + @index42 + @index43, @index92 + @index43 + @index44, @index93 + @index44 + @index45, @index94 + @index45 + @index46, @index95 + @index46 + @index47, @index96 + @index47 + @index48, @index97 + @index48 + @index49], @index98 + @index49) + +Test case: NESTED_MACROS +Source: [1,2,3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3])))))))) +=====> +Result: [[[[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]]], [[[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]]], [[[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]]]] +Unparsed: cel.@block([[1, 2, 3], @x7:0 + [@index0], @index0.map(@c7:0, @index0), @x6:0 + [@index2], @index0.map(@c6:0, @index2), @x5:0 + [@index4], @index0.map(@c5:0, @index4), @x4:0 + [@index6], @index0.map(@c4:0, @index6), @x3:0 + [@index8], @index0.map(@c3:0, @index8), @x2:0 + [@index10], @index0.map(@c2:0, @index10), @x1:0 + [@index12], @index0.map(@c1:0, @index12), @x0:0 + [@index14]], @index0.map(@c0:0, @index14)) diff --git a/optimizer/src/test/resources/large_expressions_block_recursion_depth_3.baseline b/optimizer/src/test/resources/large_expressions_block_recursion_depth_3.baseline new file mode 100644 index 000000000..832173f88 --- /dev/null +++ b/optimizer/src/test/resources/large_expressions_block_recursion_depth_3.baseline @@ -0,0 +1,17 @@ +Test case: CALC_FOUR_COMMON_SUBEXPR +Source: [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] +=====> +Result: [1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4] +Unparsed: cel.@block([[1], [1, 2], [1, 2, 3], [1, 2, 3, 4], @index0 + @index1 + @index2 + @index3, @index4 + @index0 + @index1 + @index2, @index5 + @index3 + @index0 + @index1, @index6 + @index2 + @index3 + @index0, @index7 + @index1 + @index2 + @index3, @index8 + @index0 + @index1 + @index2, @index9 + @index3 + @index0 + @index1, @index10 + @index2 + @index3 + @index0, @index11 + @index1 + @index2 + @index3, @index12 + @index0 + @index1 + @index2, @index13 + @index3 + @index0 + @index1, @index14 + @index2 + @index3 + @index0, @index15 + @index1 + @index2 + @index3, @index16 + @index0 + @index1 + @index2, @index17 + @index3 + @index0 + @index1, @index18 + @index2 + @index3 + @index0, @index19 + @index1 + @index2 + @index3, @index20 + @index0 + @index1 + @index2, @index21 + @index3 + @index0 + @index1, @index22 + @index2 + @index3 + @index0, @index23 + @index1 + @index2 + @index3, @index24 + @index0 + @index1 + @index2, @index25 + @index3 + @index0 + @index1, @index26 + @index2 + @index3 + @index0, @index27 + @index1 + @index2 + @index3, @index28 + @index0 + @index1 + @index2, @index29 + @index3 + @index0 + @index1, @index30 + @index2 + @index3 + @index0, @index31 + @index1 + @index2 + @index3, @index32 + @index0 + @index1 + @index2, @index33 + @index3 + @index0 + @index1, @index34 + @index2 + @index3 + @index0, @index35 + @index1 + @index2 + @index3, @index36 + @index0 + @index1 + @index2, @index37 + @index3 + @index0 + @index1, @index38 + @index2 + @index3 + @index0, @index39 + @index1 + @index2 + @index3, @index40 + @index0 + @index1 + @index2, @index41 + @index3 + @index0 + @index1, @index42 + @index2 + @index3 + @index0, @index43 + @index1 + @index2 + @index3, @index44 + @index0 + @index1 + @index2, @index45 + @index3 + @index0 + @index1, @index46 + @index2 + @index3 + @index0, @index47 + @index1 + @index2 + @index3, @index48 + @index0 + @index1 + @index2, @index49 + @index3 + @index0 + @index1, @index50 + @index2 + @index3 + @index0, @index51 + @index1 + @index2 + @index3, @index52 + @index0 + @index1 + @index2, @index53 + @index3 + @index0 + @index1, @index54 + @index2 + @index3 + @index0, @index55 + @index1 + @index2], @index56 + @index3) + +Test case: CALC_ALL_COMMON_SUBEXPR +Source: [0, 1] + [0, 1] + [1, 2] + [1, 2] + [2, 3] + [2, 3] + [3, 4] + [3, 4] + [4, 5] + [4, 5] + [5, 6] + [5, 6] + [6, 7] + [6, 7] + [7, 8] + [7, 8] + [8, 9] + [8, 9] + [9, 10] + [9, 10] + [10, 11] + [10, 11] + [11, 12] + [11, 12] + [12, 13] + [12, 13] + [13, 14] + [13, 14] + [14, 15] + [14, 15] + [15, 16] + [15, 16] + [16, 17] + [16, 17] + [17, 18] + [17, 18] + [18, 19] + [18, 19] + [19, 20] + [19, 20] + [20, 21] + [20, 21] + [21, 22] + [21, 22] + [22, 23] + [22, 23] + [23, 24] + [23, 24] + [24, 25] + [24, 25] + [25, 26] + [25, 26] + [26, 27] + [26, 27] + [27, 28] + [27, 28] + [28, 29] + [28, 29] + [29, 30] + [29, 30] + [30, 31] + [30, 31] + [31, 32] + [31, 32] + [32, 33] + [32, 33] + [33, 34] + [33, 34] + [34, 35] + [34, 35] + [35, 36] + [35, 36] + [36, 37] + [36, 37] + [37, 38] + [37, 38] + [38, 39] + [38, 39] + [39, 40] + [39, 40] + [40, 41] + [40, 41] + [41, 42] + [41, 42] + [42, 43] + [42, 43] + [43, 44] + [43, 44] + [44, 45] + [44, 45] + [45, 46] + [45, 46] + [46, 47] + [46, 47] + [47, 48] + [47, 48] + [48, 49] + [48, 49] + [49, 50] + [49, 50] +=====> +Result: [0, 1, 0, 1, 1, 2, 1, 2, 2, 3, 2, 3, 3, 4, 3, 4, 4, 5, 4, 5, 5, 6, 5, 6, 6, 7, 6, 7, 7, 8, 7, 8, 8, 9, 8, 9, 9, 10, 9, 10, 10, 11, 10, 11, 11, 12, 11, 12, 12, 13, 12, 13, 13, 14, 13, 14, 14, 15, 14, 15, 15, 16, 15, 16, 16, 17, 16, 17, 17, 18, 17, 18, 18, 19, 18, 19, 19, 20, 19, 20, 20, 21, 20, 21, 21, 22, 21, 22, 22, 23, 22, 23, 23, 24, 23, 24, 24, 25, 24, 25, 25, 26, 25, 26, 26, 27, 26, 27, 27, 28, 27, 28, 28, 29, 28, 29, 29, 30, 29, 30, 30, 31, 30, 31, 31, 32, 31, 32, 32, 33, 32, 33, 33, 34, 33, 34, 34, 35, 34, 35, 35, 36, 35, 36, 36, 37, 36, 37, 37, 38, 37, 38, 38, 39, 38, 39, 39, 40, 39, 40, 40, 41, 40, 41, 41, 42, 41, 42, 42, 43, 42, 43, 43, 44, 43, 44, 44, 45, 44, 45, 45, 46, 45, 46, 46, 47, 46, 47, 47, 48, 47, 48, 48, 49, 48, 49, 49, 50, 49, 50] +Unparsed: cel.@block([[0, 1], [1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7], [7, 8], [8, 9], [9, 10], [10, 11], [11, 12], [12, 13], [13, 14], [14, 15], [15, 16], [16, 17], [17, 18], [18, 19], [19, 20], [20, 21], [21, 22], [22, 23], [23, 24], [24, 25], [25, 26], [26, 27], [27, 28], [28, 29], [29, 30], [30, 31], [31, 32], [32, 33], [33, 34], [34, 35], [35, 36], [36, 37], [37, 38], [38, 39], [39, 40], [40, 41], [41, 42], [42, 43], [43, 44], [44, 45], [45, 46], [46, 47], [47, 48], [48, 49], [49, 50], @index0 + @index0 + @index1 + @index1, @index50 + @index2 + @index2 + @index3, @index51 + @index3 + @index4 + @index4, @index52 + @index5 + @index5 + @index6, @index53 + @index6 + @index7 + @index7, @index54 + @index8 + @index8 + @index9, @index55 + @index9 + @index10 + @index10, @index56 + @index11 + @index11 + @index12, @index57 + @index12 + @index13 + @index13, @index58 + @index14 + @index14 + @index15, @index59 + @index15 + @index16 + @index16, @index60 + @index17 + @index17 + @index18, @index61 + @index18 + @index19 + @index19, @index62 + @index20 + @index20 + @index21, @index63 + @index21 + @index22 + @index22, @index64 + @index23 + @index23 + @index24, @index65 + @index24 + @index25 + @index25, @index66 + @index26 + @index26 + @index27, @index67 + @index27 + @index28 + @index28, @index68 + @index29 + @index29 + @index30, @index69 + @index30 + @index31 + @index31, @index70 + @index32 + @index32 + @index33, @index71 + @index33 + @index34 + @index34, @index72 + @index35 + @index35 + @index36, @index73 + @index36 + @index37 + @index37, @index74 + @index38 + @index38 + @index39, @index75 + @index39 + @index40 + @index40, @index76 + @index41 + @index41 + @index42, @index77 + @index42 + @index43 + @index43, @index78 + @index44 + @index44 + @index45, @index79 + @index45 + @index46 + @index46, @index80 + @index47 + @index47 + @index48, @index81 + @index48 + @index49], @index82 + @index49) + +Test case: NESTED_MACROS +Source: [1,2,3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3])))))))) +=====> +Result: [[[[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]]], [[[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]]], [[[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]]]] +Unparsed: cel.@block([[1, 2, 3], @index0.map(@c7:0, @index0), @index0.map(@c6:0, @index1), @index0.map(@c5:0, @index2), @index0.map(@c4:0, @index3), @index0.map(@c3:0, @index4), @index0.map(@c2:0, @index5), @index0.map(@c1:0, @index6), @x0:0 + [@index7]], @index0.map(@c0:0, @index7)) diff --git a/optimizer/src/test/resources/subexpression_ast_block_common_subexpr_only.baseline b/optimizer/src/test/resources/subexpression_ast_block_common_subexpr_only.baseline new file mode 100644 index 000000000..1b0adb211 --- /dev/null +++ b/optimizer/src/test/resources/subexpression_ast_block_common_subexpr_only.baseline @@ -0,0 +1,2924 @@ +Test case: SIZE_1 +Source: size([1,2]) + size([1,2]) + 1 == 5 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: size + args: { + CREATE_LIST [4] { + elements: { + CONSTANT [5] { value: 1 } + CONSTANT [6] { value: 2 } + } + } + } + } + } + } + CALL [7] { + function: _==_ + args: { + CALL [8] { + function: _+_ + args: { + CALL [9] { + function: _+_ + args: { + IDENT [10] { + name: @index0 + } + IDENT [11] { + name: @index0 + } + } + } + CONSTANT [12] { value: 1 } + } + } + CONSTANT [13] { value: 5 } + } + } + } +} +Test case: SIZE_2 +Source: 2 + size([1,2]) + size([1,2]) + 1 == 7 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: size + args: { + CREATE_LIST [4] { + elements: { + CONSTANT [5] { value: 1 } + CONSTANT [6] { value: 2 } + } + } + } + } + } + } + CALL [7] { + function: _==_ + args: { + CALL [8] { + function: _+_ + args: { + CALL [9] { + function: _+_ + args: { + CALL [10] { + function: _+_ + args: { + CONSTANT [11] { value: 2 } + IDENT [12] { + name: @index0 + } + } + } + IDENT [13] { + name: @index0 + } + } + } + CONSTANT [14] { value: 1 } + } + } + CONSTANT [15] { value: 7 } + } + } + } +} +Test case: SIZE_3 +Source: size([0]) + size([0]) + size([1,2]) + size([1,2]) == 6 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: size + args: { + CREATE_LIST [4] { + elements: { + CONSTANT [5] { value: 0 } + } + } + } + } + CALL [6] { + function: size + args: { + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 1 } + CONSTANT [9] { value: 2 } + } + } + } + } + } + } + CALL [10] { + function: _==_ + args: { + CALL [11] { + function: _+_ + args: { + CALL [12] { + function: _+_ + args: { + CALL [13] { + function: _+_ + args: { + IDENT [14] { + name: @index0 + } + IDENT [15] { + name: @index0 + } + } + } + IDENT [16] { + name: @index1 + } + } + } + IDENT [17] { + name: @index1 + } + } + } + CONSTANT [18] { value: 6 } + } + } + } +} +Test case: SIZE_4 +Source: 5 + size([0]) + size([0]) + size([1,2]) + size([1,2]) + size([1,2,3]) + size([1,2,3]) == 17 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: size + args: { + CREATE_LIST [4] { + elements: { + CONSTANT [5] { value: 0 } + } + } + } + } + CALL [6] { + function: size + args: { + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 1 } + CONSTANT [9] { value: 2 } + } + } + } + } + CALL [10] { + function: size + args: { + CREATE_LIST [11] { + elements: { + CONSTANT [12] { value: 1 } + CONSTANT [13] { value: 2 } + CONSTANT [14] { value: 3 } + } + } + } + } + } + } + CALL [15] { + function: _==_ + args: { + CALL [16] { + function: _+_ + args: { + CALL [17] { + function: _+_ + args: { + CALL [18] { + function: _+_ + args: { + CALL [19] { + function: _+_ + args: { + CALL [20] { + function: _+_ + args: { + CALL [21] { + function: _+_ + args: { + CONSTANT [22] { value: 5 } + IDENT [23] { + name: @index0 + } + } + } + IDENT [24] { + name: @index0 + } + } + } + IDENT [25] { + name: @index1 + } + } + } + IDENT [26] { + name: @index1 + } + } + } + IDENT [27] { + name: @index2 + } + } + } + IDENT [28] { + name: @index2 + } + } + } + CONSTANT [29] { value: 17 } + } + } + } +} +Test case: TIMESTAMP +Source: timestamp(int(timestamp(1000000000))).getFullYear() + timestamp(int(timestamp(75))).getFullYear() + timestamp(int(timestamp(50))).getFullYear() + timestamp(int(timestamp(1000000000))).getFullYear() + timestamp(int(timestamp(50))).getSeconds() + timestamp(int(timestamp(200))).getFullYear() + timestamp(int(timestamp(200))).getFullYear() + timestamp(int(timestamp(75))).getMinutes() + timestamp(int(timestamp(1000000000))).getFullYear() == 13934 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: getFullYear + target: { + CALL [4] { + function: timestamp + args: { + CALL [5] { + function: int + args: { + CALL [6] { + function: timestamp + args: { + CONSTANT [7] { value: 1000000000 } + } + } + } + } + } + } + } + args: { + } + } + CALL [8] { + function: timestamp + args: { + CALL [9] { + function: int + args: { + CALL [10] { + function: timestamp + args: { + CONSTANT [11] { value: 50 } + } + } + } + } + } + } + CALL [12] { + function: getFullYear + target: { + CALL [13] { + function: timestamp + args: { + CALL [14] { + function: int + args: { + CALL [15] { + function: timestamp + args: { + CONSTANT [16] { value: 200 } + } + } + } + } + } + } + } + args: { + } + } + CALL [17] { + function: timestamp + args: { + CALL [18] { + function: int + args: { + CALL [19] { + function: timestamp + args: { + CONSTANT [20] { value: 75 } + } + } + } + } + } + } + } + } + CALL [21] { + function: _==_ + args: { + CALL [22] { + function: _+_ + args: { + CALL [23] { + function: _+_ + args: { + CALL [24] { + function: _+_ + args: { + CALL [25] { + function: _+_ + args: { + CALL [26] { + function: _+_ + args: { + CALL [27] { + function: _+_ + args: { + CALL [28] { + function: _+_ + args: { + CALL [29] { + function: _+_ + args: { + IDENT [30] { + name: @index0 + } + CALL [31] { + function: getFullYear + target: { + IDENT [32] { + name: @index3 + } + } + args: { + } + } + } + } + CALL [33] { + function: getFullYear + target: { + IDENT [34] { + name: @index1 + } + } + args: { + } + } + } + } + IDENT [35] { + name: @index0 + } + } + } + CALL [36] { + function: getSeconds + target: { + IDENT [37] { + name: @index1 + } + } + args: { + } + } + } + } + IDENT [38] { + name: @index2 + } + } + } + IDENT [39] { + name: @index2 + } + } + } + CALL [40] { + function: getMinutes + target: { + IDENT [41] { + name: @index3 + } + } + args: { + } + } + } + } + IDENT [42] { + name: @index0 + } + } + } + CONSTANT [43] { value: 13934 } + } + } + } +} +Test case: MAP_INDEX +Source: {"a": 2}["a"] + {"a": 2}["a"] * {"a": 2}["a"] == 6 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _[_] + args: { + CREATE_MAP [4] { + MAP_ENTRY [5] { + key: { + CONSTANT [6] { value: "a" } + } + value: { + CONSTANT [7] { value: 2 } + } + } + } + CONSTANT [8] { value: "a" } + } + } + } + } + CALL [9] { + function: _==_ + args: { + CALL [10] { + function: _+_ + args: { + IDENT [11] { + name: @index0 + } + CALL [12] { + function: _*_ + args: { + IDENT [13] { + name: @index0 + } + IDENT [14] { + name: @index0 + } + } + } + } + } + CONSTANT [15] { value: 6 } + } + } + } +} +Test case: NESTED_MAP_CONSTRUCTION +Source: {'a': {'b': 1}, 'c': {'b': 1}, 'd': {'e': {'b': 1}}, 'e': {'e': {'b': 1}}} +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: "b" } + } + value: { + CONSTANT [6] { value: 1 } + } + } + } + CREATE_MAP [7] { + MAP_ENTRY [8] { + key: { + CONSTANT [9] { value: "e" } + } + value: { + IDENT [10] { + name: @index0 + } + } + } + } + } + } + CREATE_MAP [11] { + MAP_ENTRY [12] { + key: { + CONSTANT [13] { value: "a" } + } + value: { + IDENT [14] { + name: @index0 + } + } + } + MAP_ENTRY [15] { + key: { + CONSTANT [16] { value: "c" } + } + value: { + IDENT [17] { + name: @index0 + } + } + } + MAP_ENTRY [18] { + key: { + CONSTANT [19] { value: "d" } + } + value: { + IDENT [20] { + name: @index1 + } + } + } + MAP_ENTRY [21] { + key: { + CONSTANT [22] { value: "e" } + } + value: { + IDENT [23] { + name: @index1 + } + } + } + } + } +} +Test case: NESTED_LIST_CONSTRUCTION +Source: [1, [1,2,3,4], 2, [1,2,3,4], 5, [1,2,3,4], 7, [[1,2], [1,2,3,4]], [1,2]] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + CONSTANT [6] { value: 3 } + CONSTANT [7] { value: 4 } + } + } + CREATE_LIST [8] { + elements: { + CONSTANT [9] { value: 1 } + CONSTANT [10] { value: 2 } + } + } + } + } + CREATE_LIST [11] { + elements: { + CONSTANT [12] { value: 1 } + IDENT [13] { + name: @index0 + } + CONSTANT [14] { value: 2 } + IDENT [15] { + name: @index0 + } + CONSTANT [16] { value: 5 } + IDENT [17] { + name: @index0 + } + CONSTANT [18] { value: 7 } + CREATE_LIST [19] { + elements: { + IDENT [20] { + name: @index1 + } + IDENT [21] { + name: @index0 + } + } + } + IDENT [22] { + name: @index1 + } + } + } + } +} +Test case: SELECT +Source: msg.single_int64 + msg.single_int64 == 6 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.single_int64 + } + } + } + CALL [5] { + function: _==_ + args: { + CALL [6] { + function: _+_ + args: { + IDENT [7] { + name: @index0 + } + IDENT [8] { + name: @index0 + } + } + } + CONSTANT [9] { value: 6 } + } + } + } +} +Test case: SELECT_NESTED_1 +Source: msg.oneof_type.payload.single_int64 + msg.oneof_type.payload.single_int32 + msg.oneof_type.payload.single_int64 + msg.single_int64 + msg.oneof_type.payload.oneof_type.payload.single_int64 == 31 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + SELECT [4] { + IDENT [5] { + name: msg + }.oneof_type + }.payload + } + SELECT [6] { + IDENT [7] { + name: @index0 + }.single_int64 + } + } + } + CALL [8] { + function: _==_ + args: { + CALL [9] { + function: _+_ + args: { + CALL [10] { + function: _+_ + args: { + CALL [11] { + function: _+_ + args: { + CALL [12] { + function: _+_ + args: { + IDENT [13] { + name: @index1 + } + SELECT [14] { + IDENT [15] { + name: @index0 + }.single_int32 + } + } + } + IDENT [16] { + name: @index1 + } + } + } + SELECT [17] { + IDENT [18] { + name: msg + }.single_int64 + } + } + } + SELECT [19] { + SELECT [20] { + SELECT [21] { + IDENT [22] { + name: @index0 + }.oneof_type + }.payload + }.single_int64 + } + } + } + CONSTANT [23] { value: 31 } + } + } + } +} +Test case: SELECT_NESTED_2 +Source: true || msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload.single_bool || msg.oneof_type.payload.oneof_type.payload.oneof_type.child.child.payload.single_bool +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + SELECT [4] { + SELECT [5] { + SELECT [6] { + SELECT [7] { + IDENT [8] { + name: msg + }.oneof_type + }.payload + }.oneof_type + }.payload + }.oneof_type + } + } + } + CALL [9] { + function: _||_ + args: { + CALL [10] { + function: _||_ + args: { + CONSTANT [11] { value: true } + SELECT [12] { + SELECT [13] { + SELECT [14] { + SELECT [15] { + IDENT [16] { + name: @index0 + }.payload + }.oneof_type + }.payload + }.single_bool + } + } + } + SELECT [17] { + SELECT [18] { + SELECT [19] { + SELECT [20] { + IDENT [21] { + name: @index0 + }.child + }.child + }.payload + }.single_bool + } + } + } + } +} +Test case: SELECT_NESTED_MESSAGE_MAP_INDEX_1 +Source: msg.oneof_type.payload.map_int32_int64[1] + msg.oneof_type.payload.map_int32_int64[1] + msg.oneof_type.payload.map_int32_int64[1] == 15 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _[_] + args: { + SELECT [4] { + SELECT [5] { + SELECT [6] { + IDENT [7] { + name: msg + }.oneof_type + }.payload + }.map_int32_int64 + } + CONSTANT [8] { value: 1 } + } + } + } + } + CALL [9] { + function: _==_ + args: { + CALL [10] { + function: _+_ + args: { + CALL [11] { + function: _+_ + args: { + IDENT [12] { + name: @index0 + } + IDENT [13] { + name: @index0 + } + } + } + IDENT [14] { + name: @index0 + } + } + } + CONSTANT [15] { value: 15 } + } + } + } +} +Test case: SELECT_NESTED_MESSAGE_MAP_INDEX_2 +Source: msg.oneof_type.payload.map_int32_int64[0] + msg.oneof_type.payload.map_int32_int64[1] + msg.oneof_type.payload.map_int32_int64[2] == 8 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + SELECT [4] { + SELECT [5] { + IDENT [6] { + name: msg + }.oneof_type + }.payload + }.map_int32_int64 + } + } + } + CALL [7] { + function: _==_ + args: { + CALL [8] { + function: _+_ + args: { + CALL [9] { + function: _+_ + args: { + CALL [10] { + function: _[_] + args: { + IDENT [11] { + name: @index0 + } + CONSTANT [12] { value: 0 } + } + } + CALL [13] { + function: _[_] + args: { + IDENT [14] { + name: @index0 + } + CONSTANT [15] { value: 1 } + } + } + } + } + CALL [16] { + function: _[_] + args: { + IDENT [17] { + name: @index0 + } + CONSTANT [18] { value: 2 } + } + } + } + } + CONSTANT [19] { value: 8 } + } + } + } +} +Test case: SELECT_NESTED_NO_COMMON_SUBEXPR +Source: msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload.single_int64 +=====> +SELECT [10] { + SELECT [9] { + SELECT [8] { + SELECT [7] { + SELECT [6] { + SELECT [5] { + SELECT [4] { + SELECT [3] { + SELECT [2] { + IDENT [1] { + name: msg + }.oneof_type + }.payload + }.oneof_type + }.payload + }.oneof_type + }.payload + }.oneof_type + }.payload + }.single_int64 +} +Test case: TERNARY +Source: (msg.single_int64 > 0 ? msg.single_int64 : 0) == 3 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.single_int64 + } + } + } + CALL [5] { + function: _==_ + args: { + CALL [6] { + function: _?_:_ + args: { + CALL [7] { + function: _>_ + args: { + IDENT [8] { + name: @index0 + } + CONSTANT [9] { value: 0 } + } + } + IDENT [10] { + name: @index0 + } + CONSTANT [11] { value: 0 } + } + } + CONSTANT [12] { value: 3 } + } + } + } +} +Test case: TERNARY_BIND_RHS_ONLY +Source: false ? false : (msg.single_int64) + ((msg.single_int64 + 1) * 2) == 11 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.single_int64 + } + } + } + CALL [5] { + function: _?_:_ + args: { + CONSTANT [6] { value: false } + CONSTANT [7] { value: false } + CALL [8] { + function: _==_ + args: { + CALL [9] { + function: _+_ + args: { + IDENT [10] { + name: @index0 + } + CALL [11] { + function: _*_ + args: { + CALL [12] { + function: _+_ + args: { + IDENT [13] { + name: @index0 + } + CONSTANT [14] { value: 1 } + } + } + CONSTANT [15] { value: 2 } + } + } + } + } + CONSTANT [16] { value: 11 } + } + } + } + } + } +} +Test case: NESTED_TERNARY +Source: (msg.single_int64 > 0 ? (msg.single_int32 > 0 ? msg.single_int64 + msg.single_int32 : 0) : 0) == 8 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.single_int64 + } + SELECT [5] { + IDENT [6] { + name: msg + }.single_int32 + } + } + } + CALL [7] { + function: _==_ + args: { + CALL [8] { + function: _?_:_ + args: { + CALL [9] { + function: _>_ + args: { + IDENT [10] { + name: @index0 + } + CONSTANT [11] { value: 0 } + } + } + CALL [12] { + function: _?_:_ + args: { + CALL [13] { + function: _>_ + args: { + IDENT [14] { + name: @index1 + } + CONSTANT [15] { value: 0 } + } + } + CALL [16] { + function: _+_ + args: { + IDENT [17] { + name: @index0 + } + IDENT [18] { + name: @index1 + } + } + } + CONSTANT [19] { value: 0 } + } + } + CONSTANT [20] { value: 0 } + } + } + CONSTANT [21] { value: 8 } + } + } + } +} +Test case: MULTIPLE_MACROS_1 +Source: size([[1].exists(i, i > 0)]) + size([[1].exists(j, j > 0)]) + size([[2].exists(k, k > 1)]) + size([[2].exists(l, l > 1)]) == 4 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: size + args: { + CREATE_LIST [4] { + elements: { + COMPREHENSION [5] { + iter_var: @c0:0 + iter_range: { + CREATE_LIST [6] { + elements: { + CONSTANT [7] { value: 1 } + } + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [8] { value: false } + } + loop_condition: { + CALL [9] { + function: @not_strictly_false + args: { + CALL [10] { + function: !_ + args: { + IDENT [11] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + CALL [12] { + function: _||_ + args: { + IDENT [13] { + name: @x0:0 + } + CALL [14] { + function: _>_ + args: { + IDENT [15] { + name: @c0:0 + } + CONSTANT [16] { value: 0 } + } + } + } + } + } + result: { + IDENT [17] { + name: @x0:0 + } + } + } + } + } + } + } + CALL [18] { + function: size + args: { + CREATE_LIST [19] { + elements: { + COMPREHENSION [20] { + iter_var: @c0:0 + iter_range: { + CREATE_LIST [21] { + elements: { + CONSTANT [22] { value: 2 } + } + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [23] { value: false } + } + loop_condition: { + CALL [24] { + function: @not_strictly_false + args: { + CALL [25] { + function: !_ + args: { + IDENT [26] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + CALL [27] { + function: _||_ + args: { + IDENT [28] { + name: @x0:0 + } + CALL [29] { + function: _>_ + args: { + IDENT [30] { + name: @c0:0 + } + CONSTANT [31] { value: 1 } + } + } + } + } + } + result: { + IDENT [32] { + name: @x0:0 + } + } + } + } + } + } + } + } + } + CALL [33] { + function: _==_ + args: { + CALL [34] { + function: _+_ + args: { + CALL [35] { + function: _+_ + args: { + CALL [36] { + function: _+_ + args: { + IDENT [37] { + name: @index0 + } + IDENT [38] { + name: @index0 + } + } + } + IDENT [39] { + name: @index1 + } + } + } + IDENT [40] { + name: @index1 + } + } + } + CONSTANT [41] { value: 4 } + } + } + } +} +Test case: MULTIPLE_MACROS_2 +Source: [[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == 'a')] + [['a'].exists(l, l == 'a')] == [true, true, true, true] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + COMPREHENSION [4] { + iter_var: @c0:0 + iter_range: { + CREATE_LIST [5] { + elements: { + CONSTANT [6] { value: 1 } + } + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [7] { value: false } + } + loop_condition: { + CALL [8] { + function: @not_strictly_false + args: { + CALL [9] { + function: !_ + args: { + IDENT [10] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + CALL [11] { + function: _||_ + args: { + IDENT [12] { + name: @x0:0 + } + CALL [13] { + function: _>_ + args: { + IDENT [14] { + name: @c0:0 + } + CONSTANT [15] { value: 0 } + } + } + } + } + } + result: { + IDENT [16] { + name: @x0:0 + } + } + } + } + } + CREATE_LIST [17] { + elements: { + COMPREHENSION [18] { + iter_var: @c0:1 + iter_range: { + CREATE_LIST [19] { + elements: { + CONSTANT [20] { value: "a" } + } + } + } + accu_var: @x0:1 + accu_init: { + CONSTANT [21] { value: false } + } + loop_condition: { + CALL [22] { + function: @not_strictly_false + args: { + CALL [23] { + function: !_ + args: { + IDENT [24] { + name: @x0:1 + } + } + } + } + } + } + loop_step: { + CALL [25] { + function: _||_ + args: { + IDENT [26] { + name: @x0:1 + } + CALL [27] { + function: _==_ + args: { + IDENT [28] { + name: @c0:1 + } + CONSTANT [29] { value: "a" } + } + } + } + } + } + result: { + IDENT [30] { + name: @x0:1 + } + } + } + } + } + } + } + CALL [31] { + function: _==_ + args: { + CALL [32] { + function: _+_ + args: { + CALL [33] { + function: _+_ + args: { + CALL [34] { + function: _+_ + args: { + IDENT [35] { + name: @index0 + } + IDENT [36] { + name: @index0 + } + } + } + IDENT [37] { + name: @index1 + } + } + } + IDENT [38] { + name: @index1 + } + } + } + CREATE_LIST [39] { + elements: { + CONSTANT [40] { value: true } + CONSTANT [41] { value: true } + CONSTANT [42] { value: true } + CONSTANT [43] { value: true } + } + } + } + } + } +} +Test case: NESTED_MACROS +Source: [1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [[2, 3, 4], [2, 3, 4], [2, 3, 4]] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + CONSTANT [6] { value: 3 } + } + } + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 2 } + CONSTANT [9] { value: 3 } + CONSTANT [10] { value: 4 } + } + } + } + } + CALL [11] { + function: _==_ + args: { + COMPREHENSION [12] { + iter_var: @c0:0 + iter_range: { + IDENT [13] { + name: @index0 + } + } + accu_var: @x0:0 + accu_init: { + CREATE_LIST [14] { + elements: { + } + } + } + loop_condition: { + CONSTANT [15] { value: true } + } + loop_step: { + CALL [16] { + function: _+_ + args: { + IDENT [17] { + name: @x0:0 + } + CREATE_LIST [18] { + elements: { + COMPREHENSION [19] { + iter_var: @c1:0 + iter_range: { + IDENT [20] { + name: @index0 + } + } + accu_var: @x1:0 + accu_init: { + CREATE_LIST [21] { + elements: { + } + } + } + loop_condition: { + CONSTANT [22] { value: true } + } + loop_step: { + CALL [23] { + function: _+_ + args: { + IDENT [24] { + name: @x1:0 + } + CREATE_LIST [25] { + elements: { + CALL [26] { + function: _+_ + args: { + IDENT [27] { + name: @c1:0 + } + CONSTANT [28] { value: 1 } + } + } + } + } + } + } + } + result: { + IDENT [29] { + name: @x1:0 + } + } + } + } + } + } + } + } + result: { + IDENT [30] { + name: @x0:0 + } + } + } + CREATE_LIST [31] { + elements: { + IDENT [32] { + name: @index1 + } + IDENT [33] { + name: @index1 + } + IDENT [34] { + name: @index1 + } + } + } + } + } + } +} +Test case: NESTED_MACROS_2 +Source: [1, 2].map(y, [1, 2, 3].filter(x, x == y)) == [[1], [2]] +=====> +CALL [31] { + function: _==_ + args: { + COMPREHENSION [30] { + iter_var: @c0:0 + iter_range: { + CREATE_LIST [1] { + elements: { + CONSTANT [2] { value: 1 } + CONSTANT [3] { value: 2 } + } + } + } + accu_var: @x0:0 + accu_init: { + CREATE_LIST [24] { + elements: { + } + } + } + loop_condition: { + CONSTANT [25] { value: true } + } + loop_step: { + CALL [28] { + function: _+_ + args: { + IDENT [26] { + name: @x0:0 + } + CREATE_LIST [27] { + elements: { + COMPREHENSION [23] { + iter_var: @c1:0 + iter_range: { + CREATE_LIST [6] { + elements: { + CONSTANT [7] { value: 1 } + CONSTANT [8] { value: 2 } + CONSTANT [9] { value: 3 } + } + } + } + accu_var: @x1:0 + accu_init: { + CREATE_LIST [15] { + elements: { + } + } + } + loop_condition: { + CONSTANT [16] { value: true } + } + loop_step: { + CALL [21] { + function: _?_:_ + args: { + CALL [13] { + function: _==_ + args: { + IDENT [12] { + name: @c1:0 + } + IDENT [14] { + name: @c0:0 + } + } + } + CALL [19] { + function: _+_ + args: { + IDENT [17] { + name: @x1:0 + } + CREATE_LIST [18] { + elements: { + IDENT [11] { + name: @c1:0 + } + } + } + } + } + IDENT [20] { + name: @x1:0 + } + } + } + } + result: { + IDENT [22] { + name: @x1:0 + } + } + } + } + } + } + } + } + result: { + IDENT [29] { + name: @x0:0 + } + } + } + CREATE_LIST [32] { + elements: { + CREATE_LIST [33] { + elements: { + CONSTANT [34] { value: 1 } + } + } + CREATE_LIST [35] { + elements: { + CONSTANT [36] { value: 2 } + } + } + } + } + } +} +Test case: INCLUSION_LIST +Source: 1 in [1,2,3] && 2 in [1,2,3] && 3 in [3, [1,2,3]] && 1 in [1,2,3] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + CONSTANT [6] { value: 3 } + } + } + CALL [7] { + function: @in + args: { + CONSTANT [8] { value: 1 } + IDENT [9] { + name: @index0 + } + } + } + } + } + CALL [10] { + function: _&&_ + args: { + CALL [11] { + function: _&&_ + args: { + IDENT [12] { + name: @index1 + } + CALL [13] { + function: @in + args: { + CONSTANT [14] { value: 2 } + IDENT [15] { + name: @index0 + } + } + } + } + } + CALL [16] { + function: _&&_ + args: { + CALL [17] { + function: @in + args: { + CONSTANT [18] { value: 3 } + CREATE_LIST [19] { + elements: { + CONSTANT [20] { value: 3 } + IDENT [21] { + name: @index0 + } + } + } + } + } + IDENT [22] { + name: @index1 + } + } + } + } + } + } +} +Test case: INCLUSION_MAP +Source: 2 in {'a': 1, 2: {true: false}, 3: {true: false}} +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: true } + } + value: { + CONSTANT [6] { value: false } + } + } + } + } + } + CALL [7] { + function: @in + args: { + CONSTANT [8] { value: 2 } + CREATE_MAP [9] { + MAP_ENTRY [10] { + key: { + CONSTANT [11] { value: "a" } + } + value: { + CONSTANT [12] { value: 1 } + } + } + MAP_ENTRY [13] { + key: { + CONSTANT [14] { value: 2 } + } + value: { + IDENT [15] { + name: @index0 + } + } + } + MAP_ENTRY [16] { + key: { + CONSTANT [17] { value: 3 } + } + value: { + IDENT [18] { + name: @index0 + } + } + } + } + } + } + } +} +Test case: MACRO_ITER_VAR_NOT_REFERENCED +Source: [1,2].map(i, [1, 2].map(i, [3,4])) == [[[3, 4], [3, 4]], [[3, 4], [3, 4]]] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + } + } + CREATE_LIST [6] { + elements: { + CONSTANT [7] { value: 3 } + CONSTANT [8] { value: 4 } + } + } + CREATE_LIST [9] { + elements: { + IDENT [10] { + name: @index1 + } + IDENT [11] { + name: @index1 + } + } + } + } + } + CALL [12] { + function: _==_ + args: { + COMPREHENSION [13] { + iter_var: @c0:0 + iter_range: { + IDENT [14] { + name: @index0 + } + } + accu_var: @x0:0 + accu_init: { + CREATE_LIST [15] { + elements: { + } + } + } + loop_condition: { + CONSTANT [16] { value: true } + } + loop_step: { + CALL [17] { + function: _+_ + args: { + IDENT [18] { + name: @x0:0 + } + CREATE_LIST [19] { + elements: { + COMPREHENSION [20] { + iter_var: @c1:0 + iter_range: { + IDENT [21] { + name: @index0 + } + } + accu_var: @x1:0 + accu_init: { + CREATE_LIST [22] { + elements: { + } + } + } + loop_condition: { + CONSTANT [23] { value: true } + } + loop_step: { + CALL [24] { + function: _+_ + args: { + IDENT [25] { + name: @x1:0 + } + CREATE_LIST [26] { + elements: { + IDENT [27] { + name: @index1 + } + } + } + } + } + } + result: { + IDENT [28] { + name: @x1:0 + } + } + } + } + } + } + } + } + result: { + IDENT [29] { + name: @x0:0 + } + } + } + CREATE_LIST [30] { + elements: { + IDENT [31] { + name: @index2 + } + IDENT [32] { + name: @index2 + } + } + } + } + } + } +} +Test case: MACRO_SHADOWED_VARIABLE +Source: [x - 1 > 3 ? x - 1 : 5].exists(x, x - 1 > 3) || x - 1 > 3 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _-_ + args: { + IDENT [4] { + name: x + } + CONSTANT [5] { value: 1 } + } + } + CALL [6] { + function: _>_ + args: { + IDENT [7] { + name: @index0 + } + CONSTANT [8] { value: 3 } + } + } + } + } + CALL [9] { + function: _||_ + args: { + COMPREHENSION [10] { + iter_var: @c0:0 + iter_range: { + CREATE_LIST [11] { + elements: { + CALL [12] { + function: _?_:_ + args: { + IDENT [13] { + name: @index1 + } + IDENT [14] { + name: @index0 + } + CONSTANT [15] { value: 5 } + } + } + } + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [16] { value: false } + } + loop_condition: { + CALL [17] { + function: @not_strictly_false + args: { + CALL [18] { + function: !_ + args: { + IDENT [19] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + CALL [20] { + function: _||_ + args: { + IDENT [21] { + name: @x0:0 + } + CALL [22] { + function: _>_ + args: { + CALL [23] { + function: _-_ + args: { + IDENT [24] { + name: @c0:0 + } + CONSTANT [25] { value: 1 } + } + } + CONSTANT [26] { value: 3 } + } + } + } + } + } + result: { + IDENT [27] { + name: @x0:0 + } + } + } + IDENT [28] { + name: @index1 + } + } + } + } +} +Test case: MACRO_SHADOWED_VARIABLE_2 +Source: ["foo", "bar"].map(x, [x + x, x + x]).map(x, [x + x, x + x]) +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _+_ + args: { + IDENT [4] { + name: @c1:0 + } + IDENT [5] { + name: @c1:0 + } + } + } + CALL [6] { + function: _+_ + args: { + IDENT [7] { + name: @c0:0 + } + IDENT [8] { + name: @c0:0 + } + } + } + } + } + COMPREHENSION [9] { + iter_var: @c0:0 + iter_range: { + COMPREHENSION [10] { + iter_var: @c1:0 + iter_range: { + CREATE_LIST [11] { + elements: { + CONSTANT [12] { value: "foo" } + CONSTANT [13] { value: "bar" } + } + } + } + accu_var: @x1:0 + accu_init: { + CREATE_LIST [14] { + elements: { + } + } + } + loop_condition: { + CONSTANT [15] { value: true } + } + loop_step: { + CALL [16] { + function: _+_ + args: { + IDENT [17] { + name: @x1:0 + } + CREATE_LIST [18] { + elements: { + CREATE_LIST [19] { + elements: { + IDENT [20] { + name: @index0 + } + IDENT [21] { + name: @index0 + } + } + } + } + } + } + } + } + result: { + IDENT [22] { + name: @x1:0 + } + } + } + } + accu_var: @x0:0 + accu_init: { + CREATE_LIST [23] { + elements: { + } + } + } + loop_condition: { + CONSTANT [24] { value: true } + } + loop_step: { + CALL [25] { + function: _+_ + args: { + IDENT [26] { + name: @x0:0 + } + CREATE_LIST [27] { + elements: { + CREATE_LIST [28] { + elements: { + IDENT [29] { + name: @index1 + } + IDENT [30] { + name: @index1 + } + } + } + } + } + } + } + } + result: { + IDENT [31] { + name: @x0:0 + } + } + } + } +} +Test case: PRESENCE_TEST +Source: has({'a': true}.a) && {'a':true}['a'] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: "a" } + } + value: { + CONSTANT [6] { value: true } + } + } + } + } + } + CALL [7] { + function: _&&_ + args: { + SELECT [8] { + IDENT [9] { + name: @index0 + }.a~presence_test + } + CALL [10] { + function: _[_] + args: { + IDENT [11] { + name: @index0 + } + CONSTANT [12] { value: "a" } + } + } + } + } + } +} +Test case: PRESENCE_TEST_WITH_TERNARY +Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : 0) == 10 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + } + } + CALL [5] { + function: _==_ + args: { + CALL [6] { + function: _?_:_ + args: { + SELECT [7] { + IDENT [8] { + name: @index0 + }.payload~presence_test + } + SELECT [9] { + SELECT [10] { + IDENT [11] { + name: @index0 + }.payload + }.single_int64 + } + CONSTANT [12] { value: 0 } + } + } + CONSTANT [13] { value: 10 } + } + } + } +} +Test case: PRESENCE_TEST_WITH_TERNARY_2 +Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : msg.oneof_type.payload.single_int64 * 0) == 10 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + SELECT [6] { + IDENT [7] { + name: @index0 + }.payload + }.single_int64 + } + } + } + CALL [8] { + function: _==_ + args: { + CALL [9] { + function: _?_:_ + args: { + SELECT [10] { + IDENT [11] { + name: @index0 + }.payload~presence_test + } + IDENT [12] { + name: @index1 + } + CALL [13] { + function: _*_ + args: { + IDENT [14] { + name: @index1 + } + CONSTANT [15] { value: 0 } + } + } + } + } + CONSTANT [16] { value: 10 } + } + } + } +} +Test case: PRESENCE_TEST_WITH_TERNARY_3 +Source: (has(msg.oneof_type.payload.single_int64) ? msg.oneof_type.payload.single_int64 : msg.oneof_type.payload.single_int64 * 0) == 10 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + SELECT [4] { + IDENT [5] { + name: msg + }.oneof_type + }.payload + } + SELECT [6] { + IDENT [7] { + name: @index0 + }.single_int64 + } + } + } + CALL [8] { + function: _==_ + args: { + CALL [9] { + function: _?_:_ + args: { + SELECT [10] { + IDENT [11] { + name: @index0 + }.single_int64~presence_test + } + IDENT [12] { + name: @index1 + } + CALL [13] { + function: _*_ + args: { + IDENT [14] { + name: @index1 + } + CONSTANT [15] { value: 0 } + } + } + } + } + CONSTANT [16] { value: 10 } + } + } + } +} +Test case: PRESENCE_TEST_WITH_TERNARY_NESTED +Source: (has(msg.oneof_type) && has(msg.oneof_type.payload) && has(msg.oneof_type.payload.single_int64)) ? ((has(msg.oneof_type.payload.map_string_string) && has(msg.oneof_type.payload.map_string_string.key)) ? msg.oneof_type.payload.map_string_string.key == 'A' : false) : false +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.map_string_string + } + } + } + CALL [9] { + function: _?_:_ + args: { + CALL [10] { + function: _&&_ + args: { + CALL [11] { + function: _&&_ + args: { + SELECT [12] { + IDENT [13] { + name: msg + }.oneof_type~presence_test + } + SELECT [14] { + IDENT [15] { + name: @index0 + }.payload~presence_test + } + } + } + SELECT [16] { + IDENT [17] { + name: @index1 + }.single_int64~presence_test + } + } + } + CALL [18] { + function: _?_:_ + args: { + CALL [19] { + function: _&&_ + args: { + SELECT [20] { + IDENT [21] { + name: @index1 + }.map_string_string~presence_test + } + SELECT [22] { + IDENT [23] { + name: @index2 + }.key~presence_test + } + } + } + CALL [24] { + function: _==_ + args: { + SELECT [25] { + IDENT [26] { + name: @index2 + }.key + } + CONSTANT [27] { value: "A" } + } + } + CONSTANT [28] { value: false } + } + } + CONSTANT [29] { value: false } + } + } + } +} +Test case: OPTIONAL_LIST +Source: [10, ?optional.none(), [?optional.none(), ?opt_x], [?optional.none(), ?opt_x]] == [10, [5], [5]] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: optional.none + args: { + } + } + CREATE_LIST [4] { + elements: { + IDENT [5] { + name: @index0 + } + IDENT [6] { + name: opt_x + } + } + optional_indices: [0, 1] + } + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 5 } + } + } + } + } + CALL [9] { + function: _==_ + args: { + CREATE_LIST [10] { + elements: { + CONSTANT [11] { value: 10 } + IDENT [12] { + name: @index0 + } + IDENT [13] { + name: @index1 + } + IDENT [14] { + name: @index1 + } + } + optional_indices: [0] + } + CREATE_LIST [15] { + elements: { + CONSTANT [16] { value: 10 } + IDENT [17] { + name: @index2 + } + IDENT [18] { + name: @index2 + } + } + } + } + } + } +} +Test case: OPTIONAL_MAP +Source: {?'hello': optional.of('hello')}['hello'] + {?'hello': optional.of('hello')}['hello'] == 'hellohello' +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _[_] + args: { + CREATE_MAP [4] { + MAP_ENTRY [5] { + key: { + CONSTANT [6] { value: "hello" } + } + optional_entry: true + value: { + CALL [7] { + function: optional.of + args: { + CONSTANT [8] { value: "hello" } + } + } + } + } + } + CONSTANT [9] { value: "hello" } + } + } + } + } + CALL [10] { + function: _==_ + args: { + CALL [11] { + function: _+_ + args: { + IDENT [12] { + name: @index0 + } + IDENT [13] { + name: @index0 + } + } + } + CONSTANT [14] { value: "hellohello" } + } + } + } +} +Test case: OPTIONAL_MAP_CHAINED +Source: {?'key': optional.of('test')}[?'bogus'].or({'key': 'test'}[?'bogus']).orValue({'key': 'test'}['key']) == 'test' +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: "key" } + } + value: { + CONSTANT [6] { value: "test" } + } + } + } + } + } + CALL [7] { + function: _==_ + args: { + CALL [8] { + function: orValue + target: { + CALL [9] { + function: or + target: { + CALL [10] { + function: _[?_] + args: { + CREATE_MAP [11] { + MAP_ENTRY [12] { + key: { + CONSTANT [13] { value: "key" } + } + optional_entry: true + value: { + CALL [14] { + function: optional.of + args: { + CONSTANT [15] { value: "test" } + } + } + } + } + } + CONSTANT [16] { value: "bogus" } + } + } + } + args: { + CALL [17] { + function: _[?_] + args: { + IDENT [18] { + name: @index0 + } + CONSTANT [19] { value: "bogus" } + } + } + } + } + } + args: { + CALL [20] { + function: _[_] + args: { + IDENT [21] { + name: @index0 + } + CONSTANT [22] { value: "key" } + } + } + } + } + CONSTANT [23] { value: "test" } + } + } + } +} +Test case: OPTIONAL_MESSAGE +Source: TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}.single_int32 + TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}.single_int64 == 5 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_STRUCT [3] { + name: TestAllTypes + entries: { + ENTRY [4] { + field_key: single_int64 + optional_entry: true + value: { + CALL [5] { + function: optional.ofNonZeroValue + args: { + CONSTANT [6] { value: 1 } + } + } + } + } + ENTRY [7] { + field_key: single_int32 + optional_entry: true + value: { + CALL [8] { + function: optional.of + args: { + CONSTANT [9] { value: 4 } + } + } + } + } + } + } + } + } + CALL [10] { + function: _==_ + args: { + CALL [11] { + function: _+_ + args: { + SELECT [12] { + IDENT [13] { + name: @index0 + }.single_int32 + } + SELECT [14] { + IDENT [15] { + name: @index0 + }.single_int64 + } + } + } + CONSTANT [16] { value: 5 } + } + } + } +} +Test case: CALL +Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('h' + 'e' + 'l' + 'l' + 'o') +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _+_ + args: { + CALL [4] { + function: _+_ + args: { + CALL [5] { + function: _+_ + args: { + CALL [6] { + function: _+_ + args: { + CONSTANT [7] { value: "h" } + CONSTANT [8] { value: "e" } + } + } + CONSTANT [9] { value: "l" } + } + } + CONSTANT [10] { value: "l" } + } + } + CONSTANT [11] { value: "o" } + } + } + } + } + CALL [12] { + function: matches + target: { + CALL [13] { + function: _+_ + args: { + IDENT [14] { + name: @index0 + } + CONSTANT [15] { value: " world" } + } + } + } + args: { + IDENT [16] { + name: @index0 + } + } + } + } +} +Test case: CALL_ARGUMENT_NESTED_NO_COMMON_SUBEXPR +Source: 'hello world'.matches('h' + 'e' + 'l' + 'l' + 'o') +=====> +CALL [2] { + function: matches + target: { + CONSTANT [1] { value: "hello world" } + } + args: { + CALL [10] { + function: _+_ + args: { + CALL [8] { + function: _+_ + args: { + CALL [6] { + function: _+_ + args: { + CALL [4] { + function: _+_ + args: { + CONSTANT [3] { value: "h" } + CONSTANT [5] { value: "e" } + } + } + CONSTANT [7] { value: "l" } + } + } + CONSTANT [9] { value: "l" } + } + } + CONSTANT [11] { value: "o" } + } + } + } +} +Test case: CALL_TARGET_NESTED_NO_COMMON_SUBEXPR +Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('hello') +=====> +CALL [12] { + function: matches + target: { + CALL [10] { + function: _+_ + args: { + CALL [8] { + function: _+_ + args: { + CALL [6] { + function: _+_ + args: { + CALL [4] { + function: _+_ + args: { + CALL [2] { + function: _+_ + args: { + CONSTANT [1] { value: "h" } + CONSTANT [3] { value: "e" } + } + } + CONSTANT [5] { value: "l" } + } + } + CONSTANT [7] { value: "l" } + } + } + CONSTANT [9] { value: "o" } + } + } + CONSTANT [11] { value: " world" } + } + } + } + args: { + CONSTANT [13] { value: "hello" } + } +} +Test case: CALL_BOTH_ARGUMENT_TARGET_NESTED_NO_COMMON_SUBEXPR +Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('w' + 'o' + 'r' + 'l' + 'd') +=====> +CALL [12] { + function: matches + target: { + CALL [10] { + function: _+_ + args: { + CALL [8] { + function: _+_ + args: { + CALL [6] { + function: _+_ + args: { + CALL [4] { + function: _+_ + args: { + CALL [2] { + function: _+_ + args: { + CONSTANT [1] { value: "h" } + CONSTANT [3] { value: "e" } + } + } + CONSTANT [5] { value: "l" } + } + } + CONSTANT [7] { value: "l" } + } + } + CONSTANT [9] { value: "o" } + } + } + CONSTANT [11] { value: " world" } + } + } + } + args: { + CALL [20] { + function: _+_ + args: { + CALL [18] { + function: _+_ + args: { + CALL [16] { + function: _+_ + args: { + CALL [14] { + function: _+_ + args: { + CONSTANT [13] { value: "w" } + CONSTANT [15] { value: "o" } + } + } + CONSTANT [17] { value: "r" } + } + } + CONSTANT [19] { value: "l" } + } + } + CONSTANT [21] { value: "d" } + } + } + } +} diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_1.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_1.baseline new file mode 100644 index 000000000..77f95f1a3 --- /dev/null +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_1.baseline @@ -0,0 +1,3710 @@ +Test case: SIZE_1 +Source: size([1,2]) + size([1,2]) + 1 == 5 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + } + } + CALL [6] { + function: size + args: { + IDENT [7] { + name: @index0 + } + } + } + CALL [8] { + function: _+_ + args: { + IDENT [9] { + name: @index1 + } + IDENT [10] { + name: @index1 + } + } + } + CALL [11] { + function: _+_ + args: { + IDENT [12] { + name: @index2 + } + CONSTANT [13] { value: 1 } + } + } + } + } + CALL [14] { + function: _==_ + args: { + IDENT [15] { + name: @index3 + } + CONSTANT [16] { value: 5 } + } + } + } +} +Test case: SIZE_2 +Source: 2 + size([1,2]) + size([1,2]) + 1 == 7 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + } + } + CALL [6] { + function: size + args: { + IDENT [7] { + name: @index0 + } + } + } + CALL [8] { + function: _+_ + args: { + CONSTANT [9] { value: 2 } + IDENT [10] { + name: @index1 + } + } + } + CALL [11] { + function: _+_ + args: { + IDENT [12] { + name: @index2 + } + IDENT [13] { + name: @index1 + } + } + } + CALL [14] { + function: _+_ + args: { + IDENT [15] { + name: @index3 + } + CONSTANT [16] { value: 1 } + } + } + } + } + CALL [17] { + function: _==_ + args: { + IDENT [18] { + name: @index4 + } + CONSTANT [19] { value: 7 } + } + } + } +} +Test case: SIZE_3 +Source: size([0]) + size([0]) + size([1,2]) + size([1,2]) == 6 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 0 } + } + } + CALL [5] { + function: size + args: { + IDENT [6] { + name: @index0 + } + } + } + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 1 } + CONSTANT [9] { value: 2 } + } + } + CALL [10] { + function: size + args: { + IDENT [11] { + name: @index2 + } + } + } + CALL [12] { + function: _+_ + args: { + IDENT [13] { + name: @index1 + } + IDENT [14] { + name: @index1 + } + } + } + CALL [15] { + function: _+_ + args: { + IDENT [16] { + name: @index4 + } + IDENT [17] { + name: @index3 + } + } + } + CALL [18] { + function: _+_ + args: { + IDENT [19] { + name: @index5 + } + IDENT [20] { + name: @index3 + } + } + } + } + } + CALL [21] { + function: _==_ + args: { + IDENT [22] { + name: @index6 + } + CONSTANT [23] { value: 6 } + } + } + } +} +Test case: SIZE_4 +Source: 5 + size([0]) + size([0]) + size([1,2]) + size([1,2]) + size([1,2,3]) + size([1,2,3]) == 17 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 0 } + } + } + CALL [5] { + function: size + args: { + IDENT [6] { + name: @index0 + } + } + } + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 1 } + CONSTANT [9] { value: 2 } + } + } + CALL [10] { + function: size + args: { + IDENT [11] { + name: @index2 + } + } + } + CREATE_LIST [12] { + elements: { + CONSTANT [13] { value: 1 } + CONSTANT [14] { value: 2 } + CONSTANT [15] { value: 3 } + } + } + CALL [16] { + function: size + args: { + IDENT [17] { + name: @index4 + } + } + } + CALL [18] { + function: _+_ + args: { + CONSTANT [19] { value: 5 } + IDENT [20] { + name: @index1 + } + } + } + CALL [21] { + function: _+_ + args: { + IDENT [22] { + name: @index6 + } + IDENT [23] { + name: @index1 + } + } + } + CALL [24] { + function: _+_ + args: { + IDENT [25] { + name: @index7 + } + IDENT [26] { + name: @index3 + } + } + } + CALL [27] { + function: _+_ + args: { + IDENT [28] { + name: @index8 + } + IDENT [29] { + name: @index3 + } + } + } + CALL [30] { + function: _+_ + args: { + IDENT [31] { + name: @index9 + } + IDENT [32] { + name: @index5 + } + } + } + CALL [33] { + function: _+_ + args: { + IDENT [34] { + name: @index10 + } + IDENT [35] { + name: @index5 + } + } + } + } + } + CALL [36] { + function: _==_ + args: { + IDENT [37] { + name: @index11 + } + CONSTANT [38] { value: 17 } + } + } + } +} +Test case: TIMESTAMP +Source: timestamp(int(timestamp(1000000000))).getFullYear() + timestamp(int(timestamp(75))).getFullYear() + timestamp(int(timestamp(50))).getFullYear() + timestamp(int(timestamp(1000000000))).getFullYear() + timestamp(int(timestamp(50))).getSeconds() + timestamp(int(timestamp(200))).getFullYear() + timestamp(int(timestamp(200))).getFullYear() + timestamp(int(timestamp(75))).getMinutes() + timestamp(int(timestamp(1000000000))).getFullYear() == 13934 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: timestamp + args: { + CONSTANT [4] { value: 1000000000 } + } + } + CALL [5] { + function: int + args: { + IDENT [6] { + name: @index0 + } + } + } + CALL [7] { + function: timestamp + args: { + IDENT [8] { + name: @index1 + } + } + } + CALL [9] { + function: getFullYear + target: { + IDENT [10] { + name: @index2 + } + } + args: { + } + } + CALL [11] { + function: timestamp + args: { + CONSTANT [12] { value: 50 } + } + } + CALL [13] { + function: int + args: { + IDENT [14] { + name: @index4 + } + } + } + CALL [15] { + function: timestamp + args: { + IDENT [16] { + name: @index5 + } + } + } + CALL [17] { + function: timestamp + args: { + CONSTANT [18] { value: 200 } + } + } + CALL [19] { + function: int + args: { + IDENT [20] { + name: @index7 + } + } + } + CALL [21] { + function: timestamp + args: { + IDENT [22] { + name: @index8 + } + } + } + CALL [23] { + function: getFullYear + target: { + IDENT [24] { + name: @index9 + } + } + args: { + } + } + CALL [25] { + function: timestamp + args: { + CONSTANT [26] { value: 75 } + } + } + CALL [27] { + function: int + args: { + IDENT [28] { + name: @index11 + } + } + } + CALL [29] { + function: timestamp + args: { + IDENT [30] { + name: @index12 + } + } + } + CALL [31] { + function: getMinutes + target: { + IDENT [32] { + name: @index13 + } + } + args: { + } + } + CALL [33] { + function: getSeconds + target: { + IDENT [34] { + name: @index6 + } + } + args: { + } + } + CALL [35] { + function: getFullYear + target: { + IDENT [36] { + name: @index6 + } + } + args: { + } + } + CALL [37] { + function: getFullYear + target: { + IDENT [38] { + name: @index13 + } + } + args: { + } + } + CALL [39] { + function: _+_ + args: { + IDENT [40] { + name: @index3 + } + IDENT [41] { + name: @index17 + } + } + } + CALL [42] { + function: _+_ + args: { + IDENT [43] { + name: @index18 + } + IDENT [44] { + name: @index16 + } + } + } + CALL [45] { + function: _+_ + args: { + IDENT [46] { + name: @index19 + } + IDENT [47] { + name: @index3 + } + } + } + CALL [48] { + function: _+_ + args: { + IDENT [49] { + name: @index20 + } + IDENT [50] { + name: @index15 + } + } + } + CALL [51] { + function: _+_ + args: { + IDENT [52] { + name: @index21 + } + IDENT [53] { + name: @index10 + } + } + } + CALL [54] { + function: _+_ + args: { + IDENT [55] { + name: @index22 + } + IDENT [56] { + name: @index10 + } + } + } + CALL [57] { + function: _+_ + args: { + IDENT [58] { + name: @index23 + } + IDENT [59] { + name: @index14 + } + } + } + CALL [60] { + function: _+_ + args: { + IDENT [61] { + name: @index24 + } + IDENT [62] { + name: @index3 + } + } + } + } + } + CALL [63] { + function: _==_ + args: { + IDENT [64] { + name: @index25 + } + CONSTANT [65] { value: 13934 } + } + } + } +} +Test case: MAP_INDEX +Source: {"a": 2}["a"] + {"a": 2}["a"] * {"a": 2}["a"] == 6 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: "a" } + } + value: { + CONSTANT [6] { value: 2 } + } + } + } + CALL [7] { + function: _[_] + args: { + IDENT [8] { + name: @index0 + } + CONSTANT [9] { value: "a" } + } + } + CALL [10] { + function: _*_ + args: { + IDENT [11] { + name: @index1 + } + IDENT [12] { + name: @index1 + } + } + } + CALL [13] { + function: _+_ + args: { + IDENT [14] { + name: @index1 + } + IDENT [15] { + name: @index2 + } + } + } + } + } + CALL [16] { + function: _==_ + args: { + IDENT [17] { + name: @index3 + } + CONSTANT [18] { value: 6 } + } + } + } +} +Test case: NESTED_MAP_CONSTRUCTION +Source: {'a': {'b': 1}, 'c': {'b': 1}, 'd': {'e': {'b': 1}}, 'e': {'e': {'b': 1}}} +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: "b" } + } + value: { + CONSTANT [6] { value: 1 } + } + } + } + CREATE_MAP [7] { + MAP_ENTRY [8] { + key: { + CONSTANT [9] { value: "e" } + } + value: { + IDENT [10] { + name: @index0 + } + } + } + } + } + } + CREATE_MAP [11] { + MAP_ENTRY [12] { + key: { + CONSTANT [13] { value: "a" } + } + value: { + IDENT [14] { + name: @index0 + } + } + } + MAP_ENTRY [15] { + key: { + CONSTANT [16] { value: "c" } + } + value: { + IDENT [17] { + name: @index0 + } + } + } + MAP_ENTRY [18] { + key: { + CONSTANT [19] { value: "d" } + } + value: { + IDENT [20] { + name: @index1 + } + } + } + MAP_ENTRY [21] { + key: { + CONSTANT [22] { value: "e" } + } + value: { + IDENT [23] { + name: @index1 + } + } + } + } + } +} +Test case: NESTED_LIST_CONSTRUCTION +Source: [1, [1,2,3,4], 2, [1,2,3,4], 5, [1,2,3,4], 7, [[1,2], [1,2,3,4]], [1,2]] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + CONSTANT [6] { value: 3 } + CONSTANT [7] { value: 4 } + } + } + CREATE_LIST [8] { + elements: { + CONSTANT [9] { value: 1 } + CONSTANT [10] { value: 2 } + } + } + CREATE_LIST [11] { + elements: { + IDENT [12] { + name: @index1 + } + IDENT [13] { + name: @index0 + } + } + } + } + } + CREATE_LIST [14] { + elements: { + CONSTANT [15] { value: 1 } + IDENT [16] { + name: @index0 + } + CONSTANT [17] { value: 2 } + IDENT [18] { + name: @index0 + } + CONSTANT [19] { value: 5 } + IDENT [20] { + name: @index0 + } + CONSTANT [21] { value: 7 } + IDENT [22] { + name: @index2 + } + IDENT [23] { + name: @index1 + } + } + } + } +} +Test case: SELECT +Source: msg.single_int64 + msg.single_int64 == 6 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.single_int64 + } + CALL [5] { + function: _+_ + args: { + IDENT [6] { + name: @index0 + } + IDENT [7] { + name: @index0 + } + } + } + } + } + CALL [8] { + function: _==_ + args: { + IDENT [9] { + name: @index1 + } + CONSTANT [10] { value: 6 } + } + } + } +} +Test case: SELECT_NESTED_1 +Source: msg.oneof_type.payload.single_int64 + msg.oneof_type.payload.single_int32 + msg.oneof_type.payload.single_int64 + msg.single_int64 + msg.oneof_type.payload.oneof_type.payload.single_int64 == 31 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.single_int64 + } + SELECT [9] { + IDENT [10] { + name: @index1 + }.oneof_type + } + SELECT [11] { + IDENT [12] { + name: @index3 + }.payload + } + SELECT [13] { + IDENT [14] { + name: @index4 + }.single_int64 + } + SELECT [15] { + IDENT [16] { + name: msg + }.single_int64 + } + SELECT [17] { + IDENT [18] { + name: @index1 + }.single_int32 + } + CALL [19] { + function: _+_ + args: { + IDENT [20] { + name: @index2 + } + IDENT [21] { + name: @index7 + } + } + } + CALL [22] { + function: _+_ + args: { + IDENT [23] { + name: @index8 + } + IDENT [24] { + name: @index2 + } + } + } + CALL [25] { + function: _+_ + args: { + IDENT [26] { + name: @index9 + } + IDENT [27] { + name: @index6 + } + } + } + CALL [28] { + function: _+_ + args: { + IDENT [29] { + name: @index10 + } + IDENT [30] { + name: @index5 + } + } + } + } + } + CALL [31] { + function: _==_ + args: { + IDENT [32] { + name: @index11 + } + CONSTANT [33] { value: 31 } + } + } + } +} +Test case: SELECT_NESTED_2 +Source: true || msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload.single_bool || msg.oneof_type.payload.oneof_type.payload.oneof_type.child.child.payload.single_bool +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.oneof_type + } + SELECT [9] { + IDENT [10] { + name: @index2 + }.payload + } + SELECT [11] { + IDENT [12] { + name: @index3 + }.oneof_type + } + SELECT [13] { + IDENT [14] { + name: @index4 + }.child + } + SELECT [15] { + IDENT [16] { + name: @index5 + }.child + } + SELECT [17] { + IDENT [18] { + name: @index6 + }.payload + } + SELECT [19] { + IDENT [20] { + name: @index7 + }.single_bool + } + SELECT [21] { + IDENT [22] { + name: @index4 + }.payload + } + SELECT [23] { + IDENT [24] { + name: @index9 + }.oneof_type + } + SELECT [25] { + IDENT [26] { + name: @index10 + }.payload + } + SELECT [27] { + IDENT [28] { + name: @index11 + }.single_bool + } + CALL [29] { + function: _||_ + args: { + CONSTANT [30] { value: true } + IDENT [31] { + name: @index12 + } + } + } + } + } + CALL [32] { + function: _||_ + args: { + IDENT [33] { + name: @index13 + } + IDENT [34] { + name: @index8 + } + } + } + } +} +Test case: SELECT_NESTED_MESSAGE_MAP_INDEX_1 +Source: msg.oneof_type.payload.map_int32_int64[1] + msg.oneof_type.payload.map_int32_int64[1] + msg.oneof_type.payload.map_int32_int64[1] == 15 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.map_int32_int64 + } + CALL [9] { + function: _[_] + args: { + IDENT [10] { + name: @index2 + } + CONSTANT [11] { value: 1 } + } + } + CALL [12] { + function: _+_ + args: { + IDENT [13] { + name: @index3 + } + IDENT [14] { + name: @index3 + } + } + } + CALL [15] { + function: _+_ + args: { + IDENT [16] { + name: @index4 + } + IDENT [17] { + name: @index3 + } + } + } + } + } + CALL [18] { + function: _==_ + args: { + IDENT [19] { + name: @index5 + } + CONSTANT [20] { value: 15 } + } + } + } +} +Test case: SELECT_NESTED_MESSAGE_MAP_INDEX_2 +Source: msg.oneof_type.payload.map_int32_int64[0] + msg.oneof_type.payload.map_int32_int64[1] + msg.oneof_type.payload.map_int32_int64[2] == 8 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.map_int32_int64 + } + CALL [9] { + function: _[_] + args: { + IDENT [10] { + name: @index2 + } + CONSTANT [11] { value: 2 } + } + } + CALL [12] { + function: _[_] + args: { + IDENT [13] { + name: @index2 + } + CONSTANT [14] { value: 1 } + } + } + CALL [15] { + function: _[_] + args: { + IDENT [16] { + name: @index2 + } + CONSTANT [17] { value: 0 } + } + } + CALL [18] { + function: _+_ + args: { + IDENT [19] { + name: @index5 + } + IDENT [20] { + name: @index4 + } + } + } + CALL [21] { + function: _+_ + args: { + IDENT [22] { + name: @index6 + } + IDENT [23] { + name: @index3 + } + } + } + } + } + CALL [24] { + function: _==_ + args: { + IDENT [25] { + name: @index7 + } + CONSTANT [26] { value: 8 } + } + } + } +} +Test case: SELECT_NESTED_NO_COMMON_SUBEXPR +Source: msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload.single_int64 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.oneof_type + } + SELECT [9] { + IDENT [10] { + name: @index2 + }.payload + } + SELECT [11] { + IDENT [12] { + name: @index3 + }.oneof_type + } + SELECT [13] { + IDENT [14] { + name: @index4 + }.payload + } + SELECT [15] { + IDENT [16] { + name: @index5 + }.oneof_type + } + SELECT [17] { + IDENT [18] { + name: @index6 + }.payload + } + } + } + SELECT [19] { + IDENT [20] { + name: @index7 + }.single_int64 + } + } +} +Test case: TERNARY +Source: (msg.single_int64 > 0 ? msg.single_int64 : 0) == 3 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.single_int64 + } + CALL [5] { + function: _>_ + args: { + IDENT [6] { + name: @index0 + } + CONSTANT [7] { value: 0 } + } + } + CALL [8] { + function: _?_:_ + args: { + IDENT [9] { + name: @index1 + } + IDENT [10] { + name: @index0 + } + CONSTANT [11] { value: 0 } + } + } + } + } + CALL [12] { + function: _==_ + args: { + IDENT [13] { + name: @index2 + } + CONSTANT [14] { value: 3 } + } + } + } +} +Test case: TERNARY_BIND_RHS_ONLY +Source: false ? false : (msg.single_int64) + ((msg.single_int64 + 1) * 2) == 11 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.single_int64 + } + CALL [5] { + function: _+_ + args: { + IDENT [6] { + name: @index0 + } + CONSTANT [7] { value: 1 } + } + } + CALL [8] { + function: _*_ + args: { + IDENT [9] { + name: @index1 + } + CONSTANT [10] { value: 2 } + } + } + CALL [11] { + function: _+_ + args: { + IDENT [12] { + name: @index0 + } + IDENT [13] { + name: @index2 + } + } + } + CALL [14] { + function: _==_ + args: { + IDENT [15] { + name: @index3 + } + CONSTANT [16] { value: 11 } + } + } + } + } + CALL [17] { + function: _?_:_ + args: { + CONSTANT [18] { value: false } + CONSTANT [19] { value: false } + IDENT [20] { + name: @index4 + } + } + } + } +} +Test case: NESTED_TERNARY +Source: (msg.single_int64 > 0 ? (msg.single_int32 > 0 ? msg.single_int64 + msg.single_int32 : 0) : 0) == 8 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.single_int64 + } + SELECT [5] { + IDENT [6] { + name: msg + }.single_int32 + } + CALL [7] { + function: _+_ + args: { + IDENT [8] { + name: @index0 + } + IDENT [9] { + name: @index1 + } + } + } + CALL [10] { + function: _>_ + args: { + IDENT [11] { + name: @index1 + } + CONSTANT [12] { value: 0 } + } + } + CALL [13] { + function: _?_:_ + args: { + IDENT [14] { + name: @index3 + } + IDENT [15] { + name: @index2 + } + CONSTANT [16] { value: 0 } + } + } + CALL [17] { + function: _>_ + args: { + IDENT [18] { + name: @index0 + } + CONSTANT [19] { value: 0 } + } + } + CALL [20] { + function: _?_:_ + args: { + IDENT [21] { + name: @index5 + } + IDENT [22] { + name: @index4 + } + CONSTANT [23] { value: 0 } + } + } + } + } + CALL [24] { + function: _==_ + args: { + IDENT [25] { + name: @index6 + } + CONSTANT [26] { value: 8 } + } + } + } +} +Test case: MULTIPLE_MACROS_1 +Source: size([[1].exists(i, i > 0)]) + size([[1].exists(j, j > 0)]) + size([[2].exists(k, k > 1)]) + size([[2].exists(l, l > 1)]) == 4 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + } + } + CALL [5] { + function: _>_ + args: { + IDENT [6] { + name: @c0:0 + } + CONSTANT [7] { value: 0 } + } + } + CALL [8] { + function: _||_ + args: { + IDENT [9] { + name: @x0:0 + } + IDENT [10] { + name: @index1 + } + } + } + CREATE_LIST [11] { + elements: { + CONSTANT [12] { value: 2 } + } + } + CALL [13] { + function: _>_ + args: { + IDENT [14] { + name: @c0:0 + } + CONSTANT [15] { value: 1 } + } + } + CALL [16] { + function: _||_ + args: { + IDENT [17] { + name: @x0:0 + } + IDENT [18] { + name: @index4 + } + } + } + } + } + CALL [19] { + function: _==_ + args: { + CALL [20] { + function: _+_ + args: { + CALL [21] { + function: _+_ + args: { + CALL [22] { + function: _+_ + args: { + CALL [23] { + function: size + args: { + CREATE_LIST [24] { + elements: { + COMPREHENSION [25] { + iter_var: @c0:0 + iter_range: { + IDENT [26] { + name: @index0 + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [27] { value: false } + } + loop_condition: { + CALL [28] { + function: @not_strictly_false + args: { + CALL [29] { + function: !_ + args: { + IDENT [30] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + IDENT [31] { + name: @index2 + } + } + result: { + IDENT [32] { + name: @x0:0 + } + } + } + } + } + } + } + CALL [33] { + function: size + args: { + CREATE_LIST [34] { + elements: { + COMPREHENSION [35] { + iter_var: @c0:0 + iter_range: { + IDENT [36] { + name: @index0 + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [37] { value: false } + } + loop_condition: { + CALL [38] { + function: @not_strictly_false + args: { + CALL [39] { + function: !_ + args: { + IDENT [40] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + IDENT [41] { + name: @index2 + } + } + result: { + IDENT [42] { + name: @x0:0 + } + } + } + } + } + } + } + } + } + CALL [43] { + function: size + args: { + CREATE_LIST [44] { + elements: { + COMPREHENSION [45] { + iter_var: @c0:0 + iter_range: { + IDENT [46] { + name: @index3 + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [47] { value: false } + } + loop_condition: { + CALL [48] { + function: @not_strictly_false + args: { + CALL [49] { + function: !_ + args: { + IDENT [50] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + IDENT [51] { + name: @index5 + } + } + result: { + IDENT [52] { + name: @x0:0 + } + } + } + } + } + } + } + } + } + CALL [53] { + function: size + args: { + CREATE_LIST [54] { + elements: { + COMPREHENSION [55] { + iter_var: @c0:0 + iter_range: { + IDENT [56] { + name: @index3 + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [57] { value: false } + } + loop_condition: { + CALL [58] { + function: @not_strictly_false + args: { + CALL [59] { + function: !_ + args: { + IDENT [60] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + IDENT [61] { + name: @index5 + } + } + result: { + IDENT [62] { + name: @x0:0 + } + } + } + } + } + } + } + } + } + CONSTANT [63] { value: 4 } + } + } + } +} +Test case: MULTIPLE_MACROS_2 +Source: [[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == 'a')] + [['a'].exists(l, l == 'a')] == [true, true, true, true] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + } + } + CALL [5] { + function: _>_ + args: { + IDENT [6] { + name: @c0:0 + } + CONSTANT [7] { value: 0 } + } + } + CALL [8] { + function: _||_ + args: { + IDENT [9] { + name: @x0:0 + } + IDENT [10] { + name: @index1 + } + } + } + CREATE_LIST [11] { + elements: { + CONSTANT [12] { value: "a" } + } + } + CALL [13] { + function: _==_ + args: { + IDENT [14] { + name: @c0:1 + } + CONSTANT [15] { value: "a" } + } + } + CALL [16] { + function: _||_ + args: { + IDENT [17] { + name: @x0:1 + } + IDENT [18] { + name: @index4 + } + } + } + CREATE_LIST [19] { + elements: { + CONSTANT [20] { value: true } + CONSTANT [21] { value: true } + CONSTANT [22] { value: true } + CONSTANT [23] { value: true } + } + } + } + } + CALL [24] { + function: _==_ + args: { + CALL [25] { + function: _+_ + args: { + CALL [26] { + function: _+_ + args: { + CALL [27] { + function: _+_ + args: { + CREATE_LIST [28] { + elements: { + COMPREHENSION [29] { + iter_var: @c0:0 + iter_range: { + IDENT [30] { + name: @index0 + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [31] { value: false } + } + loop_condition: { + CALL [32] { + function: @not_strictly_false + args: { + CALL [33] { + function: !_ + args: { + IDENT [34] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + IDENT [35] { + name: @index2 + } + } + result: { + IDENT [36] { + name: @x0:0 + } + } + } + } + } + CREATE_LIST [37] { + elements: { + COMPREHENSION [38] { + iter_var: @c0:0 + iter_range: { + IDENT [39] { + name: @index0 + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [40] { value: false } + } + loop_condition: { + CALL [41] { + function: @not_strictly_false + args: { + CALL [42] { + function: !_ + args: { + IDENT [43] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + IDENT [44] { + name: @index2 + } + } + result: { + IDENT [45] { + name: @x0:0 + } + } + } + } + } + } + } + CREATE_LIST [46] { + elements: { + COMPREHENSION [47] { + iter_var: @c0:1 + iter_range: { + IDENT [48] { + name: @index3 + } + } + accu_var: @x0:1 + accu_init: { + CONSTANT [49] { value: false } + } + loop_condition: { + CALL [50] { + function: @not_strictly_false + args: { + CALL [51] { + function: !_ + args: { + IDENT [52] { + name: @x0:1 + } + } + } + } + } + } + loop_step: { + IDENT [53] { + name: @index5 + } + } + result: { + IDENT [54] { + name: @x0:1 + } + } + } + } + } + } + } + CREATE_LIST [55] { + elements: { + COMPREHENSION [56] { + iter_var: @c0:1 + iter_range: { + IDENT [57] { + name: @index3 + } + } + accu_var: @x0:1 + accu_init: { + CONSTANT [58] { value: false } + } + loop_condition: { + CALL [59] { + function: @not_strictly_false + args: { + CALL [60] { + function: !_ + args: { + IDENT [61] { + name: @x0:1 + } + } + } + } + } + } + loop_step: { + IDENT [62] { + name: @index5 + } + } + result: { + IDENT [63] { + name: @x0:1 + } + } + } + } + } + } + } + IDENT [64] { + name: @index6 + } + } + } + } +} +Test case: NESTED_MACROS +Source: [1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [[2, 3, 4], [2, 3, 4], [2, 3, 4]] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + CONSTANT [6] { value: 3 } + } + } + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 2 } + CONSTANT [9] { value: 3 } + CONSTANT [10] { value: 4 } + } + } + CREATE_LIST [11] { + elements: { + IDENT [12] { + name: @index1 + } + IDENT [13] { + name: @index1 + } + IDENT [14] { + name: @index1 + } + } + } + CALL [15] { + function: _+_ + args: { + IDENT [16] { + name: @c1:0 + } + CONSTANT [17] { value: 1 } + } + } + CREATE_LIST [18] { + elements: { + IDENT [19] { + name: @index3 + } + } + } + CALL [20] { + function: _+_ + args: { + IDENT [21] { + name: @x1:0 + } + IDENT [22] { + name: @index4 + } + } + } + } + } + CALL [23] { + function: _==_ + args: { + COMPREHENSION [24] { + iter_var: @c0:0 + iter_range: { + IDENT [25] { + name: @index0 + } + } + accu_var: @x0:0 + accu_init: { + CREATE_LIST [26] { + elements: { + } + } + } + loop_condition: { + CONSTANT [27] { value: true } + } + loop_step: { + CALL [28] { + function: _+_ + args: { + IDENT [29] { + name: @x0:0 + } + CREATE_LIST [30] { + elements: { + COMPREHENSION [31] { + iter_var: @c1:0 + iter_range: { + IDENT [32] { + name: @index0 + } + } + accu_var: @x1:0 + accu_init: { + CREATE_LIST [33] { + elements: { + } + } + } + loop_condition: { + CONSTANT [34] { value: true } + } + loop_step: { + IDENT [35] { + name: @index5 + } + } + result: { + IDENT [36] { + name: @x1:0 + } + } + } + } + } + } + } + } + result: { + IDENT [37] { + name: @x0:0 + } + } + } + IDENT [38] { + name: @index2 + } + } + } + } +} +Test case: NESTED_MACROS_2 +Source: [1, 2].map(y, [1, 2, 3].filter(x, x == y)) == [[1], [2]] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 2 } + } + } + CREATE_LIST [5] { + elements: { + CONSTANT [6] { value: 1 } + } + } + CREATE_LIST [7] { + elements: { + IDENT [8] { + name: @index1 + } + IDENT [9] { + name: @index0 + } + } + } + CREATE_LIST [10] { + elements: { + IDENT [11] { + name: @c1:0 + } + } + } + CALL [12] { + function: _+_ + args: { + IDENT [13] { + name: @x1:0 + } + IDENT [14] { + name: @index3 + } + } + } + CALL [15] { + function: _==_ + args: { + IDENT [16] { + name: @c1:0 + } + IDENT [17] { + name: @c0:0 + } + } + } + CALL [18] { + function: _?_:_ + args: { + IDENT [19] { + name: @index5 + } + IDENT [20] { + name: @index4 + } + IDENT [21] { + name: @x1:0 + } + } + } + CREATE_LIST [22] { + elements: { + CONSTANT [23] { value: 1 } + CONSTANT [24] { value: 2 } + CONSTANT [25] { value: 3 } + } + } + CREATE_LIST [26] { + elements: { + CONSTANT [27] { value: 1 } + CONSTANT [28] { value: 2 } + } + } + } + } + CALL [29] { + function: _==_ + args: { + COMPREHENSION [30] { + iter_var: @c0:0 + iter_range: { + IDENT [31] { + name: @index8 + } + } + accu_var: @x0:0 + accu_init: { + CREATE_LIST [32] { + elements: { + } + } + } + loop_condition: { + CONSTANT [33] { value: true } + } + loop_step: { + CALL [34] { + function: _+_ + args: { + IDENT [35] { + name: @x0:0 + } + CREATE_LIST [36] { + elements: { + COMPREHENSION [37] { + iter_var: @c1:0 + iter_range: { + IDENT [38] { + name: @index7 + } + } + accu_var: @x1:0 + accu_init: { + CREATE_LIST [39] { + elements: { + } + } + } + loop_condition: { + CONSTANT [40] { value: true } + } + loop_step: { + IDENT [41] { + name: @index6 + } + } + result: { + IDENT [42] { + name: @x1:0 + } + } + } + } + } + } + } + } + result: { + IDENT [43] { + name: @x0:0 + } + } + } + IDENT [44] { + name: @index2 + } + } + } + } +} +Test case: INCLUSION_LIST +Source: 1 in [1,2,3] && 2 in [1,2,3] && 3 in [3, [1,2,3]] && 1 in [1,2,3] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + CONSTANT [6] { value: 3 } + } + } + CALL [7] { + function: @in + args: { + CONSTANT [8] { value: 1 } + IDENT [9] { + name: @index0 + } + } + } + CREATE_LIST [10] { + elements: { + CONSTANT [11] { value: 3 } + IDENT [12] { + name: @index0 + } + } + } + CALL [13] { + function: @in + args: { + CONSTANT [14] { value: 3 } + IDENT [15] { + name: @index2 + } + } + } + CALL [16] { + function: _&&_ + args: { + IDENT [17] { + name: @index3 + } + IDENT [18] { + name: @index1 + } + } + } + CALL [19] { + function: @in + args: { + CONSTANT [20] { value: 2 } + IDENT [21] { + name: @index0 + } + } + } + CALL [22] { + function: _&&_ + args: { + IDENT [23] { + name: @index1 + } + IDENT [24] { + name: @index5 + } + } + } + } + } + CALL [25] { + function: _&&_ + args: { + IDENT [26] { + name: @index6 + } + IDENT [27] { + name: @index4 + } + } + } + } +} +Test case: INCLUSION_MAP +Source: 2 in {'a': 1, 2: {true: false}, 3: {true: false}} +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: true } + } + value: { + CONSTANT [6] { value: false } + } + } + } + CREATE_MAP [7] { + MAP_ENTRY [8] { + key: { + CONSTANT [9] { value: "a" } + } + value: { + CONSTANT [10] { value: 1 } + } + } + MAP_ENTRY [11] { + key: { + CONSTANT [12] { value: 2 } + } + value: { + IDENT [13] { + name: @index0 + } + } + } + MAP_ENTRY [14] { + key: { + CONSTANT [15] { value: 3 } + } + value: { + IDENT [16] { + name: @index0 + } + } + } + } + } + } + CALL [17] { + function: @in + args: { + CONSTANT [18] { value: 2 } + IDENT [19] { + name: @index1 + } + } + } + } +} +Test case: MACRO_ITER_VAR_NOT_REFERENCED +Source: [1,2].map(i, [1, 2].map(i, [3,4])) == [[[3, 4], [3, 4]], [[3, 4], [3, 4]]] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + } + } + CREATE_LIST [6] { + elements: { + CONSTANT [7] { value: 3 } + CONSTANT [8] { value: 4 } + } + } + CREATE_LIST [9] { + elements: { + IDENT [10] { + name: @index1 + } + IDENT [11] { + name: @index1 + } + } + } + CREATE_LIST [12] { + elements: { + IDENT [13] { + name: @index2 + } + IDENT [14] { + name: @index2 + } + } + } + CREATE_LIST [15] { + elements: { + IDENT [16] { + name: @index1 + } + } + } + CALL [17] { + function: _+_ + args: { + IDENT [18] { + name: @x1:0 + } + IDENT [19] { + name: @index4 + } + } + } + } + } + CALL [20] { + function: _==_ + args: { + COMPREHENSION [21] { + iter_var: @c0:0 + iter_range: { + IDENT [22] { + name: @index0 + } + } + accu_var: @x0:0 + accu_init: { + CREATE_LIST [23] { + elements: { + } + } + } + loop_condition: { + CONSTANT [24] { value: true } + } + loop_step: { + CALL [25] { + function: _+_ + args: { + IDENT [26] { + name: @x0:0 + } + CREATE_LIST [27] { + elements: { + COMPREHENSION [28] { + iter_var: @c1:0 + iter_range: { + IDENT [29] { + name: @index0 + } + } + accu_var: @x1:0 + accu_init: { + CREATE_LIST [30] { + elements: { + } + } + } + loop_condition: { + CONSTANT [31] { value: true } + } + loop_step: { + IDENT [32] { + name: @index5 + } + } + result: { + IDENT [33] { + name: @x1:0 + } + } + } + } + } + } + } + } + result: { + IDENT [34] { + name: @x0:0 + } + } + } + IDENT [35] { + name: @index3 + } + } + } + } +} +Test case: MACRO_SHADOWED_VARIABLE +Source: [x - 1 > 3 ? x - 1 : 5].exists(x, x - 1 > 3) || x - 1 > 3 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _-_ + args: { + IDENT [4] { + name: x + } + CONSTANT [5] { value: 1 } + } + } + CALL [6] { + function: _>_ + args: { + IDENT [7] { + name: @index0 + } + CONSTANT [8] { value: 3 } + } + } + CALL [9] { + function: _-_ + args: { + IDENT [10] { + name: @c0:0 + } + CONSTANT [11] { value: 1 } + } + } + CALL [12] { + function: _>_ + args: { + IDENT [13] { + name: @index2 + } + CONSTANT [14] { value: 3 } + } + } + CALL [15] { + function: _||_ + args: { + IDENT [16] { + name: @x0:0 + } + IDENT [17] { + name: @index3 + } + } + } + CALL [18] { + function: _?_:_ + args: { + IDENT [19] { + name: @index1 + } + IDENT [20] { + name: @index0 + } + CONSTANT [21] { value: 5 } + } + } + CREATE_LIST [22] { + elements: { + IDENT [23] { + name: @index5 + } + } + } + } + } + CALL [24] { + function: _||_ + args: { + COMPREHENSION [25] { + iter_var: @c0:0 + iter_range: { + IDENT [26] { + name: @index6 + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [27] { value: false } + } + loop_condition: { + CALL [28] { + function: @not_strictly_false + args: { + CALL [29] { + function: !_ + args: { + IDENT [30] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + IDENT [31] { + name: @index4 + } + } + result: { + IDENT [32] { + name: @x0:0 + } + } + } + IDENT [33] { + name: @index1 + } + } + } + } +} +Test case: MACRO_SHADOWED_VARIABLE_2 +Source: ["foo", "bar"].map(x, [x + x, x + x]).map(x, [x + x, x + x]) +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _+_ + args: { + IDENT [4] { + name: @c1:0 + } + IDENT [5] { + name: @c1:0 + } + } + } + CALL [6] { + function: _+_ + args: { + IDENT [7] { + name: @c0:0 + } + IDENT [8] { + name: @c0:0 + } + } + } + CREATE_LIST [9] { + elements: { + IDENT [10] { + name: @index1 + } + IDENT [11] { + name: @index1 + } + } + } + CREATE_LIST [12] { + elements: { + IDENT [13] { + name: @index2 + } + } + } + CALL [14] { + function: _+_ + args: { + IDENT [15] { + name: @x0:0 + } + IDENT [16] { + name: @index3 + } + } + } + CREATE_LIST [17] { + elements: { + IDENT [18] { + name: @index0 + } + IDENT [19] { + name: @index0 + } + } + } + CREATE_LIST [20] { + elements: { + IDENT [21] { + name: @index5 + } + } + } + CALL [22] { + function: _+_ + args: { + IDENT [23] { + name: @x1:0 + } + IDENT [24] { + name: @index6 + } + } + } + CREATE_LIST [25] { + elements: { + CONSTANT [26] { value: "foo" } + CONSTANT [27] { value: "bar" } + } + } + } + } + COMPREHENSION [28] { + iter_var: @c0:0 + iter_range: { + COMPREHENSION [29] { + iter_var: @c1:0 + iter_range: { + IDENT [30] { + name: @index8 + } + } + accu_var: @x1:0 + accu_init: { + CREATE_LIST [31] { + elements: { + } + } + } + loop_condition: { + CONSTANT [32] { value: true } + } + loop_step: { + IDENT [33] { + name: @index7 + } + } + result: { + IDENT [34] { + name: @x1:0 + } + } + } + } + accu_var: @x0:0 + accu_init: { + CREATE_LIST [35] { + elements: { + } + } + } + loop_condition: { + CONSTANT [36] { value: true } + } + loop_step: { + IDENT [37] { + name: @index4 + } + } + result: { + IDENT [38] { + name: @x0:0 + } + } + } + } +} +Test case: PRESENCE_TEST +Source: has({'a': true}.a) && {'a':true}['a'] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: "a" } + } + value: { + CONSTANT [6] { value: true } + } + } + } + CALL [7] { + function: _[_] + args: { + IDENT [8] { + name: @index0 + } + CONSTANT [9] { value: "a" } + } + } + } + } + CALL [10] { + function: _&&_ + args: { + SELECT [11] { + IDENT [12] { + name: @index0 + }.a~presence_test + } + IDENT [13] { + name: @index1 + } + } + } + } +} +Test case: PRESENCE_TEST_WITH_TERNARY +Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : 0) == 10 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.single_int64 + } + } + } + CALL [9] { + function: _==_ + args: { + CALL [10] { + function: _?_:_ + args: { + SELECT [11] { + IDENT [12] { + name: @index0 + }.payload~presence_test + } + IDENT [13] { + name: @index2 + } + CONSTANT [14] { value: 0 } + } + } + CONSTANT [15] { value: 10 } + } + } + } +} +Test case: PRESENCE_TEST_WITH_TERNARY_2 +Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : msg.oneof_type.payload.single_int64 * 0) == 10 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.single_int64 + } + CALL [9] { + function: _*_ + args: { + IDENT [10] { + name: @index2 + } + CONSTANT [11] { value: 0 } + } + } + } + } + CALL [12] { + function: _==_ + args: { + CALL [13] { + function: _?_:_ + args: { + SELECT [14] { + IDENT [15] { + name: @index0 + }.payload~presence_test + } + IDENT [16] { + name: @index2 + } + IDENT [17] { + name: @index3 + } + } + } + CONSTANT [18] { value: 10 } + } + } + } +} +Test case: PRESENCE_TEST_WITH_TERNARY_3 +Source: (has(msg.oneof_type.payload.single_int64) ? msg.oneof_type.payload.single_int64 : msg.oneof_type.payload.single_int64 * 0) == 10 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.single_int64 + } + CALL [9] { + function: _*_ + args: { + IDENT [10] { + name: @index2 + } + CONSTANT [11] { value: 0 } + } + } + } + } + CALL [12] { + function: _==_ + args: { + CALL [13] { + function: _?_:_ + args: { + SELECT [14] { + IDENT [15] { + name: @index1 + }.single_int64~presence_test + } + IDENT [16] { + name: @index2 + } + IDENT [17] { + name: @index3 + } + } + } + CONSTANT [18] { value: 10 } + } + } + } +} +Test case: PRESENCE_TEST_WITH_TERNARY_NESTED +Source: (has(msg.oneof_type) && has(msg.oneof_type.payload) && has(msg.oneof_type.payload.single_int64)) ? ((has(msg.oneof_type.payload.map_string_string) && has(msg.oneof_type.payload.map_string_string.key)) ? msg.oneof_type.payload.map_string_string.key == 'A' : false) : false +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.map_string_string + } + SELECT [9] { + IDENT [10] { + name: @index2 + }.key + } + CALL [11] { + function: _==_ + args: { + IDENT [12] { + name: @index3 + } + CONSTANT [13] { value: "A" } + } + } + } + } + CALL [14] { + function: _?_:_ + args: { + CALL [15] { + function: _&&_ + args: { + CALL [16] { + function: _&&_ + args: { + SELECT [17] { + IDENT [18] { + name: msg + }.oneof_type~presence_test + } + SELECT [19] { + IDENT [20] { + name: @index0 + }.payload~presence_test + } + } + } + SELECT [21] { + IDENT [22] { + name: @index1 + }.single_int64~presence_test + } + } + } + CALL [23] { + function: _?_:_ + args: { + CALL [24] { + function: _&&_ + args: { + SELECT [25] { + IDENT [26] { + name: @index1 + }.map_string_string~presence_test + } + SELECT [27] { + IDENT [28] { + name: @index2 + }.key~presence_test + } + } + } + IDENT [29] { + name: @index4 + } + CONSTANT [30] { value: false } + } + } + CONSTANT [31] { value: false } + } + } + } +} +Test case: OPTIONAL_LIST +Source: [10, ?optional.none(), [?optional.none(), ?opt_x], [?optional.none(), ?opt_x]] == [10, [5], [5]] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: optional.none + args: { + } + } + CREATE_LIST [4] { + elements: { + IDENT [5] { + name: @index0 + } + IDENT [6] { + name: opt_x + } + } + optional_indices: [0, 1] + } + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 5 } + } + } + CREATE_LIST [9] { + elements: { + CONSTANT [10] { value: 10 } + IDENT [11] { + name: @index2 + } + IDENT [12] { + name: @index2 + } + } + } + CREATE_LIST [13] { + elements: { + CONSTANT [14] { value: 10 } + IDENT [15] { + name: @index0 + } + IDENT [16] { + name: @index1 + } + IDENT [17] { + name: @index1 + } + } + optional_indices: [0] + } + } + } + CALL [18] { + function: _==_ + args: { + IDENT [19] { + name: @index4 + } + IDENT [20] { + name: @index3 + } + } + } + } +} +Test case: OPTIONAL_MAP +Source: {?'hello': optional.of('hello')}['hello'] + {?'hello': optional.of('hello')}['hello'] == 'hellohello' +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: optional.of + args: { + CONSTANT [4] { value: "hello" } + } + } + CREATE_MAP [5] { + MAP_ENTRY [6] { + key: { + CONSTANT [7] { value: "hello" } + } + optional_entry: true + value: { + IDENT [8] { + name: @index0 + } + } + } + } + CALL [9] { + function: _[_] + args: { + IDENT [10] { + name: @index1 + } + CONSTANT [11] { value: "hello" } + } + } + CALL [12] { + function: _+_ + args: { + IDENT [13] { + name: @index2 + } + IDENT [14] { + name: @index2 + } + } + } + } + } + CALL [15] { + function: _==_ + args: { + IDENT [16] { + name: @index3 + } + CONSTANT [17] { value: "hellohello" } + } + } + } +} +Test case: OPTIONAL_MAP_CHAINED +Source: {?'key': optional.of('test')}[?'bogus'].or({'key': 'test'}[?'bogus']).orValue({'key': 'test'}['key']) == 'test' +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: "key" } + } + value: { + CONSTANT [6] { value: "test" } + } + } + } + CALL [7] { + function: _[_] + args: { + IDENT [8] { + name: @index0 + } + CONSTANT [9] { value: "key" } + } + } + CALL [10] { + function: _[?_] + args: { + IDENT [11] { + name: @index0 + } + CONSTANT [12] { value: "bogus" } + } + } + CALL [13] { + function: optional.of + args: { + CONSTANT [14] { value: "test" } + } + } + CREATE_MAP [15] { + MAP_ENTRY [16] { + key: { + CONSTANT [17] { value: "key" } + } + optional_entry: true + value: { + IDENT [18] { + name: @index3 + } + } + } + } + CALL [19] { + function: _[?_] + args: { + IDENT [20] { + name: @index4 + } + CONSTANT [21] { value: "bogus" } + } + } + CALL [22] { + function: or + target: { + IDENT [23] { + name: @index5 + } + } + args: { + IDENT [24] { + name: @index2 + } + } + } + CALL [25] { + function: orValue + target: { + IDENT [26] { + name: @index6 + } + } + args: { + IDENT [27] { + name: @index1 + } + } + } + } + } + CALL [28] { + function: _==_ + args: { + IDENT [29] { + name: @index7 + } + CONSTANT [30] { value: "test" } + } + } + } +} +Test case: OPTIONAL_MESSAGE +Source: TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}.single_int32 + TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}.single_int64 == 5 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: optional.ofNonZeroValue + args: { + CONSTANT [4] { value: 1 } + } + } + CALL [5] { + function: optional.of + args: { + CONSTANT [6] { value: 4 } + } + } + CREATE_STRUCT [7] { + name: TestAllTypes + entries: { + ENTRY [8] { + field_key: single_int64 + optional_entry: true + value: { + IDENT [9] { + name: @index0 + } + } + } + ENTRY [10] { + field_key: single_int32 + optional_entry: true + value: { + IDENT [11] { + name: @index1 + } + } + } + } + } + SELECT [12] { + IDENT [13] { + name: @index2 + }.single_int64 + } + SELECT [14] { + IDENT [15] { + name: @index2 + }.single_int32 + } + CALL [16] { + function: _+_ + args: { + IDENT [17] { + name: @index4 + } + IDENT [18] { + name: @index3 + } + } + } + } + } + CALL [19] { + function: _==_ + args: { + IDENT [20] { + name: @index5 + } + CONSTANT [21] { value: 5 } + } + } + } +} +Test case: CALL +Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('h' + 'e' + 'l' + 'l' + 'o') +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _+_ + args: { + CONSTANT [4] { value: "h" } + CONSTANT [5] { value: "e" } + } + } + CALL [6] { + function: _+_ + args: { + IDENT [7] { + name: @index0 + } + CONSTANT [8] { value: "l" } + } + } + CALL [9] { + function: _+_ + args: { + IDENT [10] { + name: @index1 + } + CONSTANT [11] { value: "l" } + } + } + CALL [12] { + function: _+_ + args: { + IDENT [13] { + name: @index2 + } + CONSTANT [14] { value: "o" } + } + } + CALL [15] { + function: _+_ + args: { + IDENT [16] { + name: @index3 + } + CONSTANT [17] { value: " world" } + } + } + } + } + CALL [18] { + function: matches + target: { + IDENT [19] { + name: @index4 + } + } + args: { + IDENT [20] { + name: @index3 + } + } + } + } +} +Test case: CALL_ARGUMENT_NESTED_NO_COMMON_SUBEXPR +Source: 'hello world'.matches('h' + 'e' + 'l' + 'l' + 'o') +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _+_ + args: { + CONSTANT [4] { value: "h" } + CONSTANT [5] { value: "e" } + } + } + CALL [6] { + function: _+_ + args: { + IDENT [7] { + name: @index0 + } + CONSTANT [8] { value: "l" } + } + } + CALL [9] { + function: _+_ + args: { + IDENT [10] { + name: @index1 + } + CONSTANT [11] { value: "l" } + } + } + CALL [12] { + function: _+_ + args: { + IDENT [13] { + name: @index2 + } + CONSTANT [14] { value: "o" } + } + } + } + } + CALL [15] { + function: matches + target: { + CONSTANT [16] { value: "hello world" } + } + args: { + IDENT [17] { + name: @index3 + } + } + } + } +} +Test case: CALL_TARGET_NESTED_NO_COMMON_SUBEXPR +Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('hello') +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _+_ + args: { + CONSTANT [4] { value: "h" } + CONSTANT [5] { value: "e" } + } + } + CALL [6] { + function: _+_ + args: { + IDENT [7] { + name: @index0 + } + CONSTANT [8] { value: "l" } + } + } + CALL [9] { + function: _+_ + args: { + IDENT [10] { + name: @index1 + } + CONSTANT [11] { value: "l" } + } + } + CALL [12] { + function: _+_ + args: { + IDENT [13] { + name: @index2 + } + CONSTANT [14] { value: "o" } + } + } + CALL [15] { + function: _+_ + args: { + IDENT [16] { + name: @index3 + } + CONSTANT [17] { value: " world" } + } + } + } + } + CALL [18] { + function: matches + target: { + IDENT [19] { + name: @index4 + } + } + args: { + CONSTANT [20] { value: "hello" } + } + } + } +} +Test case: CALL_BOTH_ARGUMENT_TARGET_NESTED_NO_COMMON_SUBEXPR +Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('w' + 'o' + 'r' + 'l' + 'd') +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _+_ + args: { + CONSTANT [4] { value: "w" } + CONSTANT [5] { value: "o" } + } + } + CALL [6] { + function: _+_ + args: { + IDENT [7] { + name: @index0 + } + CONSTANT [8] { value: "r" } + } + } + CALL [9] { + function: _+_ + args: { + IDENT [10] { + name: @index1 + } + CONSTANT [11] { value: "l" } + } + } + CALL [12] { + function: _+_ + args: { + IDENT [13] { + name: @index2 + } + CONSTANT [14] { value: "d" } + } + } + CALL [15] { + function: _+_ + args: { + CONSTANT [16] { value: "h" } + CONSTANT [17] { value: "e" } + } + } + CALL [18] { + function: _+_ + args: { + IDENT [19] { + name: @index4 + } + CONSTANT [20] { value: "l" } + } + } + CALL [21] { + function: _+_ + args: { + IDENT [22] { + name: @index5 + } + CONSTANT [23] { value: "l" } + } + } + CALL [24] { + function: _+_ + args: { + IDENT [25] { + name: @index6 + } + CONSTANT [26] { value: "o" } + } + } + CALL [27] { + function: _+_ + args: { + IDENT [28] { + name: @index7 + } + CONSTANT [29] { value: " world" } + } + } + } + } + CALL [30] { + function: matches + target: { + IDENT [31] { + name: @index8 + } + } + args: { + IDENT [32] { + name: @index3 + } + } + } + } +} diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_2.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_2.baseline new file mode 100644 index 000000000..5a2a4272c --- /dev/null +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_2.baseline @@ -0,0 +1,3569 @@ +Test case: SIZE_1 +Source: size([1,2]) + size([1,2]) + 1 == 5 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + } + } + CALL [6] { + function: size + args: { + IDENT [7] { + name: @index0 + } + } + } + CALL [8] { + function: _+_ + args: { + CALL [9] { + function: _+_ + args: { + IDENT [10] { + name: @index1 + } + IDENT [11] { + name: @index1 + } + } + } + CONSTANT [12] { value: 1 } + } + } + } + } + CALL [13] { + function: _==_ + args: { + IDENT [14] { + name: @index2 + } + CONSTANT [15] { value: 5 } + } + } + } +} +Test case: SIZE_2 +Source: 2 + size([1,2]) + size([1,2]) + 1 == 7 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + } + } + CALL [6] { + function: size + args: { + IDENT [7] { + name: @index0 + } + } + } + CALL [8] { + function: _+_ + args: { + CALL [9] { + function: _+_ + args: { + CONSTANT [10] { value: 2 } + IDENT [11] { + name: @index1 + } + } + } + IDENT [12] { + name: @index1 + } + } + } + CALL [13] { + function: _+_ + args: { + IDENT [14] { + name: @index2 + } + CONSTANT [15] { value: 1 } + } + } + } + } + CALL [16] { + function: _==_ + args: { + IDENT [17] { + name: @index3 + } + CONSTANT [18] { value: 7 } + } + } + } +} +Test case: SIZE_3 +Source: size([0]) + size([0]) + size([1,2]) + size([1,2]) == 6 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 0 } + } + } + CALL [5] { + function: size + args: { + IDENT [6] { + name: @index0 + } + } + } + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 1 } + CONSTANT [9] { value: 2 } + } + } + CALL [10] { + function: size + args: { + IDENT [11] { + name: @index2 + } + } + } + CALL [12] { + function: _+_ + args: { + CALL [13] { + function: _+_ + args: { + IDENT [14] { + name: @index1 + } + IDENT [15] { + name: @index1 + } + } + } + IDENT [16] { + name: @index3 + } + } + } + CALL [17] { + function: _+_ + args: { + IDENT [18] { + name: @index4 + } + IDENT [19] { + name: @index3 + } + } + } + } + } + CALL [20] { + function: _==_ + args: { + IDENT [21] { + name: @index5 + } + CONSTANT [22] { value: 6 } + } + } + } +} +Test case: SIZE_4 +Source: 5 + size([0]) + size([0]) + size([1,2]) + size([1,2]) + size([1,2,3]) + size([1,2,3]) == 17 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 0 } + } + } + CALL [5] { + function: size + args: { + IDENT [6] { + name: @index0 + } + } + } + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 1 } + CONSTANT [9] { value: 2 } + } + } + CALL [10] { + function: size + args: { + IDENT [11] { + name: @index2 + } + } + } + CREATE_LIST [12] { + elements: { + CONSTANT [13] { value: 1 } + CONSTANT [14] { value: 2 } + CONSTANT [15] { value: 3 } + } + } + CALL [16] { + function: size + args: { + IDENT [17] { + name: @index4 + } + } + } + CALL [18] { + function: _+_ + args: { + CALL [19] { + function: _+_ + args: { + CONSTANT [20] { value: 5 } + IDENT [21] { + name: @index1 + } + } + } + IDENT [22] { + name: @index1 + } + } + } + CALL [23] { + function: _+_ + args: { + CALL [24] { + function: _+_ + args: { + IDENT [25] { + name: @index6 + } + IDENT [26] { + name: @index3 + } + } + } + IDENT [27] { + name: @index3 + } + } + } + CALL [28] { + function: _+_ + args: { + CALL [29] { + function: _+_ + args: { + IDENT [30] { + name: @index7 + } + IDENT [31] { + name: @index5 + } + } + } + IDENT [32] { + name: @index5 + } + } + } + } + } + CALL [33] { + function: _==_ + args: { + IDENT [34] { + name: @index8 + } + CONSTANT [35] { value: 17 } + } + } + } +} +Test case: TIMESTAMP +Source: timestamp(int(timestamp(1000000000))).getFullYear() + timestamp(int(timestamp(75))).getFullYear() + timestamp(int(timestamp(50))).getFullYear() + timestamp(int(timestamp(1000000000))).getFullYear() + timestamp(int(timestamp(50))).getSeconds() + timestamp(int(timestamp(200))).getFullYear() + timestamp(int(timestamp(200))).getFullYear() + timestamp(int(timestamp(75))).getMinutes() + timestamp(int(timestamp(1000000000))).getFullYear() == 13934 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: timestamp + args: { + CONSTANT [4] { value: 1000000000 } + } + } + CALL [5] { + function: int + args: { + IDENT [6] { + name: @index0 + } + } + } + CALL [7] { + function: timestamp + args: { + IDENT [8] { + name: @index1 + } + } + } + CALL [9] { + function: getFullYear + target: { + IDENT [10] { + name: @index2 + } + } + args: { + } + } + CALL [11] { + function: timestamp + args: { + CONSTANT [12] { value: 50 } + } + } + CALL [13] { + function: int + args: { + IDENT [14] { + name: @index4 + } + } + } + CALL [15] { + function: timestamp + args: { + IDENT [16] { + name: @index5 + } + } + } + CALL [17] { + function: timestamp + args: { + CONSTANT [18] { value: 200 } + } + } + CALL [19] { + function: int + args: { + IDENT [20] { + name: @index7 + } + } + } + CALL [21] { + function: timestamp + args: { + IDENT [22] { + name: @index8 + } + } + } + CALL [23] { + function: getFullYear + target: { + IDENT [24] { + name: @index9 + } + } + args: { + } + } + CALL [25] { + function: timestamp + args: { + CONSTANT [26] { value: 75 } + } + } + CALL [27] { + function: int + args: { + IDENT [28] { + name: @index11 + } + } + } + CALL [29] { + function: timestamp + args: { + IDENT [30] { + name: @index12 + } + } + } + CALL [31] { + function: getMinutes + target: { + IDENT [32] { + name: @index13 + } + } + args: { + } + } + CALL [33] { + function: getSeconds + target: { + IDENT [34] { + name: @index6 + } + } + args: { + } + } + CALL [35] { + function: getFullYear + target: { + IDENT [36] { + name: @index6 + } + } + args: { + } + } + CALL [37] { + function: _+_ + args: { + IDENT [38] { + name: @index3 + } + CALL [39] { + function: getFullYear + target: { + IDENT [40] { + name: @index13 + } + } + args: { + } + } + } + } + CALL [41] { + function: _+_ + args: { + CALL [42] { + function: _+_ + args: { + IDENT [43] { + name: @index17 + } + IDENT [44] { + name: @index16 + } + } + } + IDENT [45] { + name: @index3 + } + } + } + CALL [46] { + function: _+_ + args: { + CALL [47] { + function: _+_ + args: { + IDENT [48] { + name: @index18 + } + IDENT [49] { + name: @index15 + } + } + } + IDENT [50] { + name: @index10 + } + } + } + CALL [51] { + function: _+_ + args: { + CALL [52] { + function: _+_ + args: { + IDENT [53] { + name: @index19 + } + IDENT [54] { + name: @index10 + } + } + } + IDENT [55] { + name: @index14 + } + } + } + CALL [56] { + function: _+_ + args: { + IDENT [57] { + name: @index20 + } + IDENT [58] { + name: @index3 + } + } + } + } + } + CALL [59] { + function: _==_ + args: { + IDENT [60] { + name: @index21 + } + CONSTANT [61] { value: 13934 } + } + } + } +} +Test case: MAP_INDEX +Source: {"a": 2}["a"] + {"a": 2}["a"] * {"a": 2}["a"] == 6 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: "a" } + } + value: { + CONSTANT [6] { value: 2 } + } + } + } + CALL [7] { + function: _[_] + args: { + IDENT [8] { + name: @index0 + } + CONSTANT [9] { value: "a" } + } + } + CALL [10] { + function: _+_ + args: { + IDENT [11] { + name: @index1 + } + CALL [12] { + function: _*_ + args: { + IDENT [13] { + name: @index1 + } + IDENT [14] { + name: @index1 + } + } + } + } + } + } + } + CALL [15] { + function: _==_ + args: { + IDENT [16] { + name: @index2 + } + CONSTANT [17] { value: 6 } + } + } + } +} +Test case: NESTED_MAP_CONSTRUCTION +Source: {'a': {'b': 1}, 'c': {'b': 1}, 'd': {'e': {'b': 1}}, 'e': {'e': {'b': 1}}} +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: "b" } + } + value: { + CONSTANT [6] { value: 1 } + } + } + } + CREATE_MAP [7] { + MAP_ENTRY [8] { + key: { + CONSTANT [9] { value: "e" } + } + value: { + IDENT [10] { + name: @index0 + } + } + } + } + } + } + CREATE_MAP [11] { + MAP_ENTRY [12] { + key: { + CONSTANT [13] { value: "a" } + } + value: { + IDENT [14] { + name: @index0 + } + } + } + MAP_ENTRY [15] { + key: { + CONSTANT [16] { value: "c" } + } + value: { + IDENT [17] { + name: @index0 + } + } + } + MAP_ENTRY [18] { + key: { + CONSTANT [19] { value: "d" } + } + value: { + IDENT [20] { + name: @index1 + } + } + } + MAP_ENTRY [21] { + key: { + CONSTANT [22] { value: "e" } + } + value: { + IDENT [23] { + name: @index1 + } + } + } + } + } +} +Test case: NESTED_LIST_CONSTRUCTION +Source: [1, [1,2,3,4], 2, [1,2,3,4], 5, [1,2,3,4], 7, [[1,2], [1,2,3,4]], [1,2]] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + CONSTANT [6] { value: 3 } + CONSTANT [7] { value: 4 } + } + } + CREATE_LIST [8] { + elements: { + CONSTANT [9] { value: 1 } + CONSTANT [10] { value: 2 } + } + } + CREATE_LIST [11] { + elements: { + IDENT [12] { + name: @index1 + } + IDENT [13] { + name: @index0 + } + } + } + } + } + CREATE_LIST [14] { + elements: { + CONSTANT [15] { value: 1 } + IDENT [16] { + name: @index0 + } + CONSTANT [17] { value: 2 } + IDENT [18] { + name: @index0 + } + CONSTANT [19] { value: 5 } + IDENT [20] { + name: @index0 + } + CONSTANT [21] { value: 7 } + IDENT [22] { + name: @index2 + } + IDENT [23] { + name: @index1 + } + } + } + } +} +Test case: SELECT +Source: msg.single_int64 + msg.single_int64 == 6 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.single_int64 + } + CALL [5] { + function: _+_ + args: { + IDENT [6] { + name: @index0 + } + IDENT [7] { + name: @index0 + } + } + } + } + } + CALL [8] { + function: _==_ + args: { + IDENT [9] { + name: @index1 + } + CONSTANT [10] { value: 6 } + } + } + } +} +Test case: SELECT_NESTED_1 +Source: msg.oneof_type.payload.single_int64 + msg.oneof_type.payload.single_int32 + msg.oneof_type.payload.single_int64 + msg.single_int64 + msg.oneof_type.payload.oneof_type.payload.single_int64 == 31 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.single_int64 + } + SELECT [9] { + SELECT [10] { + IDENT [11] { + name: @index1 + }.oneof_type + }.payload + } + SELECT [12] { + IDENT [13] { + name: @index3 + }.single_int64 + } + SELECT [14] { + IDENT [15] { + name: msg + }.single_int64 + } + CALL [16] { + function: _+_ + args: { + IDENT [17] { + name: @index2 + } + SELECT [18] { + IDENT [19] { + name: @index1 + }.single_int32 + } + } + } + CALL [20] { + function: _+_ + args: { + CALL [21] { + function: _+_ + args: { + IDENT [22] { + name: @index6 + } + IDENT [23] { + name: @index2 + } + } + } + IDENT [24] { + name: @index5 + } + } + } + CALL [25] { + function: _+_ + args: { + IDENT [26] { + name: @index7 + } + IDENT [27] { + name: @index4 + } + } + } + } + } + CALL [28] { + function: _==_ + args: { + IDENT [29] { + name: @index8 + } + CONSTANT [30] { value: 31 } + } + } + } +} +Test case: SELECT_NESTED_2 +Source: true || msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload.single_bool || msg.oneof_type.payload.oneof_type.payload.oneof_type.child.child.payload.single_bool +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.oneof_type + } + SELECT [9] { + IDENT [10] { + name: @index2 + }.payload + } + SELECT [11] { + IDENT [12] { + name: @index3 + }.oneof_type + } + SELECT [13] { + SELECT [14] { + IDENT [15] { + name: @index4 + }.child + }.child + } + SELECT [16] { + SELECT [17] { + IDENT [18] { + name: @index5 + }.payload + }.single_bool + } + SELECT [19] { + SELECT [20] { + IDENT [21] { + name: @index4 + }.payload + }.oneof_type + } + SELECT [22] { + SELECT [23] { + IDENT [24] { + name: @index7 + }.payload + }.single_bool + } + CALL [25] { + function: _||_ + args: { + CONSTANT [26] { value: true } + IDENT [27] { + name: @index8 + } + } + } + } + } + CALL [28] { + function: _||_ + args: { + IDENT [29] { + name: @index9 + } + IDENT [30] { + name: @index6 + } + } + } + } +} +Test case: SELECT_NESTED_MESSAGE_MAP_INDEX_1 +Source: msg.oneof_type.payload.map_int32_int64[1] + msg.oneof_type.payload.map_int32_int64[1] + msg.oneof_type.payload.map_int32_int64[1] == 15 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.map_int32_int64 + } + CALL [9] { + function: _[_] + args: { + IDENT [10] { + name: @index2 + } + CONSTANT [11] { value: 1 } + } + } + CALL [12] { + function: _+_ + args: { + CALL [13] { + function: _+_ + args: { + IDENT [14] { + name: @index3 + } + IDENT [15] { + name: @index3 + } + } + } + IDENT [16] { + name: @index3 + } + } + } + } + } + CALL [17] { + function: _==_ + args: { + IDENT [18] { + name: @index4 + } + CONSTANT [19] { value: 15 } + } + } + } +} +Test case: SELECT_NESTED_MESSAGE_MAP_INDEX_2 +Source: msg.oneof_type.payload.map_int32_int64[0] + msg.oneof_type.payload.map_int32_int64[1] + msg.oneof_type.payload.map_int32_int64[2] == 8 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.map_int32_int64 + } + CALL [9] { + function: _[_] + args: { + IDENT [10] { + name: @index2 + } + CONSTANT [11] { value: 2 } + } + } + CALL [12] { + function: _+_ + args: { + CALL [13] { + function: _[_] + args: { + IDENT [14] { + name: @index2 + } + CONSTANT [15] { value: 0 } + } + } + CALL [16] { + function: _[_] + args: { + IDENT [17] { + name: @index2 + } + CONSTANT [18] { value: 1 } + } + } + } + } + CALL [19] { + function: _+_ + args: { + IDENT [20] { + name: @index4 + } + IDENT [21] { + name: @index3 + } + } + } + } + } + CALL [22] { + function: _==_ + args: { + IDENT [23] { + name: @index5 + } + CONSTANT [24] { value: 8 } + } + } + } +} +Test case: SELECT_NESTED_NO_COMMON_SUBEXPR +Source: msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload.single_int64 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + SELECT [4] { + IDENT [5] { + name: msg + }.oneof_type + }.payload + } + SELECT [6] { + SELECT [7] { + IDENT [8] { + name: @index0 + }.oneof_type + }.payload + } + SELECT [9] { + SELECT [10] { + IDENT [11] { + name: @index1 + }.oneof_type + }.payload + } + SELECT [12] { + SELECT [13] { + IDENT [14] { + name: @index2 + }.oneof_type + }.payload + } + } + } + SELECT [15] { + IDENT [16] { + name: @index3 + }.single_int64 + } + } +} +Test case: TERNARY +Source: (msg.single_int64 > 0 ? msg.single_int64 : 0) == 3 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.single_int64 + } + CALL [5] { + function: _?_:_ + args: { + CALL [6] { + function: _>_ + args: { + IDENT [7] { + name: @index0 + } + CONSTANT [8] { value: 0 } + } + } + IDENT [9] { + name: @index0 + } + CONSTANT [10] { value: 0 } + } + } + } + } + CALL [11] { + function: _==_ + args: { + IDENT [12] { + name: @index1 + } + CONSTANT [13] { value: 3 } + } + } + } +} +Test case: TERNARY_BIND_RHS_ONLY +Source: false ? false : (msg.single_int64) + ((msg.single_int64 + 1) * 2) == 11 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.single_int64 + } + CALL [5] { + function: _*_ + args: { + CALL [6] { + function: _+_ + args: { + IDENT [7] { + name: @index0 + } + CONSTANT [8] { value: 1 } + } + } + CONSTANT [9] { value: 2 } + } + } + CALL [10] { + function: _==_ + args: { + CALL [11] { + function: _+_ + args: { + IDENT [12] { + name: @index0 + } + IDENT [13] { + name: @index1 + } + } + } + CONSTANT [14] { value: 11 } + } + } + } + } + CALL [15] { + function: _?_:_ + args: { + CONSTANT [16] { value: false } + CONSTANT [17] { value: false } + IDENT [18] { + name: @index2 + } + } + } + } +} +Test case: NESTED_TERNARY +Source: (msg.single_int64 > 0 ? (msg.single_int32 > 0 ? msg.single_int64 + msg.single_int32 : 0) : 0) == 8 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.single_int64 + } + SELECT [5] { + IDENT [6] { + name: msg + }.single_int32 + } + CALL [7] { + function: _?_:_ + args: { + CALL [8] { + function: _>_ + args: { + IDENT [9] { + name: @index1 + } + CONSTANT [10] { value: 0 } + } + } + CALL [11] { + function: _+_ + args: { + IDENT [12] { + name: @index0 + } + IDENT [13] { + name: @index1 + } + } + } + CONSTANT [14] { value: 0 } + } + } + CALL [15] { + function: _?_:_ + args: { + CALL [16] { + function: _>_ + args: { + IDENT [17] { + name: @index0 + } + CONSTANT [18] { value: 0 } + } + } + IDENT [19] { + name: @index2 + } + CONSTANT [20] { value: 0 } + } + } + } + } + CALL [21] { + function: _==_ + args: { + IDENT [22] { + name: @index3 + } + CONSTANT [23] { value: 8 } + } + } + } +} +Test case: MULTIPLE_MACROS_1 +Source: size([[1].exists(i, i > 0)]) + size([[1].exists(j, j > 0)]) + size([[2].exists(k, k > 1)]) + size([[2].exists(l, l > 1)]) == 4 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + } + } + CALL [5] { + function: _>_ + args: { + IDENT [6] { + name: @c0:0 + } + CONSTANT [7] { value: 0 } + } + } + CALL [8] { + function: _||_ + args: { + IDENT [9] { + name: @x0:0 + } + IDENT [10] { + name: @index1 + } + } + } + CREATE_LIST [11] { + elements: { + CONSTANT [12] { value: 2 } + } + } + CALL [13] { + function: _>_ + args: { + IDENT [14] { + name: @c0:0 + } + CONSTANT [15] { value: 1 } + } + } + CALL [16] { + function: _||_ + args: { + IDENT [17] { + name: @x0:0 + } + IDENT [18] { + name: @index4 + } + } + } + } + } + CALL [19] { + function: _==_ + args: { + CALL [20] { + function: _+_ + args: { + CALL [21] { + function: _+_ + args: { + CALL [22] { + function: _+_ + args: { + CALL [23] { + function: size + args: { + CREATE_LIST [24] { + elements: { + COMPREHENSION [25] { + iter_var: @c0:0 + iter_range: { + IDENT [26] { + name: @index0 + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [27] { value: false } + } + loop_condition: { + CALL [28] { + function: @not_strictly_false + args: { + CALL [29] { + function: !_ + args: { + IDENT [30] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + IDENT [31] { + name: @index2 + } + } + result: { + IDENT [32] { + name: @x0:0 + } + } + } + } + } + } + } + CALL [33] { + function: size + args: { + CREATE_LIST [34] { + elements: { + COMPREHENSION [35] { + iter_var: @c0:0 + iter_range: { + IDENT [36] { + name: @index0 + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [37] { value: false } + } + loop_condition: { + CALL [38] { + function: @not_strictly_false + args: { + CALL [39] { + function: !_ + args: { + IDENT [40] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + IDENT [41] { + name: @index2 + } + } + result: { + IDENT [42] { + name: @x0:0 + } + } + } + } + } + } + } + } + } + CALL [43] { + function: size + args: { + CREATE_LIST [44] { + elements: { + COMPREHENSION [45] { + iter_var: @c0:0 + iter_range: { + IDENT [46] { + name: @index3 + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [47] { value: false } + } + loop_condition: { + CALL [48] { + function: @not_strictly_false + args: { + CALL [49] { + function: !_ + args: { + IDENT [50] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + IDENT [51] { + name: @index5 + } + } + result: { + IDENT [52] { + name: @x0:0 + } + } + } + } + } + } + } + } + } + CALL [53] { + function: size + args: { + CREATE_LIST [54] { + elements: { + COMPREHENSION [55] { + iter_var: @c0:0 + iter_range: { + IDENT [56] { + name: @index3 + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [57] { value: false } + } + loop_condition: { + CALL [58] { + function: @not_strictly_false + args: { + CALL [59] { + function: !_ + args: { + IDENT [60] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + IDENT [61] { + name: @index5 + } + } + result: { + IDENT [62] { + name: @x0:0 + } + } + } + } + } + } + } + } + } + CONSTANT [63] { value: 4 } + } + } + } +} +Test case: MULTIPLE_MACROS_2 +Source: [[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == 'a')] + [['a'].exists(l, l == 'a')] == [true, true, true, true] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + } + } + CALL [5] { + function: _>_ + args: { + IDENT [6] { + name: @c0:0 + } + CONSTANT [7] { value: 0 } + } + } + CALL [8] { + function: _||_ + args: { + IDENT [9] { + name: @x0:0 + } + IDENT [10] { + name: @index1 + } + } + } + CREATE_LIST [11] { + elements: { + CONSTANT [12] { value: "a" } + } + } + CALL [13] { + function: _==_ + args: { + IDENT [14] { + name: @c0:1 + } + CONSTANT [15] { value: "a" } + } + } + CALL [16] { + function: _||_ + args: { + IDENT [17] { + name: @x0:1 + } + IDENT [18] { + name: @index4 + } + } + } + CREATE_LIST [19] { + elements: { + CONSTANT [20] { value: true } + CONSTANT [21] { value: true } + CONSTANT [22] { value: true } + CONSTANT [23] { value: true } + } + } + } + } + CALL [24] { + function: _==_ + args: { + CALL [25] { + function: _+_ + args: { + CALL [26] { + function: _+_ + args: { + CALL [27] { + function: _+_ + args: { + CREATE_LIST [28] { + elements: { + COMPREHENSION [29] { + iter_var: @c0:0 + iter_range: { + IDENT [30] { + name: @index0 + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [31] { value: false } + } + loop_condition: { + CALL [32] { + function: @not_strictly_false + args: { + CALL [33] { + function: !_ + args: { + IDENT [34] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + IDENT [35] { + name: @index2 + } + } + result: { + IDENT [36] { + name: @x0:0 + } + } + } + } + } + CREATE_LIST [37] { + elements: { + COMPREHENSION [38] { + iter_var: @c0:0 + iter_range: { + IDENT [39] { + name: @index0 + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [40] { value: false } + } + loop_condition: { + CALL [41] { + function: @not_strictly_false + args: { + CALL [42] { + function: !_ + args: { + IDENT [43] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + IDENT [44] { + name: @index2 + } + } + result: { + IDENT [45] { + name: @x0:0 + } + } + } + } + } + } + } + CREATE_LIST [46] { + elements: { + COMPREHENSION [47] { + iter_var: @c0:1 + iter_range: { + IDENT [48] { + name: @index3 + } + } + accu_var: @x0:1 + accu_init: { + CONSTANT [49] { value: false } + } + loop_condition: { + CALL [50] { + function: @not_strictly_false + args: { + CALL [51] { + function: !_ + args: { + IDENT [52] { + name: @x0:1 + } + } + } + } + } + } + loop_step: { + IDENT [53] { + name: @index5 + } + } + result: { + IDENT [54] { + name: @x0:1 + } + } + } + } + } + } + } + CREATE_LIST [55] { + elements: { + COMPREHENSION [56] { + iter_var: @c0:1 + iter_range: { + IDENT [57] { + name: @index3 + } + } + accu_var: @x0:1 + accu_init: { + CONSTANT [58] { value: false } + } + loop_condition: { + CALL [59] { + function: @not_strictly_false + args: { + CALL [60] { + function: !_ + args: { + IDENT [61] { + name: @x0:1 + } + } + } + } + } + } + loop_step: { + IDENT [62] { + name: @index5 + } + } + result: { + IDENT [63] { + name: @x0:1 + } + } + } + } + } + } + } + IDENT [64] { + name: @index6 + } + } + } + } +} +Test case: NESTED_MACROS +Source: [1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [[2, 3, 4], [2, 3, 4], [2, 3, 4]] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + CONSTANT [6] { value: 3 } + } + } + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 2 } + CONSTANT [9] { value: 3 } + CONSTANT [10] { value: 4 } + } + } + CREATE_LIST [11] { + elements: { + IDENT [12] { + name: @index1 + } + IDENT [13] { + name: @index1 + } + IDENT [14] { + name: @index1 + } + } + } + CREATE_LIST [15] { + elements: { + CALL [16] { + function: _+_ + args: { + IDENT [17] { + name: @c1:0 + } + CONSTANT [18] { value: 1 } + } + } + } + } + COMPREHENSION [19] { + iter_var: @c1:0 + iter_range: { + IDENT [20] { + name: @index0 + } + } + accu_var: @x1:0 + accu_init: { + CREATE_LIST [21] { + elements: { + } + } + } + loop_condition: { + CONSTANT [22] { value: true } + } + loop_step: { + CALL [23] { + function: _+_ + args: { + IDENT [24] { + name: @x1:0 + } + IDENT [25] { + name: @index3 + } + } + } + } + result: { + IDENT [26] { + name: @x1:0 + } + } + } + CALL [27] { + function: _+_ + args: { + IDENT [28] { + name: @x0:0 + } + CREATE_LIST [29] { + elements: { + IDENT [30] { + name: @index4 + } + } + } + } + } + COMPREHENSION [31] { + iter_var: @c0:0 + iter_range: { + IDENT [32] { + name: @index0 + } + } + accu_var: @x0:0 + accu_init: { + CREATE_LIST [33] { + elements: { + } + } + } + loop_condition: { + CONSTANT [34] { value: true } + } + loop_step: { + IDENT [35] { + name: @index5 + } + } + result: { + IDENT [36] { + name: @x0:0 + } + } + } + } + } + CALL [37] { + function: _==_ + args: { + IDENT [38] { + name: @index6 + } + IDENT [39] { + name: @index2 + } + } + } + } +} +Test case: NESTED_MACROS_2 +Source: [1, 2].map(y, [1, 2, 3].filter(x, x == y)) == [[1], [2]] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CREATE_LIST [4] { + elements: { + CONSTANT [5] { value: 1 } + } + } + CREATE_LIST [6] { + elements: { + CONSTANT [7] { value: 2 } + } + } + } + } + CALL [8] { + function: _+_ + args: { + IDENT [9] { + name: @x1:0 + } + CREATE_LIST [10] { + elements: { + IDENT [11] { + name: @c1:0 + } + } + } + } + } + CALL [12] { + function: _?_:_ + args: { + CALL [13] { + function: _==_ + args: { + IDENT [14] { + name: @c1:0 + } + IDENT [15] { + name: @c0:0 + } + } + } + IDENT [16] { + name: @index1 + } + IDENT [17] { + name: @x1:0 + } + } + } + COMPREHENSION [18] { + iter_var: @c1:0 + iter_range: { + CREATE_LIST [19] { + elements: { + CONSTANT [20] { value: 1 } + CONSTANT [21] { value: 2 } + CONSTANT [22] { value: 3 } + } + } + } + accu_var: @x1:0 + accu_init: { + CREATE_LIST [23] { + elements: { + } + } + } + loop_condition: { + CONSTANT [24] { value: true } + } + loop_step: { + IDENT [25] { + name: @index2 + } + } + result: { + IDENT [26] { + name: @x1:0 + } + } + } + CALL [27] { + function: _+_ + args: { + IDENT [28] { + name: @x0:0 + } + CREATE_LIST [29] { + elements: { + IDENT [30] { + name: @index3 + } + } + } + } + } + COMPREHENSION [31] { + iter_var: @c0:0 + iter_range: { + CREATE_LIST [32] { + elements: { + CONSTANT [33] { value: 1 } + CONSTANT [34] { value: 2 } + } + } + } + accu_var: @x0:0 + accu_init: { + CREATE_LIST [35] { + elements: { + } + } + } + loop_condition: { + CONSTANT [36] { value: true } + } + loop_step: { + IDENT [37] { + name: @index4 + } + } + result: { + IDENT [38] { + name: @x0:0 + } + } + } + } + } + CALL [39] { + function: _==_ + args: { + IDENT [40] { + name: @index5 + } + IDENT [41] { + name: @index0 + } + } + } + } +} +Test case: INCLUSION_LIST +Source: 1 in [1,2,3] && 2 in [1,2,3] && 3 in [3, [1,2,3]] && 1 in [1,2,3] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + CONSTANT [6] { value: 3 } + } + } + CALL [7] { + function: @in + args: { + CONSTANT [8] { value: 1 } + IDENT [9] { + name: @index0 + } + } + } + CALL [10] { + function: @in + args: { + CONSTANT [11] { value: 3 } + CREATE_LIST [12] { + elements: { + CONSTANT [13] { value: 3 } + IDENT [14] { + name: @index0 + } + } + } + } + } + CALL [15] { + function: _&&_ + args: { + IDENT [16] { + name: @index2 + } + IDENT [17] { + name: @index1 + } + } + } + CALL [18] { + function: _&&_ + args: { + IDENT [19] { + name: @index1 + } + CALL [20] { + function: @in + args: { + CONSTANT [21] { value: 2 } + IDENT [22] { + name: @index0 + } + } + } + } + } + } + } + CALL [23] { + function: _&&_ + args: { + IDENT [24] { + name: @index4 + } + IDENT [25] { + name: @index3 + } + } + } + } +} +Test case: INCLUSION_MAP +Source: 2 in {'a': 1, 2: {true: false}, 3: {true: false}} +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: true } + } + value: { + CONSTANT [6] { value: false } + } + } + } + CREATE_MAP [7] { + MAP_ENTRY [8] { + key: { + CONSTANT [9] { value: "a" } + } + value: { + CONSTANT [10] { value: 1 } + } + } + MAP_ENTRY [11] { + key: { + CONSTANT [12] { value: 2 } + } + value: { + IDENT [13] { + name: @index0 + } + } + } + MAP_ENTRY [14] { + key: { + CONSTANT [15] { value: 3 } + } + value: { + IDENT [16] { + name: @index0 + } + } + } + } + } + } + CALL [17] { + function: @in + args: { + CONSTANT [18] { value: 2 } + IDENT [19] { + name: @index1 + } + } + } + } +} +Test case: MACRO_ITER_VAR_NOT_REFERENCED +Source: [1,2].map(i, [1, 2].map(i, [3,4])) == [[[3, 4], [3, 4]], [[3, 4], [3, 4]]] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + } + } + CREATE_LIST [6] { + elements: { + CONSTANT [7] { value: 3 } + CONSTANT [8] { value: 4 } + } + } + CREATE_LIST [9] { + elements: { + IDENT [10] { + name: @index1 + } + IDENT [11] { + name: @index1 + } + } + } + CREATE_LIST [12] { + elements: { + IDENT [13] { + name: @index2 + } + IDENT [14] { + name: @index2 + } + } + } + CALL [15] { + function: _+_ + args: { + IDENT [16] { + name: @x1:0 + } + CREATE_LIST [17] { + elements: { + IDENT [18] { + name: @index1 + } + } + } + } + } + COMPREHENSION [19] { + iter_var: @c1:0 + iter_range: { + IDENT [20] { + name: @index0 + } + } + accu_var: @x1:0 + accu_init: { + CREATE_LIST [21] { + elements: { + } + } + } + loop_condition: { + CONSTANT [22] { value: true } + } + loop_step: { + IDENT [23] { + name: @index4 + } + } + result: { + IDENT [24] { + name: @x1:0 + } + } + } + CALL [25] { + function: _+_ + args: { + IDENT [26] { + name: @x0:0 + } + CREATE_LIST [27] { + elements: { + IDENT [28] { + name: @index5 + } + } + } + } + } + COMPREHENSION [29] { + iter_var: @c0:0 + iter_range: { + IDENT [30] { + name: @index0 + } + } + accu_var: @x0:0 + accu_init: { + CREATE_LIST [31] { + elements: { + } + } + } + loop_condition: { + CONSTANT [32] { value: true } + } + loop_step: { + IDENT [33] { + name: @index6 + } + } + result: { + IDENT [34] { + name: @x0:0 + } + } + } + } + } + CALL [35] { + function: _==_ + args: { + IDENT [36] { + name: @index7 + } + IDENT [37] { + name: @index3 + } + } + } + } +} +Test case: MACRO_SHADOWED_VARIABLE +Source: [x - 1 > 3 ? x - 1 : 5].exists(x, x - 1 > 3) || x - 1 > 3 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _-_ + args: { + IDENT [4] { + name: x + } + CONSTANT [5] { value: 1 } + } + } + CALL [6] { + function: _>_ + args: { + IDENT [7] { + name: @index0 + } + CONSTANT [8] { value: 3 } + } + } + CALL [9] { + function: _>_ + args: { + CALL [10] { + function: _-_ + args: { + IDENT [11] { + name: @c0:0 + } + CONSTANT [12] { value: 1 } + } + } + CONSTANT [13] { value: 3 } + } + } + CALL [14] { + function: _||_ + args: { + IDENT [15] { + name: @x0:0 + } + IDENT [16] { + name: @index2 + } + } + } + CREATE_LIST [17] { + elements: { + CALL [18] { + function: _?_:_ + args: { + IDENT [19] { + name: @index1 + } + IDENT [20] { + name: @index0 + } + CONSTANT [21] { value: 5 } + } + } + } + } + } + } + CALL [22] { + function: _||_ + args: { + COMPREHENSION [23] { + iter_var: @c0:0 + iter_range: { + IDENT [24] { + name: @index4 + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [25] { value: false } + } + loop_condition: { + CALL [26] { + function: @not_strictly_false + args: { + CALL [27] { + function: !_ + args: { + IDENT [28] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + IDENT [29] { + name: @index3 + } + } + result: { + IDENT [30] { + name: @x0:0 + } + } + } + IDENT [31] { + name: @index1 + } + } + } + } +} +Test case: MACRO_SHADOWED_VARIABLE_2 +Source: ["foo", "bar"].map(x, [x + x, x + x]).map(x, [x + x, x + x]) +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _+_ + args: { + IDENT [4] { + name: @c1:0 + } + IDENT [5] { + name: @c1:0 + } + } + } + CALL [6] { + function: _+_ + args: { + IDENT [7] { + name: @c0:0 + } + IDENT [8] { + name: @c0:0 + } + } + } + CREATE_LIST [9] { + elements: { + CREATE_LIST [10] { + elements: { + IDENT [11] { + name: @index1 + } + IDENT [12] { + name: @index1 + } + } + } + } + } + CALL [13] { + function: _+_ + args: { + IDENT [14] { + name: @x0:0 + } + IDENT [15] { + name: @index2 + } + } + } + CREATE_LIST [16] { + elements: { + CREATE_LIST [17] { + elements: { + IDENT [18] { + name: @index0 + } + IDENT [19] { + name: @index0 + } + } + } + } + } + COMPREHENSION [20] { + iter_var: @c1:0 + iter_range: { + CREATE_LIST [21] { + elements: { + CONSTANT [22] { value: "foo" } + CONSTANT [23] { value: "bar" } + } + } + } + accu_var: @x1:0 + accu_init: { + CREATE_LIST [24] { + elements: { + } + } + } + loop_condition: { + CONSTANT [25] { value: true } + } + loop_step: { + CALL [26] { + function: _+_ + args: { + IDENT [27] { + name: @x1:0 + } + IDENT [28] { + name: @index4 + } + } + } + } + result: { + IDENT [29] { + name: @x1:0 + } + } + } + } + } + COMPREHENSION [30] { + iter_var: @c0:0 + iter_range: { + IDENT [31] { + name: @index5 + } + } + accu_var: @x0:0 + accu_init: { + CREATE_LIST [32] { + elements: { + } + } + } + loop_condition: { + CONSTANT [33] { value: true } + } + loop_step: { + IDENT [34] { + name: @index3 + } + } + result: { + IDENT [35] { + name: @x0:0 + } + } + } + } +} +Test case: PRESENCE_TEST +Source: has({'a': true}.a) && {'a':true}['a'] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: "a" } + } + value: { + CONSTANT [6] { value: true } + } + } + } + CALL [7] { + function: _[_] + args: { + IDENT [8] { + name: @index0 + } + CONSTANT [9] { value: "a" } + } + } + } + } + CALL [10] { + function: _&&_ + args: { + SELECT [11] { + IDENT [12] { + name: @index0 + }.a~presence_test + } + IDENT [13] { + name: @index1 + } + } + } + } +} +Test case: PRESENCE_TEST_WITH_TERNARY +Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : 0) == 10 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + SELECT [6] { + IDENT [7] { + name: @index0 + }.payload + }.single_int64 + } + CALL [8] { + function: _?_:_ + args: { + SELECT [9] { + IDENT [10] { + name: @index0 + }.payload~presence_test + } + IDENT [11] { + name: @index1 + } + CONSTANT [12] { value: 0 } + } + } + } + } + CALL [13] { + function: _==_ + args: { + IDENT [14] { + name: @index2 + } + CONSTANT [15] { value: 10 } + } + } + } +} +Test case: PRESENCE_TEST_WITH_TERNARY_2 +Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : msg.oneof_type.payload.single_int64 * 0) == 10 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.single_int64 + } + CALL [9] { + function: _?_:_ + args: { + SELECT [10] { + IDENT [11] { + name: @index0 + }.payload~presence_test + } + IDENT [12] { + name: @index2 + } + CALL [13] { + function: _*_ + args: { + IDENT [14] { + name: @index2 + } + CONSTANT [15] { value: 0 } + } + } + } + } + } + } + CALL [16] { + function: _==_ + args: { + IDENT [17] { + name: @index3 + } + CONSTANT [18] { value: 10 } + } + } + } +} +Test case: PRESENCE_TEST_WITH_TERNARY_3 +Source: (has(msg.oneof_type.payload.single_int64) ? msg.oneof_type.payload.single_int64 : msg.oneof_type.payload.single_int64 * 0) == 10 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.single_int64 + } + CALL [9] { + function: _?_:_ + args: { + SELECT [10] { + IDENT [11] { + name: @index1 + }.single_int64~presence_test + } + IDENT [12] { + name: @index2 + } + CALL [13] { + function: _*_ + args: { + IDENT [14] { + name: @index2 + } + CONSTANT [15] { value: 0 } + } + } + } + } + } + } + CALL [16] { + function: _==_ + args: { + IDENT [17] { + name: @index3 + } + CONSTANT [18] { value: 10 } + } + } + } +} +Test case: PRESENCE_TEST_WITH_TERNARY_NESTED +Source: (has(msg.oneof_type) && has(msg.oneof_type.payload) && has(msg.oneof_type.payload.single_int64)) ? ((has(msg.oneof_type.payload.map_string_string) && has(msg.oneof_type.payload.map_string_string.key)) ? msg.oneof_type.payload.map_string_string.key == 'A' : false) : false +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.map_string_string + } + CALL [9] { + function: _==_ + args: { + SELECT [10] { + IDENT [11] { + name: @index2 + }.key + } + CONSTANT [12] { value: "A" } + } + } + CALL [13] { + function: _&&_ + args: { + SELECT [14] { + IDENT [15] { + name: @index1 + }.map_string_string~presence_test + } + SELECT [16] { + IDENT [17] { + name: @index2 + }.key~presence_test + } + } + } + CALL [18] { + function: _?_:_ + args: { + IDENT [19] { + name: @index4 + } + IDENT [20] { + name: @index3 + } + CONSTANT [21] { value: false } + } + } + CALL [22] { + function: _&&_ + args: { + SELECT [23] { + IDENT [24] { + name: msg + }.oneof_type~presence_test + } + SELECT [25] { + IDENT [26] { + name: @index0 + }.payload~presence_test + } + } + } + CALL [27] { + function: _&&_ + args: { + IDENT [28] { + name: @index6 + } + SELECT [29] { + IDENT [30] { + name: @index1 + }.single_int64~presence_test + } + } + } + } + } + CALL [31] { + function: _?_:_ + args: { + IDENT [32] { + name: @index7 + } + IDENT [33] { + name: @index5 + } + CONSTANT [34] { value: false } + } + } + } +} +Test case: OPTIONAL_LIST +Source: [10, ?optional.none(), [?optional.none(), ?opt_x], [?optional.none(), ?opt_x]] == [10, [5], [5]] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: optional.none + args: { + } + } + CREATE_LIST [4] { + elements: { + IDENT [5] { + name: @index0 + } + IDENT [6] { + name: opt_x + } + } + optional_indices: [0, 1] + } + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 5 } + } + } + CREATE_LIST [9] { + elements: { + CONSTANT [10] { value: 10 } + IDENT [11] { + name: @index2 + } + IDENT [12] { + name: @index2 + } + } + } + CREATE_LIST [13] { + elements: { + CONSTANT [14] { value: 10 } + IDENT [15] { + name: @index0 + } + IDENT [16] { + name: @index1 + } + IDENT [17] { + name: @index1 + } + } + optional_indices: [0] + } + } + } + CALL [18] { + function: _==_ + args: { + IDENT [19] { + name: @index4 + } + IDENT [20] { + name: @index3 + } + } + } + } +} +Test case: OPTIONAL_MAP +Source: {?'hello': optional.of('hello')}['hello'] + {?'hello': optional.of('hello')}['hello'] == 'hellohello' +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: optional.of + args: { + CONSTANT [4] { value: "hello" } + } + } + CREATE_MAP [5] { + MAP_ENTRY [6] { + key: { + CONSTANT [7] { value: "hello" } + } + optional_entry: true + value: { + IDENT [8] { + name: @index0 + } + } + } + } + CALL [9] { + function: _[_] + args: { + IDENT [10] { + name: @index1 + } + CONSTANT [11] { value: "hello" } + } + } + CALL [12] { + function: _+_ + args: { + IDENT [13] { + name: @index2 + } + IDENT [14] { + name: @index2 + } + } + } + } + } + CALL [15] { + function: _==_ + args: { + IDENT [16] { + name: @index3 + } + CONSTANT [17] { value: "hellohello" } + } + } + } +} +Test case: OPTIONAL_MAP_CHAINED +Source: {?'key': optional.of('test')}[?'bogus'].or({'key': 'test'}[?'bogus']).orValue({'key': 'test'}['key']) == 'test' +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: "key" } + } + value: { + CONSTANT [6] { value: "test" } + } + } + } + CALL [7] { + function: _[_] + args: { + IDENT [8] { + name: @index0 + } + CONSTANT [9] { value: "key" } + } + } + CALL [10] { + function: _[?_] + args: { + IDENT [11] { + name: @index0 + } + CONSTANT [12] { value: "bogus" } + } + } + CREATE_MAP [13] { + MAP_ENTRY [14] { + key: { + CONSTANT [15] { value: "key" } + } + optional_entry: true + value: { + CALL [16] { + function: optional.of + args: { + CONSTANT [17] { value: "test" } + } + } + } + } + } + CALL [18] { + function: or + target: { + CALL [19] { + function: _[?_] + args: { + IDENT [20] { + name: @index3 + } + CONSTANT [21] { value: "bogus" } + } + } + } + args: { + IDENT [22] { + name: @index2 + } + } + } + CALL [23] { + function: orValue + target: { + IDENT [24] { + name: @index4 + } + } + args: { + IDENT [25] { + name: @index1 + } + } + } + } + } + CALL [26] { + function: _==_ + args: { + IDENT [27] { + name: @index5 + } + CONSTANT [28] { value: "test" } + } + } + } +} +Test case: OPTIONAL_MESSAGE +Source: TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}.single_int32 + TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}.single_int64 == 5 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: optional.ofNonZeroValue + args: { + CONSTANT [4] { value: 1 } + } + } + CALL [5] { + function: optional.of + args: { + CONSTANT [6] { value: 4 } + } + } + CREATE_STRUCT [7] { + name: TestAllTypes + entries: { + ENTRY [8] { + field_key: single_int64 + optional_entry: true + value: { + IDENT [9] { + name: @index0 + } + } + } + ENTRY [10] { + field_key: single_int32 + optional_entry: true + value: { + IDENT [11] { + name: @index1 + } + } + } + } + } + CALL [12] { + function: _+_ + args: { + SELECT [13] { + IDENT [14] { + name: @index2 + }.single_int32 + } + SELECT [15] { + IDENT [16] { + name: @index2 + }.single_int64 + } + } + } + } + } + CALL [17] { + function: _==_ + args: { + IDENT [18] { + name: @index3 + } + CONSTANT [19] { value: 5 } + } + } + } +} +Test case: CALL +Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('h' + 'e' + 'l' + 'l' + 'o') +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _+_ + args: { + CONSTANT [4] { value: "h" } + CONSTANT [5] { value: "e" } + } + } + CALL [6] { + function: _+_ + args: { + IDENT [7] { + name: @index0 + } + CONSTANT [8] { value: "l" } + } + } + CALL [9] { + function: _+_ + args: { + IDENT [10] { + name: @index1 + } + CONSTANT [11] { value: "l" } + } + } + CALL [12] { + function: _+_ + args: { + IDENT [13] { + name: @index2 + } + CONSTANT [14] { value: "o" } + } + } + CALL [15] { + function: _+_ + args: { + IDENT [16] { + name: @index3 + } + CONSTANT [17] { value: " world" } + } + } + } + } + CALL [18] { + function: matches + target: { + IDENT [19] { + name: @index4 + } + } + args: { + IDENT [20] { + name: @index3 + } + } + } + } +} +Test case: CALL_ARGUMENT_NESTED_NO_COMMON_SUBEXPR +Source: 'hello world'.matches('h' + 'e' + 'l' + 'l' + 'o') +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _+_ + args: { + CALL [4] { + function: _+_ + args: { + CONSTANT [5] { value: "h" } + CONSTANT [6] { value: "e" } + } + } + CONSTANT [7] { value: "l" } + } + } + CALL [8] { + function: _+_ + args: { + CALL [9] { + function: _+_ + args: { + IDENT [10] { + name: @index0 + } + CONSTANT [11] { value: "l" } + } + } + CONSTANT [12] { value: "o" } + } + } + } + } + CALL [13] { + function: matches + target: { + CONSTANT [14] { value: "hello world" } + } + args: { + IDENT [15] { + name: @index1 + } + } + } + } +} +Test case: CALL_TARGET_NESTED_NO_COMMON_SUBEXPR +Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('hello') +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _+_ + args: { + CALL [4] { + function: _+_ + args: { + CONSTANT [5] { value: "h" } + CONSTANT [6] { value: "e" } + } + } + CONSTANT [7] { value: "l" } + } + } + CALL [8] { + function: _+_ + args: { + CALL [9] { + function: _+_ + args: { + IDENT [10] { + name: @index0 + } + CONSTANT [11] { value: "l" } + } + } + CONSTANT [12] { value: "o" } + } + } + CALL [13] { + function: _+_ + args: { + IDENT [14] { + name: @index1 + } + CONSTANT [15] { value: " world" } + } + } + } + } + CALL [16] { + function: matches + target: { + IDENT [17] { + name: @index2 + } + } + args: { + CONSTANT [18] { value: "hello" } + } + } + } +} +Test case: CALL_BOTH_ARGUMENT_TARGET_NESTED_NO_COMMON_SUBEXPR +Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('w' + 'o' + 'r' + 'l' + 'd') +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _+_ + args: { + CALL [4] { + function: _+_ + args: { + CONSTANT [5] { value: "w" } + CONSTANT [6] { value: "o" } + } + } + CONSTANT [7] { value: "r" } + } + } + CALL [8] { + function: _+_ + args: { + CALL [9] { + function: _+_ + args: { + IDENT [10] { + name: @index0 + } + CONSTANT [11] { value: "l" } + } + } + CONSTANT [12] { value: "d" } + } + } + CALL [13] { + function: _+_ + args: { + CALL [14] { + function: _+_ + args: { + CONSTANT [15] { value: "h" } + CONSTANT [16] { value: "e" } + } + } + CONSTANT [17] { value: "l" } + } + } + CALL [18] { + function: _+_ + args: { + CALL [19] { + function: _+_ + args: { + IDENT [20] { + name: @index2 + } + CONSTANT [21] { value: "l" } + } + } + CONSTANT [22] { value: "o" } + } + } + CALL [23] { + function: _+_ + args: { + IDENT [24] { + name: @index3 + } + CONSTANT [25] { value: " world" } + } + } + } + } + CALL [26] { + function: matches + target: { + IDENT [27] { + name: @index4 + } + } + args: { + IDENT [28] { + name: @index1 + } + } + } + } +} diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_3.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_3.baseline new file mode 100644 index 000000000..bf930a9e5 --- /dev/null +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_3.baseline @@ -0,0 +1,3359 @@ +Test case: SIZE_1 +Source: size([1,2]) + size([1,2]) + 1 == 5 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + } + } + CALL [6] { + function: size + args: { + IDENT [7] { + name: @index0 + } + } + } + CALL [8] { + function: _+_ + args: { + CALL [9] { + function: _+_ + args: { + IDENT [10] { + name: @index1 + } + IDENT [11] { + name: @index1 + } + } + } + CONSTANT [12] { value: 1 } + } + } + } + } + CALL [13] { + function: _==_ + args: { + IDENT [14] { + name: @index2 + } + CONSTANT [15] { value: 5 } + } + } + } +} +Test case: SIZE_2 +Source: 2 + size([1,2]) + size([1,2]) + 1 == 7 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + } + } + CALL [6] { + function: size + args: { + IDENT [7] { + name: @index0 + } + } + } + CALL [8] { + function: _+_ + args: { + CALL [9] { + function: _+_ + args: { + CALL [10] { + function: _+_ + args: { + CONSTANT [11] { value: 2 } + IDENT [12] { + name: @index1 + } + } + } + IDENT [13] { + name: @index1 + } + } + } + CONSTANT [14] { value: 1 } + } + } + } + } + CALL [15] { + function: _==_ + args: { + IDENT [16] { + name: @index2 + } + CONSTANT [17] { value: 7 } + } + } + } +} +Test case: SIZE_3 +Source: size([0]) + size([0]) + size([1,2]) + size([1,2]) == 6 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 0 } + } + } + CALL [5] { + function: size + args: { + IDENT [6] { + name: @index0 + } + } + } + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 1 } + CONSTANT [9] { value: 2 } + } + } + CALL [10] { + function: size + args: { + IDENT [11] { + name: @index2 + } + } + } + CALL [12] { + function: _+_ + args: { + CALL [13] { + function: _+_ + args: { + CALL [14] { + function: _+_ + args: { + IDENT [15] { + name: @index1 + } + IDENT [16] { + name: @index1 + } + } + } + IDENT [17] { + name: @index3 + } + } + } + IDENT [18] { + name: @index3 + } + } + } + } + } + CALL [19] { + function: _==_ + args: { + IDENT [20] { + name: @index4 + } + CONSTANT [21] { value: 6 } + } + } + } +} +Test case: SIZE_4 +Source: 5 + size([0]) + size([0]) + size([1,2]) + size([1,2]) + size([1,2,3]) + size([1,2,3]) == 17 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 0 } + } + } + CALL [5] { + function: size + args: { + IDENT [6] { + name: @index0 + } + } + } + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 1 } + CONSTANT [9] { value: 2 } + } + } + CALL [10] { + function: size + args: { + IDENT [11] { + name: @index2 + } + } + } + CREATE_LIST [12] { + elements: { + CONSTANT [13] { value: 1 } + CONSTANT [14] { value: 2 } + CONSTANT [15] { value: 3 } + } + } + CALL [16] { + function: size + args: { + IDENT [17] { + name: @index4 + } + } + } + CALL [18] { + function: _+_ + args: { + CALL [19] { + function: _+_ + args: { + CALL [20] { + function: _+_ + args: { + CONSTANT [21] { value: 5 } + IDENT [22] { + name: @index1 + } + } + } + IDENT [23] { + name: @index1 + } + } + } + IDENT [24] { + name: @index3 + } + } + } + CALL [25] { + function: _+_ + args: { + CALL [26] { + function: _+_ + args: { + CALL [27] { + function: _+_ + args: { + IDENT [28] { + name: @index6 + } + IDENT [29] { + name: @index3 + } + } + } + IDENT [30] { + name: @index5 + } + } + } + IDENT [31] { + name: @index5 + } + } + } + } + } + CALL [32] { + function: _==_ + args: { + IDENT [33] { + name: @index7 + } + CONSTANT [34] { value: 17 } + } + } + } +} +Test case: TIMESTAMP +Source: timestamp(int(timestamp(1000000000))).getFullYear() + timestamp(int(timestamp(75))).getFullYear() + timestamp(int(timestamp(50))).getFullYear() + timestamp(int(timestamp(1000000000))).getFullYear() + timestamp(int(timestamp(50))).getSeconds() + timestamp(int(timestamp(200))).getFullYear() + timestamp(int(timestamp(200))).getFullYear() + timestamp(int(timestamp(75))).getMinutes() + timestamp(int(timestamp(1000000000))).getFullYear() == 13934 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: timestamp + args: { + CONSTANT [4] { value: 1000000000 } + } + } + CALL [5] { + function: int + args: { + IDENT [6] { + name: @index0 + } + } + } + CALL [7] { + function: timestamp + args: { + IDENT [8] { + name: @index1 + } + } + } + CALL [9] { + function: getFullYear + target: { + IDENT [10] { + name: @index2 + } + } + args: { + } + } + CALL [11] { + function: timestamp + args: { + CONSTANT [12] { value: 50 } + } + } + CALL [13] { + function: int + args: { + IDENT [14] { + name: @index4 + } + } + } + CALL [15] { + function: timestamp + args: { + IDENT [16] { + name: @index5 + } + } + } + CALL [17] { + function: timestamp + args: { + CONSTANT [18] { value: 200 } + } + } + CALL [19] { + function: int + args: { + IDENT [20] { + name: @index7 + } + } + } + CALL [21] { + function: timestamp + args: { + IDENT [22] { + name: @index8 + } + } + } + CALL [23] { + function: getFullYear + target: { + IDENT [24] { + name: @index9 + } + } + args: { + } + } + CALL [25] { + function: timestamp + args: { + CONSTANT [26] { value: 75 } + } + } + CALL [27] { + function: int + args: { + IDENT [28] { + name: @index11 + } + } + } + CALL [29] { + function: timestamp + args: { + IDENT [30] { + name: @index12 + } + } + } + CALL [31] { + function: getMinutes + target: { + IDENT [32] { + name: @index13 + } + } + args: { + } + } + CALL [33] { + function: getSeconds + target: { + IDENT [34] { + name: @index6 + } + } + args: { + } + } + CALL [35] { + function: _+_ + args: { + CALL [36] { + function: _+_ + args: { + IDENT [37] { + name: @index3 + } + CALL [38] { + function: getFullYear + target: { + IDENT [39] { + name: @index13 + } + } + args: { + } + } + } + } + CALL [40] { + function: getFullYear + target: { + IDENT [41] { + name: @index6 + } + } + args: { + } + } + } + } + CALL [42] { + function: _+_ + args: { + CALL [43] { + function: _+_ + args: { + CALL [44] { + function: _+_ + args: { + IDENT [45] { + name: @index16 + } + IDENT [46] { + name: @index3 + } + } + } + IDENT [47] { + name: @index15 + } + } + } + IDENT [48] { + name: @index10 + } + } + } + CALL [49] { + function: _+_ + args: { + CALL [50] { + function: _+_ + args: { + CALL [51] { + function: _+_ + args: { + IDENT [52] { + name: @index17 + } + IDENT [53] { + name: @index10 + } + } + } + IDENT [54] { + name: @index14 + } + } + } + IDENT [55] { + name: @index3 + } + } + } + } + } + CALL [56] { + function: _==_ + args: { + IDENT [57] { + name: @index18 + } + CONSTANT [58] { value: 13934 } + } + } + } +} +Test case: MAP_INDEX +Source: {"a": 2}["a"] + {"a": 2}["a"] * {"a": 2}["a"] == 6 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: "a" } + } + value: { + CONSTANT [6] { value: 2 } + } + } + } + CALL [7] { + function: _[_] + args: { + IDENT [8] { + name: @index0 + } + CONSTANT [9] { value: "a" } + } + } + CALL [10] { + function: _+_ + args: { + IDENT [11] { + name: @index1 + } + CALL [12] { + function: _*_ + args: { + IDENT [13] { + name: @index1 + } + IDENT [14] { + name: @index1 + } + } + } + } + } + } + } + CALL [15] { + function: _==_ + args: { + IDENT [16] { + name: @index2 + } + CONSTANT [17] { value: 6 } + } + } + } +} +Test case: NESTED_MAP_CONSTRUCTION +Source: {'a': {'b': 1}, 'c': {'b': 1}, 'd': {'e': {'b': 1}}, 'e': {'e': {'b': 1}}} +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: "b" } + } + value: { + CONSTANT [6] { value: 1 } + } + } + } + CREATE_MAP [7] { + MAP_ENTRY [8] { + key: { + CONSTANT [9] { value: "e" } + } + value: { + IDENT [10] { + name: @index0 + } + } + } + } + } + } + CREATE_MAP [11] { + MAP_ENTRY [12] { + key: { + CONSTANT [13] { value: "a" } + } + value: { + IDENT [14] { + name: @index0 + } + } + } + MAP_ENTRY [15] { + key: { + CONSTANT [16] { value: "c" } + } + value: { + IDENT [17] { + name: @index0 + } + } + } + MAP_ENTRY [18] { + key: { + CONSTANT [19] { value: "d" } + } + value: { + IDENT [20] { + name: @index1 + } + } + } + MAP_ENTRY [21] { + key: { + CONSTANT [22] { value: "e" } + } + value: { + IDENT [23] { + name: @index1 + } + } + } + } + } +} +Test case: NESTED_LIST_CONSTRUCTION +Source: [1, [1,2,3,4], 2, [1,2,3,4], 5, [1,2,3,4], 7, [[1,2], [1,2,3,4]], [1,2]] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + CONSTANT [6] { value: 3 } + CONSTANT [7] { value: 4 } + } + } + CREATE_LIST [8] { + elements: { + CONSTANT [9] { value: 1 } + CONSTANT [10] { value: 2 } + } + } + CREATE_LIST [11] { + elements: { + IDENT [12] { + name: @index1 + } + IDENT [13] { + name: @index0 + } + } + } + } + } + CREATE_LIST [14] { + elements: { + CONSTANT [15] { value: 1 } + IDENT [16] { + name: @index0 + } + CONSTANT [17] { value: 2 } + IDENT [18] { + name: @index0 + } + CONSTANT [19] { value: 5 } + IDENT [20] { + name: @index0 + } + CONSTANT [21] { value: 7 } + IDENT [22] { + name: @index2 + } + IDENT [23] { + name: @index1 + } + } + } + } +} +Test case: SELECT +Source: msg.single_int64 + msg.single_int64 == 6 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.single_int64 + } + CALL [5] { + function: _+_ + args: { + IDENT [6] { + name: @index0 + } + IDENT [7] { + name: @index0 + } + } + } + } + } + CALL [8] { + function: _==_ + args: { + IDENT [9] { + name: @index1 + } + CONSTANT [10] { value: 6 } + } + } + } +} +Test case: SELECT_NESTED_1 +Source: msg.oneof_type.payload.single_int64 + msg.oneof_type.payload.single_int32 + msg.oneof_type.payload.single_int64 + msg.single_int64 + msg.oneof_type.payload.oneof_type.payload.single_int64 == 31 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.single_int64 + } + SELECT [9] { + SELECT [10] { + SELECT [11] { + IDENT [12] { + name: @index1 + }.oneof_type + }.payload + }.single_int64 + } + SELECT [13] { + IDENT [14] { + name: msg + }.single_int64 + } + CALL [15] { + function: _+_ + args: { + CALL [16] { + function: _+_ + args: { + IDENT [17] { + name: @index2 + } + SELECT [18] { + IDENT [19] { + name: @index1 + }.single_int32 + } + } + } + IDENT [20] { + name: @index2 + } + } + } + CALL [21] { + function: _+_ + args: { + CALL [22] { + function: _+_ + args: { + IDENT [23] { + name: @index5 + } + IDENT [24] { + name: @index4 + } + } + } + IDENT [25] { + name: @index3 + } + } + } + } + } + CALL [26] { + function: _==_ + args: { + IDENT [27] { + name: @index6 + } + CONSTANT [28] { value: 31 } + } + } + } +} +Test case: SELECT_NESTED_2 +Source: true || msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload.single_bool || msg.oneof_type.payload.oneof_type.payload.oneof_type.child.child.payload.single_bool +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.oneof_type + } + SELECT [9] { + IDENT [10] { + name: @index2 + }.payload + } + SELECT [11] { + IDENT [12] { + name: @index3 + }.oneof_type + } + SELECT [13] { + SELECT [14] { + SELECT [15] { + IDENT [16] { + name: @index4 + }.child + }.child + }.payload + } + SELECT [17] { + IDENT [18] { + name: @index5 + }.single_bool + } + SELECT [19] { + SELECT [20] { + SELECT [21] { + IDENT [22] { + name: @index4 + }.payload + }.oneof_type + }.payload + } + CALL [23] { + function: _||_ + args: { + CONSTANT [24] { value: true } + SELECT [25] { + IDENT [26] { + name: @index7 + }.single_bool + } + } + } + } + } + CALL [27] { + function: _||_ + args: { + IDENT [28] { + name: @index8 + } + IDENT [29] { + name: @index6 + } + } + } + } +} +Test case: SELECT_NESTED_MESSAGE_MAP_INDEX_1 +Source: msg.oneof_type.payload.map_int32_int64[1] + msg.oneof_type.payload.map_int32_int64[1] + msg.oneof_type.payload.map_int32_int64[1] == 15 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.map_int32_int64 + } + CALL [9] { + function: _[_] + args: { + IDENT [10] { + name: @index2 + } + CONSTANT [11] { value: 1 } + } + } + CALL [12] { + function: _+_ + args: { + CALL [13] { + function: _+_ + args: { + IDENT [14] { + name: @index3 + } + IDENT [15] { + name: @index3 + } + } + } + IDENT [16] { + name: @index3 + } + } + } + } + } + CALL [17] { + function: _==_ + args: { + IDENT [18] { + name: @index4 + } + CONSTANT [19] { value: 15 } + } + } + } +} +Test case: SELECT_NESTED_MESSAGE_MAP_INDEX_2 +Source: msg.oneof_type.payload.map_int32_int64[0] + msg.oneof_type.payload.map_int32_int64[1] + msg.oneof_type.payload.map_int32_int64[2] == 8 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.map_int32_int64 + } + CALL [9] { + function: _+_ + args: { + CALL [10] { + function: _+_ + args: { + CALL [11] { + function: _[_] + args: { + IDENT [12] { + name: @index2 + } + CONSTANT [13] { value: 0 } + } + } + CALL [14] { + function: _[_] + args: { + IDENT [15] { + name: @index2 + } + CONSTANT [16] { value: 1 } + } + } + } + } + CALL [17] { + function: _[_] + args: { + IDENT [18] { + name: @index2 + } + CONSTANT [19] { value: 2 } + } + } + } + } + } + } + CALL [20] { + function: _==_ + args: { + IDENT [21] { + name: @index3 + } + CONSTANT [22] { value: 8 } + } + } + } +} +Test case: SELECT_NESTED_NO_COMMON_SUBEXPR +Source: msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload.single_int64 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + SELECT [4] { + SELECT [5] { + IDENT [6] { + name: msg + }.oneof_type + }.payload + }.oneof_type + } + SELECT [7] { + SELECT [8] { + SELECT [9] { + IDENT [10] { + name: @index0 + }.payload + }.oneof_type + }.payload + } + SELECT [11] { + SELECT [12] { + IDENT [13] { + name: @index1 + }.oneof_type + }.payload + } + } + } + SELECT [14] { + IDENT [15] { + name: @index2 + }.single_int64 + } + } +} +Test case: TERNARY +Source: (msg.single_int64 > 0 ? msg.single_int64 : 0) == 3 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.single_int64 + } + CALL [5] { + function: _?_:_ + args: { + CALL [6] { + function: _>_ + args: { + IDENT [7] { + name: @index0 + } + CONSTANT [8] { value: 0 } + } + } + IDENT [9] { + name: @index0 + } + CONSTANT [10] { value: 0 } + } + } + } + } + CALL [11] { + function: _==_ + args: { + IDENT [12] { + name: @index1 + } + CONSTANT [13] { value: 3 } + } + } + } +} +Test case: TERNARY_BIND_RHS_ONLY +Source: false ? false : (msg.single_int64) + ((msg.single_int64 + 1) * 2) == 11 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.single_int64 + } + CALL [5] { + function: _+_ + args: { + IDENT [6] { + name: @index0 + } + CALL [7] { + function: _*_ + args: { + CALL [8] { + function: _+_ + args: { + IDENT [9] { + name: @index0 + } + CONSTANT [10] { value: 1 } + } + } + CONSTANT [11] { value: 2 } + } + } + } + } + CALL [12] { + function: _==_ + args: { + IDENT [13] { + name: @index1 + } + CONSTANT [14] { value: 11 } + } + } + } + } + CALL [15] { + function: _?_:_ + args: { + CONSTANT [16] { value: false } + CONSTANT [17] { value: false } + IDENT [18] { + name: @index2 + } + } + } + } +} +Test case: NESTED_TERNARY +Source: (msg.single_int64 > 0 ? (msg.single_int32 > 0 ? msg.single_int64 + msg.single_int32 : 0) : 0) == 8 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.single_int64 + } + SELECT [5] { + IDENT [6] { + name: msg + }.single_int32 + } + CALL [7] { + function: _?_:_ + args: { + CALL [8] { + function: _>_ + args: { + IDENT [9] { + name: @index0 + } + CONSTANT [10] { value: 0 } + } + } + CALL [11] { + function: _?_:_ + args: { + CALL [12] { + function: _>_ + args: { + IDENT [13] { + name: @index1 + } + CONSTANT [14] { value: 0 } + } + } + CALL [15] { + function: _+_ + args: { + IDENT [16] { + name: @index0 + } + IDENT [17] { + name: @index1 + } + } + } + CONSTANT [18] { value: 0 } + } + } + CONSTANT [19] { value: 0 } + } + } + } + } + CALL [20] { + function: _==_ + args: { + IDENT [21] { + name: @index2 + } + CONSTANT [22] { value: 8 } + } + } + } +} +Test case: MULTIPLE_MACROS_1 +Source: size([[1].exists(i, i > 0)]) + size([[1].exists(j, j > 0)]) + size([[2].exists(k, k > 1)]) + size([[2].exists(l, l > 1)]) == 4 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + } + } + CALL [5] { + function: _>_ + args: { + IDENT [6] { + name: @c0:0 + } + CONSTANT [7] { value: 0 } + } + } + CALL [8] { + function: _||_ + args: { + IDENT [9] { + name: @x0:0 + } + IDENT [10] { + name: @index1 + } + } + } + COMPREHENSION [11] { + iter_var: @c0:0 + iter_range: { + IDENT [12] { + name: @index0 + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [13] { value: false } + } + loop_condition: { + CALL [14] { + function: @not_strictly_false + args: { + CALL [15] { + function: !_ + args: { + IDENT [16] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + IDENT [17] { + name: @index2 + } + } + result: { + IDENT [18] { + name: @x0:0 + } + } + } + CREATE_LIST [19] { + elements: { + IDENT [20] { + name: @index3 + } + } + } + CALL [21] { + function: size + args: { + IDENT [22] { + name: @index4 + } + } + } + CREATE_LIST [23] { + elements: { + CONSTANT [24] { value: 2 } + } + } + CALL [25] { + function: _>_ + args: { + IDENT [26] { + name: @c0:0 + } + CONSTANT [27] { value: 1 } + } + } + CALL [28] { + function: _||_ + args: { + IDENT [29] { + name: @x0:0 + } + IDENT [30] { + name: @index7 + } + } + } + COMPREHENSION [31] { + iter_var: @c0:0 + iter_range: { + IDENT [32] { + name: @index6 + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [33] { value: false } + } + loop_condition: { + CALL [34] { + function: @not_strictly_false + args: { + CALL [35] { + function: !_ + args: { + IDENT [36] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + IDENT [37] { + name: @index8 + } + } + result: { + IDENT [38] { + name: @x0:0 + } + } + } + CREATE_LIST [39] { + elements: { + IDENT [40] { + name: @index9 + } + } + } + CALL [41] { + function: size + args: { + IDENT [42] { + name: @index10 + } + } + } + CALL [43] { + function: _+_ + args: { + CALL [44] { + function: _+_ + args: { + CALL [45] { + function: _+_ + args: { + IDENT [46] { + name: @index5 + } + IDENT [47] { + name: @index5 + } + } + } + IDENT [48] { + name: @index11 + } + } + } + IDENT [49] { + name: @index11 + } + } + } + } + } + CALL [50] { + function: _==_ + args: { + IDENT [51] { + name: @index12 + } + CONSTANT [52] { value: 4 } + } + } + } +} +Test case: MULTIPLE_MACROS_2 +Source: [[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == 'a')] + [['a'].exists(l, l == 'a')] == [true, true, true, true] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + } + } + CALL [5] { + function: _>_ + args: { + IDENT [6] { + name: @c0:0 + } + CONSTANT [7] { value: 0 } + } + } + CALL [8] { + function: _||_ + args: { + IDENT [9] { + name: @x0:0 + } + IDENT [10] { + name: @index1 + } + } + } + COMPREHENSION [11] { + iter_var: @c0:0 + iter_range: { + IDENT [12] { + name: @index0 + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [13] { value: false } + } + loop_condition: { + CALL [14] { + function: @not_strictly_false + args: { + CALL [15] { + function: !_ + args: { + IDENT [16] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + IDENT [17] { + name: @index2 + } + } + result: { + IDENT [18] { + name: @x0:0 + } + } + } + CREATE_LIST [19] { + elements: { + IDENT [20] { + name: @index3 + } + } + } + CREATE_LIST [21] { + elements: { + CONSTANT [22] { value: "a" } + } + } + CALL [23] { + function: _==_ + args: { + IDENT [24] { + name: @c0:1 + } + CONSTANT [25] { value: "a" } + } + } + CALL [26] { + function: _||_ + args: { + IDENT [27] { + name: @x0:1 + } + IDENT [28] { + name: @index6 + } + } + } + COMPREHENSION [29] { + iter_var: @c0:1 + iter_range: { + IDENT [30] { + name: @index5 + } + } + accu_var: @x0:1 + accu_init: { + CONSTANT [31] { value: false } + } + loop_condition: { + CALL [32] { + function: @not_strictly_false + args: { + CALL [33] { + function: !_ + args: { + IDENT [34] { + name: @x0:1 + } + } + } + } + } + } + loop_step: { + IDENT [35] { + name: @index7 + } + } + result: { + IDENT [36] { + name: @x0:1 + } + } + } + CREATE_LIST [37] { + elements: { + IDENT [38] { + name: @index8 + } + } + } + CREATE_LIST [39] { + elements: { + CONSTANT [40] { value: true } + CONSTANT [41] { value: true } + CONSTANT [42] { value: true } + CONSTANT [43] { value: true } + } + } + CALL [44] { + function: _+_ + args: { + CALL [45] { + function: _+_ + args: { + CALL [46] { + function: _+_ + args: { + IDENT [47] { + name: @index4 + } + IDENT [48] { + name: @index4 + } + } + } + IDENT [49] { + name: @index9 + } + } + } + IDENT [50] { + name: @index9 + } + } + } + } + } + CALL [51] { + function: _==_ + args: { + IDENT [52] { + name: @index11 + } + IDENT [53] { + name: @index10 + } + } + } + } +} +Test case: NESTED_MACROS +Source: [1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [[2, 3, 4], [2, 3, 4], [2, 3, 4]] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + CONSTANT [6] { value: 3 } + } + } + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 2 } + CONSTANT [9] { value: 3 } + CONSTANT [10] { value: 4 } + } + } + CREATE_LIST [11] { + elements: { + IDENT [12] { + name: @index1 + } + IDENT [13] { + name: @index1 + } + IDENT [14] { + name: @index1 + } + } + } + CALL [15] { + function: _+_ + args: { + IDENT [16] { + name: @x1:0 + } + CREATE_LIST [17] { + elements: { + CALL [18] { + function: _+_ + args: { + IDENT [19] { + name: @c1:0 + } + CONSTANT [20] { value: 1 } + } + } + } + } + } + } + CREATE_LIST [21] { + elements: { + COMPREHENSION [22] { + iter_var: @c1:0 + iter_range: { + IDENT [23] { + name: @index0 + } + } + accu_var: @x1:0 + accu_init: { + CREATE_LIST [24] { + elements: { + } + } + } + loop_condition: { + CONSTANT [25] { value: true } + } + loop_step: { + IDENT [26] { + name: @index3 + } + } + result: { + IDENT [27] { + name: @x1:0 + } + } + } + } + } + COMPREHENSION [28] { + iter_var: @c0:0 + iter_range: { + IDENT [29] { + name: @index0 + } + } + accu_var: @x0:0 + accu_init: { + CREATE_LIST [30] { + elements: { + } + } + } + loop_condition: { + CONSTANT [31] { value: true } + } + loop_step: { + CALL [32] { + function: _+_ + args: { + IDENT [33] { + name: @x0:0 + } + IDENT [34] { + name: @index4 + } + } + } + } + result: { + IDENT [35] { + name: @x0:0 + } + } + } + } + } + CALL [36] { + function: _==_ + args: { + IDENT [37] { + name: @index5 + } + IDENT [38] { + name: @index2 + } + } + } + } +} +Test case: NESTED_MACROS_2 +Source: [1, 2].map(y, [1, 2, 3].filter(x, x == y)) == [[1], [2]] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CREATE_LIST [4] { + elements: { + CONSTANT [5] { value: 1 } + } + } + CREATE_LIST [6] { + elements: { + CONSTANT [7] { value: 2 } + } + } + } + } + CALL [8] { + function: _?_:_ + args: { + CALL [9] { + function: _==_ + args: { + IDENT [10] { + name: @c1:0 + } + IDENT [11] { + name: @c0:0 + } + } + } + CALL [12] { + function: _+_ + args: { + IDENT [13] { + name: @x1:0 + } + CREATE_LIST [14] { + elements: { + IDENT [15] { + name: @c1:0 + } + } + } + } + } + IDENT [16] { + name: @x1:0 + } + } + } + CREATE_LIST [17] { + elements: { + COMPREHENSION [18] { + iter_var: @c1:0 + iter_range: { + CREATE_LIST [19] { + elements: { + CONSTANT [20] { value: 1 } + CONSTANT [21] { value: 2 } + CONSTANT [22] { value: 3 } + } + } + } + accu_var: @x1:0 + accu_init: { + CREATE_LIST [23] { + elements: { + } + } + } + loop_condition: { + CONSTANT [24] { value: true } + } + loop_step: { + IDENT [25] { + name: @index1 + } + } + result: { + IDENT [26] { + name: @x1:0 + } + } + } + } + } + COMPREHENSION [27] { + iter_var: @c0:0 + iter_range: { + CREATE_LIST [28] { + elements: { + CONSTANT [29] { value: 1 } + CONSTANT [30] { value: 2 } + } + } + } + accu_var: @x0:0 + accu_init: { + CREATE_LIST [31] { + elements: { + } + } + } + loop_condition: { + CONSTANT [32] { value: true } + } + loop_step: { + CALL [33] { + function: _+_ + args: { + IDENT [34] { + name: @x0:0 + } + IDENT [35] { + name: @index2 + } + } + } + } + result: { + IDENT [36] { + name: @x0:0 + } + } + } + } + } + CALL [37] { + function: _==_ + args: { + IDENT [38] { + name: @index3 + } + IDENT [39] { + name: @index0 + } + } + } + } +} +Test case: INCLUSION_LIST +Source: 1 in [1,2,3] && 2 in [1,2,3] && 3 in [3, [1,2,3]] && 1 in [1,2,3] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + CONSTANT [6] { value: 3 } + } + } + CALL [7] { + function: @in + args: { + CONSTANT [8] { value: 1 } + IDENT [9] { + name: @index0 + } + } + } + CALL [10] { + function: _&&_ + args: { + CALL [11] { + function: @in + args: { + CONSTANT [12] { value: 3 } + CREATE_LIST [13] { + elements: { + CONSTANT [14] { value: 3 } + IDENT [15] { + name: @index0 + } + } + } + } + } + IDENT [16] { + name: @index1 + } + } + } + CALL [17] { + function: _&&_ + args: { + IDENT [18] { + name: @index1 + } + CALL [19] { + function: @in + args: { + CONSTANT [20] { value: 2 } + IDENT [21] { + name: @index0 + } + } + } + } + } + } + } + CALL [22] { + function: _&&_ + args: { + IDENT [23] { + name: @index3 + } + IDENT [24] { + name: @index2 + } + } + } + } +} +Test case: INCLUSION_MAP +Source: 2 in {'a': 1, 2: {true: false}, 3: {true: false}} +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: true } + } + value: { + CONSTANT [6] { value: false } + } + } + } + CREATE_MAP [7] { + MAP_ENTRY [8] { + key: { + CONSTANT [9] { value: "a" } + } + value: { + CONSTANT [10] { value: 1 } + } + } + MAP_ENTRY [11] { + key: { + CONSTANT [12] { value: 2 } + } + value: { + IDENT [13] { + name: @index0 + } + } + } + MAP_ENTRY [14] { + key: { + CONSTANT [15] { value: 3 } + } + value: { + IDENT [16] { + name: @index0 + } + } + } + } + } + } + CALL [17] { + function: @in + args: { + CONSTANT [18] { value: 2 } + IDENT [19] { + name: @index1 + } + } + } + } +} +Test case: MACRO_ITER_VAR_NOT_REFERENCED +Source: [1,2].map(i, [1, 2].map(i, [3,4])) == [[[3, 4], [3, 4]], [[3, 4], [3, 4]]] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + } + } + CREATE_LIST [6] { + elements: { + CONSTANT [7] { value: 3 } + CONSTANT [8] { value: 4 } + } + } + CREATE_LIST [9] { + elements: { + IDENT [10] { + name: @index1 + } + IDENT [11] { + name: @index1 + } + } + } + CREATE_LIST [12] { + elements: { + IDENT [13] { + name: @index2 + } + IDENT [14] { + name: @index2 + } + } + } + COMPREHENSION [15] { + iter_var: @c1:0 + iter_range: { + IDENT [16] { + name: @index0 + } + } + accu_var: @x1:0 + accu_init: { + CREATE_LIST [17] { + elements: { + } + } + } + loop_condition: { + CONSTANT [18] { value: true } + } + loop_step: { + CALL [19] { + function: _+_ + args: { + IDENT [20] { + name: @x1:0 + } + CREATE_LIST [21] { + elements: { + IDENT [22] { + name: @index1 + } + } + } + } + } + } + result: { + IDENT [23] { + name: @x1:0 + } + } + } + COMPREHENSION [24] { + iter_var: @c0:0 + iter_range: { + IDENT [25] { + name: @index0 + } + } + accu_var: @x0:0 + accu_init: { + CREATE_LIST [26] { + elements: { + } + } + } + loop_condition: { + CONSTANT [27] { value: true } + } + loop_step: { + CALL [28] { + function: _+_ + args: { + IDENT [29] { + name: @x0:0 + } + CREATE_LIST [30] { + elements: { + IDENT [31] { + name: @index4 + } + } + } + } + } + } + result: { + IDENT [32] { + name: @x0:0 + } + } + } + } + } + CALL [33] { + function: _==_ + args: { + IDENT [34] { + name: @index5 + } + IDENT [35] { + name: @index3 + } + } + } + } +} +Test case: MACRO_SHADOWED_VARIABLE +Source: [x - 1 > 3 ? x - 1 : 5].exists(x, x - 1 > 3) || x - 1 > 3 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _-_ + args: { + IDENT [4] { + name: x + } + CONSTANT [5] { value: 1 } + } + } + CALL [6] { + function: _>_ + args: { + IDENT [7] { + name: @index0 + } + CONSTANT [8] { value: 3 } + } + } + CALL [9] { + function: _||_ + args: { + IDENT [10] { + name: @x0:0 + } + CALL [11] { + function: _>_ + args: { + CALL [12] { + function: _-_ + args: { + IDENT [13] { + name: @c0:0 + } + CONSTANT [14] { value: 1 } + } + } + CONSTANT [15] { value: 3 } + } + } + } + } + COMPREHENSION [16] { + iter_var: @c0:0 + iter_range: { + CREATE_LIST [17] { + elements: { + CALL [18] { + function: _?_:_ + args: { + IDENT [19] { + name: @index1 + } + IDENT [20] { + name: @index0 + } + CONSTANT [21] { value: 5 } + } + } + } + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [22] { value: false } + } + loop_condition: { + CALL [23] { + function: @not_strictly_false + args: { + CALL [24] { + function: !_ + args: { + IDENT [25] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + IDENT [26] { + name: @index2 + } + } + result: { + IDENT [27] { + name: @x0:0 + } + } + } + } + } + CALL [28] { + function: _||_ + args: { + IDENT [29] { + name: @index3 + } + IDENT [30] { + name: @index1 + } + } + } + } +} +Test case: MACRO_SHADOWED_VARIABLE_2 +Source: ["foo", "bar"].map(x, [x + x, x + x]).map(x, [x + x, x + x]) +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _+_ + args: { + IDENT [4] { + name: @c1:0 + } + IDENT [5] { + name: @c1:0 + } + } + } + CALL [6] { + function: _+_ + args: { + IDENT [7] { + name: @c0:0 + } + IDENT [8] { + name: @c0:0 + } + } + } + CALL [9] { + function: _+_ + args: { + IDENT [10] { + name: @x0:0 + } + CREATE_LIST [11] { + elements: { + CREATE_LIST [12] { + elements: { + IDENT [13] { + name: @index1 + } + IDENT [14] { + name: @index1 + } + } + } + } + } + } + } + CALL [15] { + function: _+_ + args: { + IDENT [16] { + name: @x1:0 + } + CREATE_LIST [17] { + elements: { + CREATE_LIST [18] { + elements: { + IDENT [19] { + name: @index0 + } + IDENT [20] { + name: @index0 + } + } + } + } + } + } + } + COMPREHENSION [21] { + iter_var: @c1:0 + iter_range: { + CREATE_LIST [22] { + elements: { + CONSTANT [23] { value: "foo" } + CONSTANT [24] { value: "bar" } + } + } + } + accu_var: @x1:0 + accu_init: { + CREATE_LIST [25] { + elements: { + } + } + } + loop_condition: { + CONSTANT [26] { value: true } + } + loop_step: { + IDENT [27] { + name: @index3 + } + } + result: { + IDENT [28] { + name: @x1:0 + } + } + } + } + } + COMPREHENSION [29] { + iter_var: @c0:0 + iter_range: { + IDENT [30] { + name: @index4 + } + } + accu_var: @x0:0 + accu_init: { + CREATE_LIST [31] { + elements: { + } + } + } + loop_condition: { + CONSTANT [32] { value: true } + } + loop_step: { + IDENT [33] { + name: @index2 + } + } + result: { + IDENT [34] { + name: @x0:0 + } + } + } + } +} +Test case: PRESENCE_TEST +Source: has({'a': true}.a) && {'a':true}['a'] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: "a" } + } + value: { + CONSTANT [6] { value: true } + } + } + } + CALL [7] { + function: _[_] + args: { + IDENT [8] { + name: @index0 + } + CONSTANT [9] { value: "a" } + } + } + } + } + CALL [10] { + function: _&&_ + args: { + SELECT [11] { + IDENT [12] { + name: @index0 + }.a~presence_test + } + IDENT [13] { + name: @index1 + } + } + } + } +} +Test case: PRESENCE_TEST_WITH_TERNARY +Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : 0) == 10 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + CALL [5] { + function: _?_:_ + args: { + SELECT [6] { + IDENT [7] { + name: @index0 + }.payload~presence_test + } + SELECT [8] { + SELECT [9] { + IDENT [10] { + name: @index0 + }.payload + }.single_int64 + } + CONSTANT [11] { value: 0 } + } + } + } + } + CALL [12] { + function: _==_ + args: { + IDENT [13] { + name: @index1 + } + CONSTANT [14] { value: 10 } + } + } + } +} +Test case: PRESENCE_TEST_WITH_TERNARY_2 +Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : msg.oneof_type.payload.single_int64 * 0) == 10 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.single_int64 + } + CALL [9] { + function: _?_:_ + args: { + SELECT [10] { + IDENT [11] { + name: @index0 + }.payload~presence_test + } + IDENT [12] { + name: @index2 + } + CALL [13] { + function: _*_ + args: { + IDENT [14] { + name: @index2 + } + CONSTANT [15] { value: 0 } + } + } + } + } + } + } + CALL [16] { + function: _==_ + args: { + IDENT [17] { + name: @index3 + } + CONSTANT [18] { value: 10 } + } + } + } +} +Test case: PRESENCE_TEST_WITH_TERNARY_3 +Source: (has(msg.oneof_type.payload.single_int64) ? msg.oneof_type.payload.single_int64 : msg.oneof_type.payload.single_int64 * 0) == 10 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.single_int64 + } + CALL [9] { + function: _?_:_ + args: { + SELECT [10] { + IDENT [11] { + name: @index1 + }.single_int64~presence_test + } + IDENT [12] { + name: @index2 + } + CALL [13] { + function: _*_ + args: { + IDENT [14] { + name: @index2 + } + CONSTANT [15] { value: 0 } + } + } + } + } + } + } + CALL [16] { + function: _==_ + args: { + IDENT [17] { + name: @index3 + } + CONSTANT [18] { value: 10 } + } + } + } +} +Test case: PRESENCE_TEST_WITH_TERNARY_NESTED +Source: (has(msg.oneof_type) && has(msg.oneof_type.payload) && has(msg.oneof_type.payload.single_int64)) ? ((has(msg.oneof_type.payload.map_string_string) && has(msg.oneof_type.payload.map_string_string.key)) ? msg.oneof_type.payload.map_string_string.key == 'A' : false) : false +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.map_string_string + } + CALL [9] { + function: _?_:_ + args: { + CALL [10] { + function: _&&_ + args: { + SELECT [11] { + IDENT [12] { + name: @index1 + }.map_string_string~presence_test + } + SELECT [13] { + IDENT [14] { + name: @index2 + }.key~presence_test + } + } + } + CALL [15] { + function: _==_ + args: { + SELECT [16] { + IDENT [17] { + name: @index2 + }.key + } + CONSTANT [18] { value: "A" } + } + } + CONSTANT [19] { value: false } + } + } + CALL [20] { + function: _&&_ + args: { + CALL [21] { + function: _&&_ + args: { + SELECT [22] { + IDENT [23] { + name: msg + }.oneof_type~presence_test + } + SELECT [24] { + IDENT [25] { + name: @index0 + }.payload~presence_test + } + } + } + SELECT [26] { + IDENT [27] { + name: @index1 + }.single_int64~presence_test + } + } + } + } + } + CALL [28] { + function: _?_:_ + args: { + IDENT [29] { + name: @index4 + } + IDENT [30] { + name: @index3 + } + CONSTANT [31] { value: false } + } + } + } +} +Test case: OPTIONAL_LIST +Source: [10, ?optional.none(), [?optional.none(), ?opt_x], [?optional.none(), ?opt_x]] == [10, [5], [5]] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: optional.none + args: { + } + } + CREATE_LIST [4] { + elements: { + IDENT [5] { + name: @index0 + } + IDENT [6] { + name: opt_x + } + } + optional_indices: [0, 1] + } + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 5 } + } + } + CREATE_LIST [9] { + elements: { + CONSTANT [10] { value: 10 } + IDENT [11] { + name: @index2 + } + IDENT [12] { + name: @index2 + } + } + } + CREATE_LIST [13] { + elements: { + CONSTANT [14] { value: 10 } + IDENT [15] { + name: @index0 + } + IDENT [16] { + name: @index1 + } + IDENT [17] { + name: @index1 + } + } + optional_indices: [0] + } + } + } + CALL [18] { + function: _==_ + args: { + IDENT [19] { + name: @index4 + } + IDENT [20] { + name: @index3 + } + } + } + } +} +Test case: OPTIONAL_MAP +Source: {?'hello': optional.of('hello')}['hello'] + {?'hello': optional.of('hello')}['hello'] == 'hellohello' +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: optional.of + args: { + CONSTANT [4] { value: "hello" } + } + } + CREATE_MAP [5] { + MAP_ENTRY [6] { + key: { + CONSTANT [7] { value: "hello" } + } + optional_entry: true + value: { + IDENT [8] { + name: @index0 + } + } + } + } + CALL [9] { + function: _[_] + args: { + IDENT [10] { + name: @index1 + } + CONSTANT [11] { value: "hello" } + } + } + CALL [12] { + function: _+_ + args: { + IDENT [13] { + name: @index2 + } + IDENT [14] { + name: @index2 + } + } + } + } + } + CALL [15] { + function: _==_ + args: { + IDENT [16] { + name: @index3 + } + CONSTANT [17] { value: "hellohello" } + } + } + } +} +Test case: OPTIONAL_MAP_CHAINED +Source: {?'key': optional.of('test')}[?'bogus'].or({'key': 'test'}[?'bogus']).orValue({'key': 'test'}['key']) == 'test' +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: "key" } + } + value: { + CONSTANT [6] { value: "test" } + } + } + } + CALL [7] { + function: _[_] + args: { + IDENT [8] { + name: @index0 + } + CONSTANT [9] { value: "key" } + } + } + CALL [10] { + function: _[?_] + args: { + IDENT [11] { + name: @index0 + } + CONSTANT [12] { value: "bogus" } + } + } + CALL [13] { + function: _[?_] + args: { + CREATE_MAP [14] { + MAP_ENTRY [15] { + key: { + CONSTANT [16] { value: "key" } + } + optional_entry: true + value: { + CALL [17] { + function: optional.of + args: { + CONSTANT [18] { value: "test" } + } + } + } + } + } + CONSTANT [19] { value: "bogus" } + } + } + CALL [20] { + function: orValue + target: { + CALL [21] { + function: or + target: { + IDENT [22] { + name: @index3 + } + } + args: { + IDENT [23] { + name: @index2 + } + } + } + } + args: { + IDENT [24] { + name: @index1 + } + } + } + } + } + CALL [25] { + function: _==_ + args: { + IDENT [26] { + name: @index4 + } + CONSTANT [27] { value: "test" } + } + } + } +} +Test case: OPTIONAL_MESSAGE +Source: TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}.single_int32 + TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}.single_int64 == 5 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: optional.ofNonZeroValue + args: { + CONSTANT [4] { value: 1 } + } + } + CALL [5] { + function: optional.of + args: { + CONSTANT [6] { value: 4 } + } + } + CREATE_STRUCT [7] { + name: TestAllTypes + entries: { + ENTRY [8] { + field_key: single_int64 + optional_entry: true + value: { + IDENT [9] { + name: @index0 + } + } + } + ENTRY [10] { + field_key: single_int32 + optional_entry: true + value: { + IDENT [11] { + name: @index1 + } + } + } + } + } + CALL [12] { + function: _+_ + args: { + SELECT [13] { + IDENT [14] { + name: @index2 + }.single_int32 + } + SELECT [15] { + IDENT [16] { + name: @index2 + }.single_int64 + } + } + } + } + } + CALL [17] { + function: _==_ + args: { + IDENT [18] { + name: @index3 + } + CONSTANT [19] { value: 5 } + } + } + } +} +Test case: CALL +Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('h' + 'e' + 'l' + 'l' + 'o') +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _+_ + args: { + CONSTANT [4] { value: "h" } + CONSTANT [5] { value: "e" } + } + } + CALL [6] { + function: _+_ + args: { + IDENT [7] { + name: @index0 + } + CONSTANT [8] { value: "l" } + } + } + CALL [9] { + function: _+_ + args: { + IDENT [10] { + name: @index1 + } + CONSTANT [11] { value: "l" } + } + } + CALL [12] { + function: _+_ + args: { + IDENT [13] { + name: @index2 + } + CONSTANT [14] { value: "o" } + } + } + CALL [15] { + function: _+_ + args: { + IDENT [16] { + name: @index3 + } + CONSTANT [17] { value: " world" } + } + } + } + } + CALL [18] { + function: matches + target: { + IDENT [19] { + name: @index4 + } + } + args: { + IDENT [20] { + name: @index3 + } + } + } + } +} +Test case: CALL_ARGUMENT_NESTED_NO_COMMON_SUBEXPR +Source: 'hello world'.matches('h' + 'e' + 'l' + 'l' + 'o') +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _+_ + args: { + CALL [4] { + function: _+_ + args: { + CALL [5] { + function: _+_ + args: { + CONSTANT [6] { value: "h" } + CONSTANT [7] { value: "e" } + } + } + CONSTANT [8] { value: "l" } + } + } + CONSTANT [9] { value: "l" } + } + } + CALL [10] { + function: _+_ + args: { + IDENT [11] { + name: @index0 + } + CONSTANT [12] { value: "o" } + } + } + } + } + CALL [13] { + function: matches + target: { + CONSTANT [14] { value: "hello world" } + } + args: { + IDENT [15] { + name: @index1 + } + } + } + } +} +Test case: CALL_TARGET_NESTED_NO_COMMON_SUBEXPR +Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('hello') +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _+_ + args: { + CALL [4] { + function: _+_ + args: { + CALL [5] { + function: _+_ + args: { + CONSTANT [6] { value: "h" } + CONSTANT [7] { value: "e" } + } + } + CONSTANT [8] { value: "l" } + } + } + CONSTANT [9] { value: "l" } + } + } + CALL [10] { + function: _+_ + args: { + CALL [11] { + function: _+_ + args: { + IDENT [12] { + name: @index0 + } + CONSTANT [13] { value: "o" } + } + } + CONSTANT [14] { value: " world" } + } + } + } + } + CALL [15] { + function: matches + target: { + IDENT [16] { + name: @index1 + } + } + args: { + CONSTANT [17] { value: "hello" } + } + } + } +} +Test case: CALL_BOTH_ARGUMENT_TARGET_NESTED_NO_COMMON_SUBEXPR +Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('w' + 'o' + 'r' + 'l' + 'd') +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _+_ + args: { + CALL [4] { + function: _+_ + args: { + CALL [5] { + function: _+_ + args: { + CONSTANT [6] { value: "w" } + CONSTANT [7] { value: "o" } + } + } + CONSTANT [8] { value: "r" } + } + } + CONSTANT [9] { value: "l" } + } + } + CALL [10] { + function: _+_ + args: { + IDENT [11] { + name: @index0 + } + CONSTANT [12] { value: "d" } + } + } + CALL [13] { + function: _+_ + args: { + CALL [14] { + function: _+_ + args: { + CALL [15] { + function: _+_ + args: { + CONSTANT [16] { value: "h" } + CONSTANT [17] { value: "e" } + } + } + CONSTANT [18] { value: "l" } + } + } + CONSTANT [19] { value: "l" } + } + } + CALL [20] { + function: _+_ + args: { + CALL [21] { + function: _+_ + args: { + IDENT [22] { + name: @index2 + } + CONSTANT [23] { value: "o" } + } + } + CONSTANT [24] { value: " world" } + } + } + } + } + CALL [25] { + function: matches + target: { + IDENT [26] { + name: @index3 + } + } + args: { + IDENT [27] { + name: @index1 + } + } + } + } +} diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_4.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_4.baseline new file mode 100644 index 000000000..c51cefac6 --- /dev/null +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_4.baseline @@ -0,0 +1,3326 @@ +Test case: SIZE_1 +Source: size([1,2]) + size([1,2]) + 1 == 5 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + } + } + CALL [6] { + function: size + args: { + IDENT [7] { + name: @index0 + } + } + } + CALL [8] { + function: _+_ + args: { + CALL [9] { + function: _+_ + args: { + IDENT [10] { + name: @index1 + } + IDENT [11] { + name: @index1 + } + } + } + CONSTANT [12] { value: 1 } + } + } + } + } + CALL [13] { + function: _==_ + args: { + IDENT [14] { + name: @index2 + } + CONSTANT [15] { value: 5 } + } + } + } +} +Test case: SIZE_2 +Source: 2 + size([1,2]) + size([1,2]) + 1 == 7 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + } + } + CALL [6] { + function: size + args: { + IDENT [7] { + name: @index0 + } + } + } + CALL [8] { + function: _+_ + args: { + CALL [9] { + function: _+_ + args: { + CALL [10] { + function: _+_ + args: { + CONSTANT [11] { value: 2 } + IDENT [12] { + name: @index1 + } + } + } + IDENT [13] { + name: @index1 + } + } + } + CONSTANT [14] { value: 1 } + } + } + } + } + CALL [15] { + function: _==_ + args: { + IDENT [16] { + name: @index2 + } + CONSTANT [17] { value: 7 } + } + } + } +} +Test case: SIZE_3 +Source: size([0]) + size([0]) + size([1,2]) + size([1,2]) == 6 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 0 } + } + } + CALL [5] { + function: size + args: { + IDENT [6] { + name: @index0 + } + } + } + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 1 } + CONSTANT [9] { value: 2 } + } + } + CALL [10] { + function: size + args: { + IDENT [11] { + name: @index2 + } + } + } + CALL [12] { + function: _+_ + args: { + CALL [13] { + function: _+_ + args: { + CALL [14] { + function: _+_ + args: { + IDENT [15] { + name: @index1 + } + IDENT [16] { + name: @index1 + } + } + } + IDENT [17] { + name: @index3 + } + } + } + IDENT [18] { + name: @index3 + } + } + } + } + } + CALL [19] { + function: _==_ + args: { + IDENT [20] { + name: @index4 + } + CONSTANT [21] { value: 6 } + } + } + } +} +Test case: SIZE_4 +Source: 5 + size([0]) + size([0]) + size([1,2]) + size([1,2]) + size([1,2,3]) + size([1,2,3]) == 17 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 0 } + } + } + CALL [5] { + function: size + args: { + IDENT [6] { + name: @index0 + } + } + } + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 1 } + CONSTANT [9] { value: 2 } + } + } + CALL [10] { + function: size + args: { + IDENT [11] { + name: @index2 + } + } + } + CREATE_LIST [12] { + elements: { + CONSTANT [13] { value: 1 } + CONSTANT [14] { value: 2 } + CONSTANT [15] { value: 3 } + } + } + CALL [16] { + function: size + args: { + IDENT [17] { + name: @index4 + } + } + } + CALL [18] { + function: _+_ + args: { + CALL [19] { + function: _+_ + args: { + CALL [20] { + function: _+_ + args: { + CALL [21] { + function: _+_ + args: { + CONSTANT [22] { value: 5 } + IDENT [23] { + name: @index1 + } + } + } + IDENT [24] { + name: @index1 + } + } + } + IDENT [25] { + name: @index3 + } + } + } + IDENT [26] { + name: @index3 + } + } + } + CALL [27] { + function: _+_ + args: { + CALL [28] { + function: _+_ + args: { + IDENT [29] { + name: @index6 + } + IDENT [30] { + name: @index5 + } + } + } + IDENT [31] { + name: @index5 + } + } + } + } + } + CALL [32] { + function: _==_ + args: { + IDENT [33] { + name: @index7 + } + CONSTANT [34] { value: 17 } + } + } + } +} +Test case: TIMESTAMP +Source: timestamp(int(timestamp(1000000000))).getFullYear() + timestamp(int(timestamp(75))).getFullYear() + timestamp(int(timestamp(50))).getFullYear() + timestamp(int(timestamp(1000000000))).getFullYear() + timestamp(int(timestamp(50))).getSeconds() + timestamp(int(timestamp(200))).getFullYear() + timestamp(int(timestamp(200))).getFullYear() + timestamp(int(timestamp(75))).getMinutes() + timestamp(int(timestamp(1000000000))).getFullYear() == 13934 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: timestamp + args: { + CONSTANT [4] { value: 1000000000 } + } + } + CALL [5] { + function: int + args: { + IDENT [6] { + name: @index0 + } + } + } + CALL [7] { + function: timestamp + args: { + IDENT [8] { + name: @index1 + } + } + } + CALL [9] { + function: getFullYear + target: { + IDENT [10] { + name: @index2 + } + } + args: { + } + } + CALL [11] { + function: timestamp + args: { + CONSTANT [12] { value: 50 } + } + } + CALL [13] { + function: int + args: { + IDENT [14] { + name: @index4 + } + } + } + CALL [15] { + function: timestamp + args: { + IDENT [16] { + name: @index5 + } + } + } + CALL [17] { + function: timestamp + args: { + CONSTANT [18] { value: 200 } + } + } + CALL [19] { + function: int + args: { + IDENT [20] { + name: @index7 + } + } + } + CALL [21] { + function: timestamp + args: { + IDENT [22] { + name: @index8 + } + } + } + CALL [23] { + function: getFullYear + target: { + IDENT [24] { + name: @index9 + } + } + args: { + } + } + CALL [25] { + function: timestamp + args: { + CONSTANT [26] { value: 75 } + } + } + CALL [27] { + function: int + args: { + IDENT [28] { + name: @index11 + } + } + } + CALL [29] { + function: timestamp + args: { + IDENT [30] { + name: @index12 + } + } + } + CALL [31] { + function: getMinutes + target: { + IDENT [32] { + name: @index13 + } + } + args: { + } + } + CALL [33] { + function: getSeconds + target: { + IDENT [34] { + name: @index6 + } + } + args: { + } + } + CALL [35] { + function: _+_ + args: { + CALL [36] { + function: _+_ + args: { + CALL [37] { + function: _+_ + args: { + IDENT [38] { + name: @index3 + } + CALL [39] { + function: getFullYear + target: { + IDENT [40] { + name: @index13 + } + } + args: { + } + } + } + } + CALL [41] { + function: getFullYear + target: { + IDENT [42] { + name: @index6 + } + } + args: { + } + } + } + } + IDENT [43] { + name: @index3 + } + } + } + CALL [44] { + function: _+_ + args: { + CALL [45] { + function: _+_ + args: { + CALL [46] { + function: _+_ + args: { + CALL [47] { + function: _+_ + args: { + IDENT [48] { + name: @index16 + } + IDENT [49] { + name: @index15 + } + } + } + IDENT [50] { + name: @index10 + } + } + } + IDENT [51] { + name: @index10 + } + } + } + IDENT [52] { + name: @index14 + } + } + } + CALL [53] { + function: _+_ + args: { + IDENT [54] { + name: @index17 + } + IDENT [55] { + name: @index3 + } + } + } + } + } + CALL [56] { + function: _==_ + args: { + IDENT [57] { + name: @index18 + } + CONSTANT [58] { value: 13934 } + } + } + } +} +Test case: MAP_INDEX +Source: {"a": 2}["a"] + {"a": 2}["a"] * {"a": 2}["a"] == 6 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: "a" } + } + value: { + CONSTANT [6] { value: 2 } + } + } + } + CALL [7] { + function: _[_] + args: { + IDENT [8] { + name: @index0 + } + CONSTANT [9] { value: "a" } + } + } + CALL [10] { + function: _+_ + args: { + IDENT [11] { + name: @index1 + } + CALL [12] { + function: _*_ + args: { + IDENT [13] { + name: @index1 + } + IDENT [14] { + name: @index1 + } + } + } + } + } + } + } + CALL [15] { + function: _==_ + args: { + IDENT [16] { + name: @index2 + } + CONSTANT [17] { value: 6 } + } + } + } +} +Test case: NESTED_MAP_CONSTRUCTION +Source: {'a': {'b': 1}, 'c': {'b': 1}, 'd': {'e': {'b': 1}}, 'e': {'e': {'b': 1}}} +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: "b" } + } + value: { + CONSTANT [6] { value: 1 } + } + } + } + CREATE_MAP [7] { + MAP_ENTRY [8] { + key: { + CONSTANT [9] { value: "e" } + } + value: { + IDENT [10] { + name: @index0 + } + } + } + } + } + } + CREATE_MAP [11] { + MAP_ENTRY [12] { + key: { + CONSTANT [13] { value: "a" } + } + value: { + IDENT [14] { + name: @index0 + } + } + } + MAP_ENTRY [15] { + key: { + CONSTANT [16] { value: "c" } + } + value: { + IDENT [17] { + name: @index0 + } + } + } + MAP_ENTRY [18] { + key: { + CONSTANT [19] { value: "d" } + } + value: { + IDENT [20] { + name: @index1 + } + } + } + MAP_ENTRY [21] { + key: { + CONSTANT [22] { value: "e" } + } + value: { + IDENT [23] { + name: @index1 + } + } + } + } + } +} +Test case: NESTED_LIST_CONSTRUCTION +Source: [1, [1,2,3,4], 2, [1,2,3,4], 5, [1,2,3,4], 7, [[1,2], [1,2,3,4]], [1,2]] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + CONSTANT [6] { value: 3 } + CONSTANT [7] { value: 4 } + } + } + CREATE_LIST [8] { + elements: { + CONSTANT [9] { value: 1 } + CONSTANT [10] { value: 2 } + } + } + CREATE_LIST [11] { + elements: { + IDENT [12] { + name: @index1 + } + IDENT [13] { + name: @index0 + } + } + } + } + } + CREATE_LIST [14] { + elements: { + CONSTANT [15] { value: 1 } + IDENT [16] { + name: @index0 + } + CONSTANT [17] { value: 2 } + IDENT [18] { + name: @index0 + } + CONSTANT [19] { value: 5 } + IDENT [20] { + name: @index0 + } + CONSTANT [21] { value: 7 } + IDENT [22] { + name: @index2 + } + IDENT [23] { + name: @index1 + } + } + } + } +} +Test case: SELECT +Source: msg.single_int64 + msg.single_int64 == 6 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.single_int64 + } + CALL [5] { + function: _+_ + args: { + IDENT [6] { + name: @index0 + } + IDENT [7] { + name: @index0 + } + } + } + } + } + CALL [8] { + function: _==_ + args: { + IDENT [9] { + name: @index1 + } + CONSTANT [10] { value: 6 } + } + } + } +} +Test case: SELECT_NESTED_1 +Source: msg.oneof_type.payload.single_int64 + msg.oneof_type.payload.single_int32 + msg.oneof_type.payload.single_int64 + msg.single_int64 + msg.oneof_type.payload.oneof_type.payload.single_int64 == 31 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.single_int64 + } + SELECT [9] { + SELECT [10] { + SELECT [11] { + IDENT [12] { + name: @index1 + }.oneof_type + }.payload + }.single_int64 + } + CALL [13] { + function: _+_ + args: { + CALL [14] { + function: _+_ + args: { + CALL [15] { + function: _+_ + args: { + IDENT [16] { + name: @index2 + } + SELECT [17] { + IDENT [18] { + name: @index1 + }.single_int32 + } + } + } + IDENT [19] { + name: @index2 + } + } + } + SELECT [20] { + IDENT [21] { + name: msg + }.single_int64 + } + } + } + CALL [22] { + function: _+_ + args: { + IDENT [23] { + name: @index4 + } + IDENT [24] { + name: @index3 + } + } + } + } + } + CALL [25] { + function: _==_ + args: { + IDENT [26] { + name: @index5 + } + CONSTANT [27] { value: 31 } + } + } + } +} +Test case: SELECT_NESTED_2 +Source: true || msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload.single_bool || msg.oneof_type.payload.oneof_type.payload.oneof_type.child.child.payload.single_bool +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.oneof_type + } + SELECT [9] { + IDENT [10] { + name: @index2 + }.payload + } + SELECT [11] { + IDENT [12] { + name: @index3 + }.oneof_type + } + SELECT [13] { + SELECT [14] { + SELECT [15] { + SELECT [16] { + IDENT [17] { + name: @index4 + }.child + }.child + }.payload + }.single_bool + } + SELECT [18] { + SELECT [19] { + SELECT [20] { + SELECT [21] { + IDENT [22] { + name: @index4 + }.payload + }.oneof_type + }.payload + }.single_bool + } + CALL [23] { + function: _||_ + args: { + CONSTANT [24] { value: true } + IDENT [25] { + name: @index6 + } + } + } + } + } + CALL [26] { + function: _||_ + args: { + IDENT [27] { + name: @index7 + } + IDENT [28] { + name: @index5 + } + } + } + } +} +Test case: SELECT_NESTED_MESSAGE_MAP_INDEX_1 +Source: msg.oneof_type.payload.map_int32_int64[1] + msg.oneof_type.payload.map_int32_int64[1] + msg.oneof_type.payload.map_int32_int64[1] == 15 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.map_int32_int64 + } + CALL [9] { + function: _[_] + args: { + IDENT [10] { + name: @index2 + } + CONSTANT [11] { value: 1 } + } + } + CALL [12] { + function: _+_ + args: { + CALL [13] { + function: _+_ + args: { + IDENT [14] { + name: @index3 + } + IDENT [15] { + name: @index3 + } + } + } + IDENT [16] { + name: @index3 + } + } + } + } + } + CALL [17] { + function: _==_ + args: { + IDENT [18] { + name: @index4 + } + CONSTANT [19] { value: 15 } + } + } + } +} +Test case: SELECT_NESTED_MESSAGE_MAP_INDEX_2 +Source: msg.oneof_type.payload.map_int32_int64[0] + msg.oneof_type.payload.map_int32_int64[1] + msg.oneof_type.payload.map_int32_int64[2] == 8 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.map_int32_int64 + } + CALL [9] { + function: _+_ + args: { + CALL [10] { + function: _+_ + args: { + CALL [11] { + function: _[_] + args: { + IDENT [12] { + name: @index2 + } + CONSTANT [13] { value: 0 } + } + } + CALL [14] { + function: _[_] + args: { + IDENT [15] { + name: @index2 + } + CONSTANT [16] { value: 1 } + } + } + } + } + CALL [17] { + function: _[_] + args: { + IDENT [18] { + name: @index2 + } + CONSTANT [19] { value: 2 } + } + } + } + } + } + } + CALL [20] { + function: _==_ + args: { + IDENT [21] { + name: @index3 + } + CONSTANT [22] { value: 8 } + } + } + } +} +Test case: SELECT_NESTED_NO_COMMON_SUBEXPR +Source: msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload.single_int64 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + SELECT [4] { + SELECT [5] { + SELECT [6] { + IDENT [7] { + name: msg + }.oneof_type + }.payload + }.oneof_type + }.payload + } + SELECT [8] { + SELECT [9] { + SELECT [10] { + SELECT [11] { + IDENT [12] { + name: @index0 + }.oneof_type + }.payload + }.oneof_type + }.payload + } + } + } + SELECT [13] { + IDENT [14] { + name: @index1 + }.single_int64 + } + } +} +Test case: TERNARY +Source: (msg.single_int64 > 0 ? msg.single_int64 : 0) == 3 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.single_int64 + } + CALL [5] { + function: _?_:_ + args: { + CALL [6] { + function: _>_ + args: { + IDENT [7] { + name: @index0 + } + CONSTANT [8] { value: 0 } + } + } + IDENT [9] { + name: @index0 + } + CONSTANT [10] { value: 0 } + } + } + } + } + CALL [11] { + function: _==_ + args: { + IDENT [12] { + name: @index1 + } + CONSTANT [13] { value: 3 } + } + } + } +} +Test case: TERNARY_BIND_RHS_ONLY +Source: false ? false : (msg.single_int64) + ((msg.single_int64 + 1) * 2) == 11 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.single_int64 + } + CALL [5] { + function: _==_ + args: { + CALL [6] { + function: _+_ + args: { + IDENT [7] { + name: @index0 + } + CALL [8] { + function: _*_ + args: { + CALL [9] { + function: _+_ + args: { + IDENT [10] { + name: @index0 + } + CONSTANT [11] { value: 1 } + } + } + CONSTANT [12] { value: 2 } + } + } + } + } + CONSTANT [13] { value: 11 } + } + } + } + } + CALL [14] { + function: _?_:_ + args: { + CONSTANT [15] { value: false } + CONSTANT [16] { value: false } + IDENT [17] { + name: @index1 + } + } + } + } +} +Test case: NESTED_TERNARY +Source: (msg.single_int64 > 0 ? (msg.single_int32 > 0 ? msg.single_int64 + msg.single_int32 : 0) : 0) == 8 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.single_int64 + } + SELECT [5] { + IDENT [6] { + name: msg + }.single_int32 + } + CALL [7] { + function: _?_:_ + args: { + CALL [8] { + function: _>_ + args: { + IDENT [9] { + name: @index0 + } + CONSTANT [10] { value: 0 } + } + } + CALL [11] { + function: _?_:_ + args: { + CALL [12] { + function: _>_ + args: { + IDENT [13] { + name: @index1 + } + CONSTANT [14] { value: 0 } + } + } + CALL [15] { + function: _+_ + args: { + IDENT [16] { + name: @index0 + } + IDENT [17] { + name: @index1 + } + } + } + CONSTANT [18] { value: 0 } + } + } + CONSTANT [19] { value: 0 } + } + } + } + } + CALL [20] { + function: _==_ + args: { + IDENT [21] { + name: @index2 + } + CONSTANT [22] { value: 8 } + } + } + } +} +Test case: MULTIPLE_MACROS_1 +Source: size([[1].exists(i, i > 0)]) + size([[1].exists(j, j > 0)]) + size([[2].exists(k, k > 1)]) + size([[2].exists(l, l > 1)]) == 4 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + } + } + CALL [5] { + function: _>_ + args: { + IDENT [6] { + name: @c0:0 + } + CONSTANT [7] { value: 0 } + } + } + CALL [8] { + function: _||_ + args: { + IDENT [9] { + name: @x0:0 + } + IDENT [10] { + name: @index1 + } + } + } + COMPREHENSION [11] { + iter_var: @c0:0 + iter_range: { + IDENT [12] { + name: @index0 + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [13] { value: false } + } + loop_condition: { + CALL [14] { + function: @not_strictly_false + args: { + CALL [15] { + function: !_ + args: { + IDENT [16] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + IDENT [17] { + name: @index2 + } + } + result: { + IDENT [18] { + name: @x0:0 + } + } + } + CREATE_LIST [19] { + elements: { + IDENT [20] { + name: @index3 + } + } + } + CALL [21] { + function: size + args: { + IDENT [22] { + name: @index4 + } + } + } + CREATE_LIST [23] { + elements: { + CONSTANT [24] { value: 2 } + } + } + CALL [25] { + function: _>_ + args: { + IDENT [26] { + name: @c0:0 + } + CONSTANT [27] { value: 1 } + } + } + CALL [28] { + function: _||_ + args: { + IDENT [29] { + name: @x0:0 + } + IDENT [30] { + name: @index7 + } + } + } + COMPREHENSION [31] { + iter_var: @c0:0 + iter_range: { + IDENT [32] { + name: @index6 + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [33] { value: false } + } + loop_condition: { + CALL [34] { + function: @not_strictly_false + args: { + CALL [35] { + function: !_ + args: { + IDENT [36] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + IDENT [37] { + name: @index8 + } + } + result: { + IDENT [38] { + name: @x0:0 + } + } + } + CREATE_LIST [39] { + elements: { + IDENT [40] { + name: @index9 + } + } + } + CALL [41] { + function: size + args: { + IDENT [42] { + name: @index10 + } + } + } + CALL [43] { + function: _+_ + args: { + CALL [44] { + function: _+_ + args: { + CALL [45] { + function: _+_ + args: { + IDENT [46] { + name: @index5 + } + IDENT [47] { + name: @index5 + } + } + } + IDENT [48] { + name: @index11 + } + } + } + IDENT [49] { + name: @index11 + } + } + } + } + } + CALL [50] { + function: _==_ + args: { + IDENT [51] { + name: @index12 + } + CONSTANT [52] { value: 4 } + } + } + } +} +Test case: MULTIPLE_MACROS_2 +Source: [[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == 'a')] + [['a'].exists(l, l == 'a')] == [true, true, true, true] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + } + } + CALL [5] { + function: _>_ + args: { + IDENT [6] { + name: @c0:0 + } + CONSTANT [7] { value: 0 } + } + } + CALL [8] { + function: _||_ + args: { + IDENT [9] { + name: @x0:0 + } + IDENT [10] { + name: @index1 + } + } + } + COMPREHENSION [11] { + iter_var: @c0:0 + iter_range: { + IDENT [12] { + name: @index0 + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [13] { value: false } + } + loop_condition: { + CALL [14] { + function: @not_strictly_false + args: { + CALL [15] { + function: !_ + args: { + IDENT [16] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + IDENT [17] { + name: @index2 + } + } + result: { + IDENT [18] { + name: @x0:0 + } + } + } + CREATE_LIST [19] { + elements: { + IDENT [20] { + name: @index3 + } + } + } + CREATE_LIST [21] { + elements: { + CONSTANT [22] { value: "a" } + } + } + CALL [23] { + function: _==_ + args: { + IDENT [24] { + name: @c0:1 + } + CONSTANT [25] { value: "a" } + } + } + CALL [26] { + function: _||_ + args: { + IDENT [27] { + name: @x0:1 + } + IDENT [28] { + name: @index6 + } + } + } + COMPREHENSION [29] { + iter_var: @c0:1 + iter_range: { + IDENT [30] { + name: @index5 + } + } + accu_var: @x0:1 + accu_init: { + CONSTANT [31] { value: false } + } + loop_condition: { + CALL [32] { + function: @not_strictly_false + args: { + CALL [33] { + function: !_ + args: { + IDENT [34] { + name: @x0:1 + } + } + } + } + } + } + loop_step: { + IDENT [35] { + name: @index7 + } + } + result: { + IDENT [36] { + name: @x0:1 + } + } + } + CREATE_LIST [37] { + elements: { + IDENT [38] { + name: @index8 + } + } + } + CREATE_LIST [39] { + elements: { + CONSTANT [40] { value: true } + CONSTANT [41] { value: true } + CONSTANT [42] { value: true } + CONSTANT [43] { value: true } + } + } + CALL [44] { + function: _+_ + args: { + CALL [45] { + function: _+_ + args: { + CALL [46] { + function: _+_ + args: { + IDENT [47] { + name: @index4 + } + IDENT [48] { + name: @index4 + } + } + } + IDENT [49] { + name: @index9 + } + } + } + IDENT [50] { + name: @index9 + } + } + } + } + } + CALL [51] { + function: _==_ + args: { + IDENT [52] { + name: @index11 + } + IDENT [53] { + name: @index10 + } + } + } + } +} +Test case: NESTED_MACROS +Source: [1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [[2, 3, 4], [2, 3, 4], [2, 3, 4]] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + CONSTANT [6] { value: 3 } + } + } + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 2 } + CONSTANT [9] { value: 3 } + CONSTANT [10] { value: 4 } + } + } + CREATE_LIST [11] { + elements: { + IDENT [12] { + name: @index1 + } + IDENT [13] { + name: @index1 + } + IDENT [14] { + name: @index1 + } + } + } + COMPREHENSION [15] { + iter_var: @c1:0 + iter_range: { + IDENT [16] { + name: @index0 + } + } + accu_var: @x1:0 + accu_init: { + CREATE_LIST [17] { + elements: { + } + } + } + loop_condition: { + CONSTANT [18] { value: true } + } + loop_step: { + CALL [19] { + function: _+_ + args: { + IDENT [20] { + name: @x1:0 + } + CREATE_LIST [21] { + elements: { + CALL [22] { + function: _+_ + args: { + IDENT [23] { + name: @c1:0 + } + CONSTANT [24] { value: 1 } + } + } + } + } + } + } + } + result: { + IDENT [25] { + name: @x1:0 + } + } + } + COMPREHENSION [26] { + iter_var: @c0:0 + iter_range: { + IDENT [27] { + name: @index0 + } + } + accu_var: @x0:0 + accu_init: { + CREATE_LIST [28] { + elements: { + } + } + } + loop_condition: { + CONSTANT [29] { value: true } + } + loop_step: { + CALL [30] { + function: _+_ + args: { + IDENT [31] { + name: @x0:0 + } + CREATE_LIST [32] { + elements: { + IDENT [33] { + name: @index3 + } + } + } + } + } + } + result: { + IDENT [34] { + name: @x0:0 + } + } + } + } + } + CALL [35] { + function: _==_ + args: { + IDENT [36] { + name: @index4 + } + IDENT [37] { + name: @index2 + } + } + } + } +} +Test case: NESTED_MACROS_2 +Source: [1, 2].map(y, [1, 2, 3].filter(x, x == y)) == [[1], [2]] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CREATE_LIST [4] { + elements: { + CONSTANT [5] { value: 1 } + } + } + CREATE_LIST [6] { + elements: { + CONSTANT [7] { value: 2 } + } + } + } + } + COMPREHENSION [8] { + iter_var: @c1:0 + iter_range: { + CREATE_LIST [9] { + elements: { + CONSTANT [10] { value: 1 } + CONSTANT [11] { value: 2 } + CONSTANT [12] { value: 3 } + } + } + } + accu_var: @x1:0 + accu_init: { + CREATE_LIST [13] { + elements: { + } + } + } + loop_condition: { + CONSTANT [14] { value: true } + } + loop_step: { + CALL [15] { + function: _?_:_ + args: { + CALL [16] { + function: _==_ + args: { + IDENT [17] { + name: @c1:0 + } + IDENT [18] { + name: @c0:0 + } + } + } + CALL [19] { + function: _+_ + args: { + IDENT [20] { + name: @x1:0 + } + CREATE_LIST [21] { + elements: { + IDENT [22] { + name: @c1:0 + } + } + } + } + } + IDENT [23] { + name: @x1:0 + } + } + } + } + result: { + IDENT [24] { + name: @x1:0 + } + } + } + COMPREHENSION [25] { + iter_var: @c0:0 + iter_range: { + CREATE_LIST [26] { + elements: { + CONSTANT [27] { value: 1 } + CONSTANT [28] { value: 2 } + } + } + } + accu_var: @x0:0 + accu_init: { + CREATE_LIST [29] { + elements: { + } + } + } + loop_condition: { + CONSTANT [30] { value: true } + } + loop_step: { + CALL [31] { + function: _+_ + args: { + IDENT [32] { + name: @x0:0 + } + CREATE_LIST [33] { + elements: { + IDENT [34] { + name: @index1 + } + } + } + } + } + } + result: { + IDENT [35] { + name: @x0:0 + } + } + } + } + } + CALL [36] { + function: _==_ + args: { + IDENT [37] { + name: @index2 + } + IDENT [38] { + name: @index0 + } + } + } + } +} +Test case: INCLUSION_LIST +Source: 1 in [1,2,3] && 2 in [1,2,3] && 3 in [3, [1,2,3]] && 1 in [1,2,3] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + CONSTANT [6] { value: 3 } + } + } + CALL [7] { + function: @in + args: { + CONSTANT [8] { value: 1 } + IDENT [9] { + name: @index0 + } + } + } + CALL [10] { + function: _&&_ + args: { + CALL [11] { + function: @in + args: { + CONSTANT [12] { value: 3 } + CREATE_LIST [13] { + elements: { + CONSTANT [14] { value: 3 } + IDENT [15] { + name: @index0 + } + } + } + } + } + IDENT [16] { + name: @index1 + } + } + } + CALL [17] { + function: _&&_ + args: { + IDENT [18] { + name: @index1 + } + CALL [19] { + function: @in + args: { + CONSTANT [20] { value: 2 } + IDENT [21] { + name: @index0 + } + } + } + } + } + } + } + CALL [22] { + function: _&&_ + args: { + IDENT [23] { + name: @index3 + } + IDENT [24] { + name: @index2 + } + } + } + } +} +Test case: INCLUSION_MAP +Source: 2 in {'a': 1, 2: {true: false}, 3: {true: false}} +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: true } + } + value: { + CONSTANT [6] { value: false } + } + } + } + CREATE_MAP [7] { + MAP_ENTRY [8] { + key: { + CONSTANT [9] { value: "a" } + } + value: { + CONSTANT [10] { value: 1 } + } + } + MAP_ENTRY [11] { + key: { + CONSTANT [12] { value: 2 } + } + value: { + IDENT [13] { + name: @index0 + } + } + } + MAP_ENTRY [14] { + key: { + CONSTANT [15] { value: 3 } + } + value: { + IDENT [16] { + name: @index0 + } + } + } + } + } + } + CALL [17] { + function: @in + args: { + CONSTANT [18] { value: 2 } + IDENT [19] { + name: @index1 + } + } + } + } +} +Test case: MACRO_ITER_VAR_NOT_REFERENCED +Source: [1,2].map(i, [1, 2].map(i, [3,4])) == [[[3, 4], [3, 4]], [[3, 4], [3, 4]]] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + } + } + CREATE_LIST [6] { + elements: { + CONSTANT [7] { value: 3 } + CONSTANT [8] { value: 4 } + } + } + CREATE_LIST [9] { + elements: { + IDENT [10] { + name: @index1 + } + IDENT [11] { + name: @index1 + } + } + } + CREATE_LIST [12] { + elements: { + IDENT [13] { + name: @index2 + } + IDENT [14] { + name: @index2 + } + } + } + CREATE_LIST [15] { + elements: { + COMPREHENSION [16] { + iter_var: @c1:0 + iter_range: { + IDENT [17] { + name: @index0 + } + } + accu_var: @x1:0 + accu_init: { + CREATE_LIST [18] { + elements: { + } + } + } + loop_condition: { + CONSTANT [19] { value: true } + } + loop_step: { + CALL [20] { + function: _+_ + args: { + IDENT [21] { + name: @x1:0 + } + CREATE_LIST [22] { + elements: { + IDENT [23] { + name: @index1 + } + } + } + } + } + } + result: { + IDENT [24] { + name: @x1:0 + } + } + } + } + } + COMPREHENSION [25] { + iter_var: @c0:0 + iter_range: { + IDENT [26] { + name: @index0 + } + } + accu_var: @x0:0 + accu_init: { + CREATE_LIST [27] { + elements: { + } + } + } + loop_condition: { + CONSTANT [28] { value: true } + } + loop_step: { + CALL [29] { + function: _+_ + args: { + IDENT [30] { + name: @x0:0 + } + IDENT [31] { + name: @index4 + } + } + } + } + result: { + IDENT [32] { + name: @x0:0 + } + } + } + } + } + CALL [33] { + function: _==_ + args: { + IDENT [34] { + name: @index5 + } + IDENT [35] { + name: @index3 + } + } + } + } +} +Test case: MACRO_SHADOWED_VARIABLE +Source: [x - 1 > 3 ? x - 1 : 5].exists(x, x - 1 > 3) || x - 1 > 3 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _-_ + args: { + IDENT [4] { + name: x + } + CONSTANT [5] { value: 1 } + } + } + CALL [6] { + function: _>_ + args: { + IDENT [7] { + name: @index0 + } + CONSTANT [8] { value: 3 } + } + } + COMPREHENSION [9] { + iter_var: @c0:0 + iter_range: { + CREATE_LIST [10] { + elements: { + CALL [11] { + function: _?_:_ + args: { + IDENT [12] { + name: @index1 + } + IDENT [13] { + name: @index0 + } + CONSTANT [14] { value: 5 } + } + } + } + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [15] { value: false } + } + loop_condition: { + CALL [16] { + function: @not_strictly_false + args: { + CALL [17] { + function: !_ + args: { + IDENT [18] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + CALL [19] { + function: _||_ + args: { + IDENT [20] { + name: @x0:0 + } + CALL [21] { + function: _>_ + args: { + CALL [22] { + function: _-_ + args: { + IDENT [23] { + name: @c0:0 + } + CONSTANT [24] { value: 1 } + } + } + CONSTANT [25] { value: 3 } + } + } + } + } + } + result: { + IDENT [26] { + name: @x0:0 + } + } + } + } + } + CALL [27] { + function: _||_ + args: { + IDENT [28] { + name: @index2 + } + IDENT [29] { + name: @index1 + } + } + } + } +} +Test case: MACRO_SHADOWED_VARIABLE_2 +Source: ["foo", "bar"].map(x, [x + x, x + x]).map(x, [x + x, x + x]) +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _+_ + args: { + IDENT [4] { + name: @c1:0 + } + IDENT [5] { + name: @c1:0 + } + } + } + CALL [6] { + function: _+_ + args: { + IDENT [7] { + name: @c0:0 + } + IDENT [8] { + name: @c0:0 + } + } + } + CALL [9] { + function: _+_ + args: { + IDENT [10] { + name: @x0:0 + } + CREATE_LIST [11] { + elements: { + CREATE_LIST [12] { + elements: { + IDENT [13] { + name: @index1 + } + IDENT [14] { + name: @index1 + } + } + } + } + } + } + } + COMPREHENSION [15] { + iter_var: @c1:0 + iter_range: { + CREATE_LIST [16] { + elements: { + CONSTANT [17] { value: "foo" } + CONSTANT [18] { value: "bar" } + } + } + } + accu_var: @x1:0 + accu_init: { + CREATE_LIST [19] { + elements: { + } + } + } + loop_condition: { + CONSTANT [20] { value: true } + } + loop_step: { + CALL [21] { + function: _+_ + args: { + IDENT [22] { + name: @x1:0 + } + CREATE_LIST [23] { + elements: { + CREATE_LIST [24] { + elements: { + IDENT [25] { + name: @index0 + } + IDENT [26] { + name: @index0 + } + } + } + } + } + } + } + } + result: { + IDENT [27] { + name: @x1:0 + } + } + } + } + } + COMPREHENSION [28] { + iter_var: @c0:0 + iter_range: { + IDENT [29] { + name: @index3 + } + } + accu_var: @x0:0 + accu_init: { + CREATE_LIST [30] { + elements: { + } + } + } + loop_condition: { + CONSTANT [31] { value: true } + } + loop_step: { + IDENT [32] { + name: @index2 + } + } + result: { + IDENT [33] { + name: @x0:0 + } + } + } + } +} +Test case: PRESENCE_TEST +Source: has({'a': true}.a) && {'a':true}['a'] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: "a" } + } + value: { + CONSTANT [6] { value: true } + } + } + } + CALL [7] { + function: _[_] + args: { + IDENT [8] { + name: @index0 + } + CONSTANT [9] { value: "a" } + } + } + } + } + CALL [10] { + function: _&&_ + args: { + SELECT [11] { + IDENT [12] { + name: @index0 + }.a~presence_test + } + IDENT [13] { + name: @index1 + } + } + } + } +} +Test case: PRESENCE_TEST_WITH_TERNARY +Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : 0) == 10 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + CALL [5] { + function: _?_:_ + args: { + SELECT [6] { + IDENT [7] { + name: @index0 + }.payload~presence_test + } + SELECT [8] { + SELECT [9] { + IDENT [10] { + name: @index0 + }.payload + }.single_int64 + } + CONSTANT [11] { value: 0 } + } + } + } + } + CALL [12] { + function: _==_ + args: { + IDENT [13] { + name: @index1 + } + CONSTANT [14] { value: 10 } + } + } + } +} +Test case: PRESENCE_TEST_WITH_TERNARY_2 +Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : msg.oneof_type.payload.single_int64 * 0) == 10 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.single_int64 + } + CALL [9] { + function: _?_:_ + args: { + SELECT [10] { + IDENT [11] { + name: @index0 + }.payload~presence_test + } + IDENT [12] { + name: @index2 + } + CALL [13] { + function: _*_ + args: { + IDENT [14] { + name: @index2 + } + CONSTANT [15] { value: 0 } + } + } + } + } + } + } + CALL [16] { + function: _==_ + args: { + IDENT [17] { + name: @index3 + } + CONSTANT [18] { value: 10 } + } + } + } +} +Test case: PRESENCE_TEST_WITH_TERNARY_3 +Source: (has(msg.oneof_type.payload.single_int64) ? msg.oneof_type.payload.single_int64 : msg.oneof_type.payload.single_int64 * 0) == 10 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.single_int64 + } + CALL [9] { + function: _?_:_ + args: { + SELECT [10] { + IDENT [11] { + name: @index1 + }.single_int64~presence_test + } + IDENT [12] { + name: @index2 + } + CALL [13] { + function: _*_ + args: { + IDENT [14] { + name: @index2 + } + CONSTANT [15] { value: 0 } + } + } + } + } + } + } + CALL [16] { + function: _==_ + args: { + IDENT [17] { + name: @index3 + } + CONSTANT [18] { value: 10 } + } + } + } +} +Test case: PRESENCE_TEST_WITH_TERNARY_NESTED +Source: (has(msg.oneof_type) && has(msg.oneof_type.payload) && has(msg.oneof_type.payload.single_int64)) ? ((has(msg.oneof_type.payload.map_string_string) && has(msg.oneof_type.payload.map_string_string.key)) ? msg.oneof_type.payload.map_string_string.key == 'A' : false) : false +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.map_string_string + } + CALL [9] { + function: _?_:_ + args: { + CALL [10] { + function: _&&_ + args: { + SELECT [11] { + IDENT [12] { + name: @index1 + }.map_string_string~presence_test + } + SELECT [13] { + IDENT [14] { + name: @index2 + }.key~presence_test + } + } + } + CALL [15] { + function: _==_ + args: { + SELECT [16] { + IDENT [17] { + name: @index2 + }.key + } + CONSTANT [18] { value: "A" } + } + } + CONSTANT [19] { value: false } + } + } + CALL [20] { + function: _&&_ + args: { + CALL [21] { + function: _&&_ + args: { + SELECT [22] { + IDENT [23] { + name: msg + }.oneof_type~presence_test + } + SELECT [24] { + IDENT [25] { + name: @index0 + }.payload~presence_test + } + } + } + SELECT [26] { + IDENT [27] { + name: @index1 + }.single_int64~presence_test + } + } + } + } + } + CALL [28] { + function: _?_:_ + args: { + IDENT [29] { + name: @index4 + } + IDENT [30] { + name: @index3 + } + CONSTANT [31] { value: false } + } + } + } +} +Test case: OPTIONAL_LIST +Source: [10, ?optional.none(), [?optional.none(), ?opt_x], [?optional.none(), ?opt_x]] == [10, [5], [5]] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: optional.none + args: { + } + } + CREATE_LIST [4] { + elements: { + IDENT [5] { + name: @index0 + } + IDENT [6] { + name: opt_x + } + } + optional_indices: [0, 1] + } + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 5 } + } + } + CREATE_LIST [9] { + elements: { + CONSTANT [10] { value: 10 } + IDENT [11] { + name: @index2 + } + IDENT [12] { + name: @index2 + } + } + } + CREATE_LIST [13] { + elements: { + CONSTANT [14] { value: 10 } + IDENT [15] { + name: @index0 + } + IDENT [16] { + name: @index1 + } + IDENT [17] { + name: @index1 + } + } + optional_indices: [0] + } + } + } + CALL [18] { + function: _==_ + args: { + IDENT [19] { + name: @index4 + } + IDENT [20] { + name: @index3 + } + } + } + } +} +Test case: OPTIONAL_MAP +Source: {?'hello': optional.of('hello')}['hello'] + {?'hello': optional.of('hello')}['hello'] == 'hellohello' +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: optional.of + args: { + CONSTANT [4] { value: "hello" } + } + } + CREATE_MAP [5] { + MAP_ENTRY [6] { + key: { + CONSTANT [7] { value: "hello" } + } + optional_entry: true + value: { + IDENT [8] { + name: @index0 + } + } + } + } + CALL [9] { + function: _[_] + args: { + IDENT [10] { + name: @index1 + } + CONSTANT [11] { value: "hello" } + } + } + CALL [12] { + function: _+_ + args: { + IDENT [13] { + name: @index2 + } + IDENT [14] { + name: @index2 + } + } + } + } + } + CALL [15] { + function: _==_ + args: { + IDENT [16] { + name: @index3 + } + CONSTANT [17] { value: "hellohello" } + } + } + } +} +Test case: OPTIONAL_MAP_CHAINED +Source: {?'key': optional.of('test')}[?'bogus'].or({'key': 'test'}[?'bogus']).orValue({'key': 'test'}['key']) == 'test' +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: "key" } + } + value: { + CONSTANT [6] { value: "test" } + } + } + } + CALL [7] { + function: _[_] + args: { + IDENT [8] { + name: @index0 + } + CONSTANT [9] { value: "key" } + } + } + CALL [10] { + function: or + target: { + CALL [11] { + function: _[?_] + args: { + CREATE_MAP [12] { + MAP_ENTRY [13] { + key: { + CONSTANT [14] { value: "key" } + } + optional_entry: true + value: { + CALL [15] { + function: optional.of + args: { + CONSTANT [16] { value: "test" } + } + } + } + } + } + CONSTANT [17] { value: "bogus" } + } + } + } + args: { + CALL [18] { + function: _[?_] + args: { + IDENT [19] { + name: @index0 + } + CONSTANT [20] { value: "bogus" } + } + } + } + } + CALL [21] { + function: orValue + target: { + IDENT [22] { + name: @index2 + } + } + args: { + IDENT [23] { + name: @index1 + } + } + } + } + } + CALL [24] { + function: _==_ + args: { + IDENT [25] { + name: @index3 + } + CONSTANT [26] { value: "test" } + } + } + } +} +Test case: OPTIONAL_MESSAGE +Source: TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}.single_int32 + TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}.single_int64 == 5 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: optional.ofNonZeroValue + args: { + CONSTANT [4] { value: 1 } + } + } + CALL [5] { + function: optional.of + args: { + CONSTANT [6] { value: 4 } + } + } + CREATE_STRUCT [7] { + name: TestAllTypes + entries: { + ENTRY [8] { + field_key: single_int64 + optional_entry: true + value: { + IDENT [9] { + name: @index0 + } + } + } + ENTRY [10] { + field_key: single_int32 + optional_entry: true + value: { + IDENT [11] { + name: @index1 + } + } + } + } + } + CALL [12] { + function: _+_ + args: { + SELECT [13] { + IDENT [14] { + name: @index2 + }.single_int32 + } + SELECT [15] { + IDENT [16] { + name: @index2 + }.single_int64 + } + } + } + } + } + CALL [17] { + function: _==_ + args: { + IDENT [18] { + name: @index3 + } + CONSTANT [19] { value: 5 } + } + } + } +} +Test case: CALL +Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('h' + 'e' + 'l' + 'l' + 'o') +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _+_ + args: { + CONSTANT [4] { value: "h" } + CONSTANT [5] { value: "e" } + } + } + CALL [6] { + function: _+_ + args: { + IDENT [7] { + name: @index0 + } + CONSTANT [8] { value: "l" } + } + } + CALL [9] { + function: _+_ + args: { + IDENT [10] { + name: @index1 + } + CONSTANT [11] { value: "l" } + } + } + CALL [12] { + function: _+_ + args: { + IDENT [13] { + name: @index2 + } + CONSTANT [14] { value: "o" } + } + } + CALL [15] { + function: _+_ + args: { + IDENT [16] { + name: @index3 + } + CONSTANT [17] { value: " world" } + } + } + } + } + CALL [18] { + function: matches + target: { + IDENT [19] { + name: @index4 + } + } + args: { + IDENT [20] { + name: @index3 + } + } + } + } +} +Test case: CALL_ARGUMENT_NESTED_NO_COMMON_SUBEXPR +Source: 'hello world'.matches('h' + 'e' + 'l' + 'l' + 'o') +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _+_ + args: { + CALL [4] { + function: _+_ + args: { + CALL [5] { + function: _+_ + args: { + CALL [6] { + function: _+_ + args: { + CONSTANT [7] { value: "h" } + CONSTANT [8] { value: "e" } + } + } + CONSTANT [9] { value: "l" } + } + } + CONSTANT [10] { value: "l" } + } + } + CONSTANT [11] { value: "o" } + } + } + } + } + CALL [12] { + function: matches + target: { + CONSTANT [13] { value: "hello world" } + } + args: { + IDENT [14] { + name: @index0 + } + } + } + } +} +Test case: CALL_TARGET_NESTED_NO_COMMON_SUBEXPR +Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('hello') +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _+_ + args: { + CALL [4] { + function: _+_ + args: { + CALL [5] { + function: _+_ + args: { + CALL [6] { + function: _+_ + args: { + CONSTANT [7] { value: "h" } + CONSTANT [8] { value: "e" } + } + } + CONSTANT [9] { value: "l" } + } + } + CONSTANT [10] { value: "l" } + } + } + CONSTANT [11] { value: "o" } + } + } + CALL [12] { + function: _+_ + args: { + IDENT [13] { + name: @index0 + } + CONSTANT [14] { value: " world" } + } + } + } + } + CALL [15] { + function: matches + target: { + IDENT [16] { + name: @index1 + } + } + args: { + CONSTANT [17] { value: "hello" } + } + } + } +} +Test case: CALL_BOTH_ARGUMENT_TARGET_NESTED_NO_COMMON_SUBEXPR +Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('w' + 'o' + 'r' + 'l' + 'd') +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _+_ + args: { + CALL [4] { + function: _+_ + args: { + CALL [5] { + function: _+_ + args: { + CALL [6] { + function: _+_ + args: { + CONSTANT [7] { value: "w" } + CONSTANT [8] { value: "o" } + } + } + CONSTANT [9] { value: "r" } + } + } + CONSTANT [10] { value: "l" } + } + } + CONSTANT [11] { value: "d" } + } + } + CALL [12] { + function: _+_ + args: { + CALL [13] { + function: _+_ + args: { + CALL [14] { + function: _+_ + args: { + CALL [15] { + function: _+_ + args: { + CONSTANT [16] { value: "h" } + CONSTANT [17] { value: "e" } + } + } + CONSTANT [18] { value: "l" } + } + } + CONSTANT [19] { value: "l" } + } + } + CONSTANT [20] { value: "o" } + } + } + CALL [21] { + function: _+_ + args: { + IDENT [22] { + name: @index1 + } + CONSTANT [23] { value: " world" } + } + } + } + } + CALL [24] { + function: matches + target: { + IDENT [25] { + name: @index2 + } + } + args: { + IDENT [26] { + name: @index0 + } + } + } + } +} diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_5.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_5.baseline new file mode 100644 index 000000000..092b22477 --- /dev/null +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_5.baseline @@ -0,0 +1,3299 @@ +Test case: SIZE_1 +Source: size([1,2]) + size([1,2]) + 1 == 5 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + } + } + CALL [6] { + function: size + args: { + IDENT [7] { + name: @index0 + } + } + } + CALL [8] { + function: _+_ + args: { + CALL [9] { + function: _+_ + args: { + IDENT [10] { + name: @index1 + } + IDENT [11] { + name: @index1 + } + } + } + CONSTANT [12] { value: 1 } + } + } + } + } + CALL [13] { + function: _==_ + args: { + IDENT [14] { + name: @index2 + } + CONSTANT [15] { value: 5 } + } + } + } +} +Test case: SIZE_2 +Source: 2 + size([1,2]) + size([1,2]) + 1 == 7 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + } + } + CALL [6] { + function: size + args: { + IDENT [7] { + name: @index0 + } + } + } + CALL [8] { + function: _+_ + args: { + CALL [9] { + function: _+_ + args: { + CALL [10] { + function: _+_ + args: { + CONSTANT [11] { value: 2 } + IDENT [12] { + name: @index1 + } + } + } + IDENT [13] { + name: @index1 + } + } + } + CONSTANT [14] { value: 1 } + } + } + } + } + CALL [15] { + function: _==_ + args: { + IDENT [16] { + name: @index2 + } + CONSTANT [17] { value: 7 } + } + } + } +} +Test case: SIZE_3 +Source: size([0]) + size([0]) + size([1,2]) + size([1,2]) == 6 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 0 } + } + } + CALL [5] { + function: size + args: { + IDENT [6] { + name: @index0 + } + } + } + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 1 } + CONSTANT [9] { value: 2 } + } + } + CALL [10] { + function: size + args: { + IDENT [11] { + name: @index2 + } + } + } + CALL [12] { + function: _+_ + args: { + CALL [13] { + function: _+_ + args: { + CALL [14] { + function: _+_ + args: { + IDENT [15] { + name: @index1 + } + IDENT [16] { + name: @index1 + } + } + } + IDENT [17] { + name: @index3 + } + } + } + IDENT [18] { + name: @index3 + } + } + } + } + } + CALL [19] { + function: _==_ + args: { + IDENT [20] { + name: @index4 + } + CONSTANT [21] { value: 6 } + } + } + } +} +Test case: SIZE_4 +Source: 5 + size([0]) + size([0]) + size([1,2]) + size([1,2]) + size([1,2,3]) + size([1,2,3]) == 17 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 0 } + } + } + CALL [5] { + function: size + args: { + IDENT [6] { + name: @index0 + } + } + } + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 1 } + CONSTANT [9] { value: 2 } + } + } + CALL [10] { + function: size + args: { + IDENT [11] { + name: @index2 + } + } + } + CREATE_LIST [12] { + elements: { + CONSTANT [13] { value: 1 } + CONSTANT [14] { value: 2 } + CONSTANT [15] { value: 3 } + } + } + CALL [16] { + function: size + args: { + IDENT [17] { + name: @index4 + } + } + } + CALL [18] { + function: _+_ + args: { + CALL [19] { + function: _+_ + args: { + CALL [20] { + function: _+_ + args: { + CALL [21] { + function: _+_ + args: { + CALL [22] { + function: _+_ + args: { + CONSTANT [23] { value: 5 } + IDENT [24] { + name: @index1 + } + } + } + IDENT [25] { + name: @index1 + } + } + } + IDENT [26] { + name: @index3 + } + } + } + IDENT [27] { + name: @index3 + } + } + } + IDENT [28] { + name: @index5 + } + } + } + CALL [29] { + function: _+_ + args: { + IDENT [30] { + name: @index6 + } + IDENT [31] { + name: @index5 + } + } + } + } + } + CALL [32] { + function: _==_ + args: { + IDENT [33] { + name: @index7 + } + CONSTANT [34] { value: 17 } + } + } + } +} +Test case: TIMESTAMP +Source: timestamp(int(timestamp(1000000000))).getFullYear() + timestamp(int(timestamp(75))).getFullYear() + timestamp(int(timestamp(50))).getFullYear() + timestamp(int(timestamp(1000000000))).getFullYear() + timestamp(int(timestamp(50))).getSeconds() + timestamp(int(timestamp(200))).getFullYear() + timestamp(int(timestamp(200))).getFullYear() + timestamp(int(timestamp(75))).getMinutes() + timestamp(int(timestamp(1000000000))).getFullYear() == 13934 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: timestamp + args: { + CONSTANT [4] { value: 1000000000 } + } + } + CALL [5] { + function: int + args: { + IDENT [6] { + name: @index0 + } + } + } + CALL [7] { + function: timestamp + args: { + IDENT [8] { + name: @index1 + } + } + } + CALL [9] { + function: getFullYear + target: { + IDENT [10] { + name: @index2 + } + } + args: { + } + } + CALL [11] { + function: timestamp + args: { + CONSTANT [12] { value: 50 } + } + } + CALL [13] { + function: int + args: { + IDENT [14] { + name: @index4 + } + } + } + CALL [15] { + function: timestamp + args: { + IDENT [16] { + name: @index5 + } + } + } + CALL [17] { + function: timestamp + args: { + CONSTANT [18] { value: 200 } + } + } + CALL [19] { + function: int + args: { + IDENT [20] { + name: @index7 + } + } + } + CALL [21] { + function: timestamp + args: { + IDENT [22] { + name: @index8 + } + } + } + CALL [23] { + function: getFullYear + target: { + IDENT [24] { + name: @index9 + } + } + args: { + } + } + CALL [25] { + function: timestamp + args: { + CONSTANT [26] { value: 75 } + } + } + CALL [27] { + function: int + args: { + IDENT [28] { + name: @index11 + } + } + } + CALL [29] { + function: timestamp + args: { + IDENT [30] { + name: @index12 + } + } + } + CALL [31] { + function: getMinutes + target: { + IDENT [32] { + name: @index13 + } + } + args: { + } + } + CALL [33] { + function: _+_ + args: { + CALL [34] { + function: _+_ + args: { + CALL [35] { + function: _+_ + args: { + CALL [36] { + function: _+_ + args: { + IDENT [37] { + name: @index3 + } + CALL [38] { + function: getFullYear + target: { + IDENT [39] { + name: @index13 + } + } + args: { + } + } + } + } + CALL [40] { + function: getFullYear + target: { + IDENT [41] { + name: @index6 + } + } + args: { + } + } + } + } + IDENT [42] { + name: @index3 + } + } + } + CALL [43] { + function: getSeconds + target: { + IDENT [44] { + name: @index6 + } + } + args: { + } + } + } + } + CALL [45] { + function: _+_ + args: { + CALL [46] { + function: _+_ + args: { + CALL [47] { + function: _+_ + args: { + CALL [48] { + function: _+_ + args: { + IDENT [49] { + name: @index15 + } + IDENT [50] { + name: @index10 + } + } + } + IDENT [51] { + name: @index10 + } + } + } + IDENT [52] { + name: @index14 + } + } + } + IDENT [53] { + name: @index3 + } + } + } + } + } + CALL [54] { + function: _==_ + args: { + IDENT [55] { + name: @index16 + } + CONSTANT [56] { value: 13934 } + } + } + } +} +Test case: MAP_INDEX +Source: {"a": 2}["a"] + {"a": 2}["a"] * {"a": 2}["a"] == 6 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: "a" } + } + value: { + CONSTANT [6] { value: 2 } + } + } + } + CALL [7] { + function: _[_] + args: { + IDENT [8] { + name: @index0 + } + CONSTANT [9] { value: "a" } + } + } + CALL [10] { + function: _+_ + args: { + IDENT [11] { + name: @index1 + } + CALL [12] { + function: _*_ + args: { + IDENT [13] { + name: @index1 + } + IDENT [14] { + name: @index1 + } + } + } + } + } + } + } + CALL [15] { + function: _==_ + args: { + IDENT [16] { + name: @index2 + } + CONSTANT [17] { value: 6 } + } + } + } +} +Test case: NESTED_MAP_CONSTRUCTION +Source: {'a': {'b': 1}, 'c': {'b': 1}, 'd': {'e': {'b': 1}}, 'e': {'e': {'b': 1}}} +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: "b" } + } + value: { + CONSTANT [6] { value: 1 } + } + } + } + CREATE_MAP [7] { + MAP_ENTRY [8] { + key: { + CONSTANT [9] { value: "e" } + } + value: { + IDENT [10] { + name: @index0 + } + } + } + } + } + } + CREATE_MAP [11] { + MAP_ENTRY [12] { + key: { + CONSTANT [13] { value: "a" } + } + value: { + IDENT [14] { + name: @index0 + } + } + } + MAP_ENTRY [15] { + key: { + CONSTANT [16] { value: "c" } + } + value: { + IDENT [17] { + name: @index0 + } + } + } + MAP_ENTRY [18] { + key: { + CONSTANT [19] { value: "d" } + } + value: { + IDENT [20] { + name: @index1 + } + } + } + MAP_ENTRY [21] { + key: { + CONSTANT [22] { value: "e" } + } + value: { + IDENT [23] { + name: @index1 + } + } + } + } + } +} +Test case: NESTED_LIST_CONSTRUCTION +Source: [1, [1,2,3,4], 2, [1,2,3,4], 5, [1,2,3,4], 7, [[1,2], [1,2,3,4]], [1,2]] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + CONSTANT [6] { value: 3 } + CONSTANT [7] { value: 4 } + } + } + CREATE_LIST [8] { + elements: { + CONSTANT [9] { value: 1 } + CONSTANT [10] { value: 2 } + } + } + CREATE_LIST [11] { + elements: { + IDENT [12] { + name: @index1 + } + IDENT [13] { + name: @index0 + } + } + } + } + } + CREATE_LIST [14] { + elements: { + CONSTANT [15] { value: 1 } + IDENT [16] { + name: @index0 + } + CONSTANT [17] { value: 2 } + IDENT [18] { + name: @index0 + } + CONSTANT [19] { value: 5 } + IDENT [20] { + name: @index0 + } + CONSTANT [21] { value: 7 } + IDENT [22] { + name: @index2 + } + IDENT [23] { + name: @index1 + } + } + } + } +} +Test case: SELECT +Source: msg.single_int64 + msg.single_int64 == 6 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.single_int64 + } + CALL [5] { + function: _+_ + args: { + IDENT [6] { + name: @index0 + } + IDENT [7] { + name: @index0 + } + } + } + } + } + CALL [8] { + function: _==_ + args: { + IDENT [9] { + name: @index1 + } + CONSTANT [10] { value: 6 } + } + } + } +} +Test case: SELECT_NESTED_1 +Source: msg.oneof_type.payload.single_int64 + msg.oneof_type.payload.single_int32 + msg.oneof_type.payload.single_int64 + msg.single_int64 + msg.oneof_type.payload.oneof_type.payload.single_int64 == 31 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.single_int64 + } + CALL [9] { + function: _+_ + args: { + CALL [10] { + function: _+_ + args: { + CALL [11] { + function: _+_ + args: { + CALL [12] { + function: _+_ + args: { + IDENT [13] { + name: @index2 + } + SELECT [14] { + IDENT [15] { + name: @index1 + }.single_int32 + } + } + } + IDENT [16] { + name: @index2 + } + } + } + SELECT [17] { + IDENT [18] { + name: msg + }.single_int64 + } + } + } + SELECT [19] { + SELECT [20] { + SELECT [21] { + IDENT [22] { + name: @index1 + }.oneof_type + }.payload + }.single_int64 + } + } + } + } + } + CALL [23] { + function: _==_ + args: { + IDENT [24] { + name: @index3 + } + CONSTANT [25] { value: 31 } + } + } + } +} +Test case: SELECT_NESTED_2 +Source: true || msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload.single_bool || msg.oneof_type.payload.oneof_type.payload.oneof_type.child.child.payload.single_bool +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.oneof_type + } + SELECT [9] { + IDENT [10] { + name: @index2 + }.payload + } + SELECT [11] { + IDENT [12] { + name: @index3 + }.oneof_type + } + SELECT [13] { + SELECT [14] { + SELECT [15] { + SELECT [16] { + IDENT [17] { + name: @index4 + }.child + }.child + }.payload + }.single_bool + } + CALL [18] { + function: _||_ + args: { + CONSTANT [19] { value: true } + SELECT [20] { + SELECT [21] { + SELECT [22] { + SELECT [23] { + IDENT [24] { + name: @index4 + }.payload + }.oneof_type + }.payload + }.single_bool + } + } + } + } + } + CALL [25] { + function: _||_ + args: { + IDENT [26] { + name: @index6 + } + IDENT [27] { + name: @index5 + } + } + } + } +} +Test case: SELECT_NESTED_MESSAGE_MAP_INDEX_1 +Source: msg.oneof_type.payload.map_int32_int64[1] + msg.oneof_type.payload.map_int32_int64[1] + msg.oneof_type.payload.map_int32_int64[1] == 15 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.map_int32_int64 + } + CALL [9] { + function: _[_] + args: { + IDENT [10] { + name: @index2 + } + CONSTANT [11] { value: 1 } + } + } + CALL [12] { + function: _+_ + args: { + CALL [13] { + function: _+_ + args: { + IDENT [14] { + name: @index3 + } + IDENT [15] { + name: @index3 + } + } + } + IDENT [16] { + name: @index3 + } + } + } + } + } + CALL [17] { + function: _==_ + args: { + IDENT [18] { + name: @index4 + } + CONSTANT [19] { value: 15 } + } + } + } +} +Test case: SELECT_NESTED_MESSAGE_MAP_INDEX_2 +Source: msg.oneof_type.payload.map_int32_int64[0] + msg.oneof_type.payload.map_int32_int64[1] + msg.oneof_type.payload.map_int32_int64[2] == 8 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.map_int32_int64 + } + CALL [9] { + function: _+_ + args: { + CALL [10] { + function: _+_ + args: { + CALL [11] { + function: _[_] + args: { + IDENT [12] { + name: @index2 + } + CONSTANT [13] { value: 0 } + } + } + CALL [14] { + function: _[_] + args: { + IDENT [15] { + name: @index2 + } + CONSTANT [16] { value: 1 } + } + } + } + } + CALL [17] { + function: _[_] + args: { + IDENT [18] { + name: @index2 + } + CONSTANT [19] { value: 2 } + } + } + } + } + } + } + CALL [20] { + function: _==_ + args: { + IDENT [21] { + name: @index3 + } + CONSTANT [22] { value: 8 } + } + } + } +} +Test case: SELECT_NESTED_NO_COMMON_SUBEXPR +Source: msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload.single_int64 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + SELECT [4] { + SELECT [5] { + SELECT [6] { + SELECT [7] { + IDENT [8] { + name: msg + }.oneof_type + }.payload + }.oneof_type + }.payload + }.oneof_type + } + SELECT [9] { + SELECT [10] { + SELECT [11] { + IDENT [12] { + name: @index0 + }.payload + }.oneof_type + }.payload + } + } + } + SELECT [13] { + IDENT [14] { + name: @index1 + }.single_int64 + } + } +} +Test case: TERNARY +Source: (msg.single_int64 > 0 ? msg.single_int64 : 0) == 3 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.single_int64 + } + CALL [5] { + function: _?_:_ + args: { + CALL [6] { + function: _>_ + args: { + IDENT [7] { + name: @index0 + } + CONSTANT [8] { value: 0 } + } + } + IDENT [9] { + name: @index0 + } + CONSTANT [10] { value: 0 } + } + } + } + } + CALL [11] { + function: _==_ + args: { + IDENT [12] { + name: @index1 + } + CONSTANT [13] { value: 3 } + } + } + } +} +Test case: TERNARY_BIND_RHS_ONLY +Source: false ? false : (msg.single_int64) + ((msg.single_int64 + 1) * 2) == 11 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.single_int64 + } + CALL [5] { + function: _==_ + args: { + CALL [6] { + function: _+_ + args: { + IDENT [7] { + name: @index0 + } + CALL [8] { + function: _*_ + args: { + CALL [9] { + function: _+_ + args: { + IDENT [10] { + name: @index0 + } + CONSTANT [11] { value: 1 } + } + } + CONSTANT [12] { value: 2 } + } + } + } + } + CONSTANT [13] { value: 11 } + } + } + } + } + CALL [14] { + function: _?_:_ + args: { + CONSTANT [15] { value: false } + CONSTANT [16] { value: false } + IDENT [17] { + name: @index1 + } + } + } + } +} +Test case: NESTED_TERNARY +Source: (msg.single_int64 > 0 ? (msg.single_int32 > 0 ? msg.single_int64 + msg.single_int32 : 0) : 0) == 8 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.single_int64 + } + SELECT [5] { + IDENT [6] { + name: msg + }.single_int32 + } + CALL [7] { + function: _?_:_ + args: { + CALL [8] { + function: _>_ + args: { + IDENT [9] { + name: @index0 + } + CONSTANT [10] { value: 0 } + } + } + CALL [11] { + function: _?_:_ + args: { + CALL [12] { + function: _>_ + args: { + IDENT [13] { + name: @index1 + } + CONSTANT [14] { value: 0 } + } + } + CALL [15] { + function: _+_ + args: { + IDENT [16] { + name: @index0 + } + IDENT [17] { + name: @index1 + } + } + } + CONSTANT [18] { value: 0 } + } + } + CONSTANT [19] { value: 0 } + } + } + } + } + CALL [20] { + function: _==_ + args: { + IDENT [21] { + name: @index2 + } + CONSTANT [22] { value: 8 } + } + } + } +} +Test case: MULTIPLE_MACROS_1 +Source: size([[1].exists(i, i > 0)]) + size([[1].exists(j, j > 0)]) + size([[2].exists(k, k > 1)]) + size([[2].exists(l, l > 1)]) == 4 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + } + } + CALL [5] { + function: _>_ + args: { + IDENT [6] { + name: @c0:0 + } + CONSTANT [7] { value: 0 } + } + } + CALL [8] { + function: _||_ + args: { + IDENT [9] { + name: @x0:0 + } + IDENT [10] { + name: @index1 + } + } + } + COMPREHENSION [11] { + iter_var: @c0:0 + iter_range: { + IDENT [12] { + name: @index0 + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [13] { value: false } + } + loop_condition: { + CALL [14] { + function: @not_strictly_false + args: { + CALL [15] { + function: !_ + args: { + IDENT [16] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + IDENT [17] { + name: @index2 + } + } + result: { + IDENT [18] { + name: @x0:0 + } + } + } + CREATE_LIST [19] { + elements: { + IDENT [20] { + name: @index3 + } + } + } + CALL [21] { + function: size + args: { + IDENT [22] { + name: @index4 + } + } + } + CREATE_LIST [23] { + elements: { + CONSTANT [24] { value: 2 } + } + } + CALL [25] { + function: _>_ + args: { + IDENT [26] { + name: @c0:0 + } + CONSTANT [27] { value: 1 } + } + } + CALL [28] { + function: _||_ + args: { + IDENT [29] { + name: @x0:0 + } + IDENT [30] { + name: @index7 + } + } + } + COMPREHENSION [31] { + iter_var: @c0:0 + iter_range: { + IDENT [32] { + name: @index6 + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [33] { value: false } + } + loop_condition: { + CALL [34] { + function: @not_strictly_false + args: { + CALL [35] { + function: !_ + args: { + IDENT [36] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + IDENT [37] { + name: @index8 + } + } + result: { + IDENT [38] { + name: @x0:0 + } + } + } + CREATE_LIST [39] { + elements: { + IDENT [40] { + name: @index9 + } + } + } + CALL [41] { + function: size + args: { + IDENT [42] { + name: @index10 + } + } + } + CALL [43] { + function: _+_ + args: { + CALL [44] { + function: _+_ + args: { + CALL [45] { + function: _+_ + args: { + IDENT [46] { + name: @index5 + } + IDENT [47] { + name: @index5 + } + } + } + IDENT [48] { + name: @index11 + } + } + } + IDENT [49] { + name: @index11 + } + } + } + } + } + CALL [50] { + function: _==_ + args: { + IDENT [51] { + name: @index12 + } + CONSTANT [52] { value: 4 } + } + } + } +} +Test case: MULTIPLE_MACROS_2 +Source: [[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == 'a')] + [['a'].exists(l, l == 'a')] == [true, true, true, true] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + } + } + CALL [5] { + function: _>_ + args: { + IDENT [6] { + name: @c0:0 + } + CONSTANT [7] { value: 0 } + } + } + CALL [8] { + function: _||_ + args: { + IDENT [9] { + name: @x0:0 + } + IDENT [10] { + name: @index1 + } + } + } + COMPREHENSION [11] { + iter_var: @c0:0 + iter_range: { + IDENT [12] { + name: @index0 + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [13] { value: false } + } + loop_condition: { + CALL [14] { + function: @not_strictly_false + args: { + CALL [15] { + function: !_ + args: { + IDENT [16] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + IDENT [17] { + name: @index2 + } + } + result: { + IDENT [18] { + name: @x0:0 + } + } + } + CREATE_LIST [19] { + elements: { + IDENT [20] { + name: @index3 + } + } + } + CREATE_LIST [21] { + elements: { + CONSTANT [22] { value: "a" } + } + } + CALL [23] { + function: _==_ + args: { + IDENT [24] { + name: @c0:1 + } + CONSTANT [25] { value: "a" } + } + } + CALL [26] { + function: _||_ + args: { + IDENT [27] { + name: @x0:1 + } + IDENT [28] { + name: @index6 + } + } + } + COMPREHENSION [29] { + iter_var: @c0:1 + iter_range: { + IDENT [30] { + name: @index5 + } + } + accu_var: @x0:1 + accu_init: { + CONSTANT [31] { value: false } + } + loop_condition: { + CALL [32] { + function: @not_strictly_false + args: { + CALL [33] { + function: !_ + args: { + IDENT [34] { + name: @x0:1 + } + } + } + } + } + } + loop_step: { + IDENT [35] { + name: @index7 + } + } + result: { + IDENT [36] { + name: @x0:1 + } + } + } + CREATE_LIST [37] { + elements: { + IDENT [38] { + name: @index8 + } + } + } + CREATE_LIST [39] { + elements: { + CONSTANT [40] { value: true } + CONSTANT [41] { value: true } + CONSTANT [42] { value: true } + CONSTANT [43] { value: true } + } + } + CALL [44] { + function: _+_ + args: { + CALL [45] { + function: _+_ + args: { + CALL [46] { + function: _+_ + args: { + IDENT [47] { + name: @index4 + } + IDENT [48] { + name: @index4 + } + } + } + IDENT [49] { + name: @index9 + } + } + } + IDENT [50] { + name: @index9 + } + } + } + } + } + CALL [51] { + function: _==_ + args: { + IDENT [52] { + name: @index11 + } + IDENT [53] { + name: @index10 + } + } + } + } +} +Test case: NESTED_MACROS +Source: [1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [[2, 3, 4], [2, 3, 4], [2, 3, 4]] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + CONSTANT [6] { value: 3 } + } + } + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 2 } + CONSTANT [9] { value: 3 } + CONSTANT [10] { value: 4 } + } + } + CREATE_LIST [11] { + elements: { + IDENT [12] { + name: @index1 + } + IDENT [13] { + name: @index1 + } + IDENT [14] { + name: @index1 + } + } + } + CREATE_LIST [15] { + elements: { + COMPREHENSION [16] { + iter_var: @c1:0 + iter_range: { + IDENT [17] { + name: @index0 + } + } + accu_var: @x1:0 + accu_init: { + CREATE_LIST [18] { + elements: { + } + } + } + loop_condition: { + CONSTANT [19] { value: true } + } + loop_step: { + CALL [20] { + function: _+_ + args: { + IDENT [21] { + name: @x1:0 + } + CREATE_LIST [22] { + elements: { + CALL [23] { + function: _+_ + args: { + IDENT [24] { + name: @c1:0 + } + CONSTANT [25] { value: 1 } + } + } + } + } + } + } + } + result: { + IDENT [26] { + name: @x1:0 + } + } + } + } + } + COMPREHENSION [27] { + iter_var: @c0:0 + iter_range: { + IDENT [28] { + name: @index0 + } + } + accu_var: @x0:0 + accu_init: { + CREATE_LIST [29] { + elements: { + } + } + } + loop_condition: { + CONSTANT [30] { value: true } + } + loop_step: { + CALL [31] { + function: _+_ + args: { + IDENT [32] { + name: @x0:0 + } + IDENT [33] { + name: @index3 + } + } + } + } + result: { + IDENT [34] { + name: @x0:0 + } + } + } + } + } + CALL [35] { + function: _==_ + args: { + IDENT [36] { + name: @index4 + } + IDENT [37] { + name: @index2 + } + } + } + } +} +Test case: NESTED_MACROS_2 +Source: [1, 2].map(y, [1, 2, 3].filter(x, x == y)) == [[1], [2]] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CREATE_LIST [4] { + elements: { + CONSTANT [5] { value: 1 } + } + } + CREATE_LIST [6] { + elements: { + CONSTANT [7] { value: 2 } + } + } + } + } + CREATE_LIST [8] { + elements: { + COMPREHENSION [9] { + iter_var: @c1:0 + iter_range: { + CREATE_LIST [10] { + elements: { + CONSTANT [11] { value: 1 } + CONSTANT [12] { value: 2 } + CONSTANT [13] { value: 3 } + } + } + } + accu_var: @x1:0 + accu_init: { + CREATE_LIST [14] { + elements: { + } + } + } + loop_condition: { + CONSTANT [15] { value: true } + } + loop_step: { + CALL [16] { + function: _?_:_ + args: { + CALL [17] { + function: _==_ + args: { + IDENT [18] { + name: @c1:0 + } + IDENT [19] { + name: @c0:0 + } + } + } + CALL [20] { + function: _+_ + args: { + IDENT [21] { + name: @x1:0 + } + CREATE_LIST [22] { + elements: { + IDENT [23] { + name: @c1:0 + } + } + } + } + } + IDENT [24] { + name: @x1:0 + } + } + } + } + result: { + IDENT [25] { + name: @x1:0 + } + } + } + } + } + COMPREHENSION [26] { + iter_var: @c0:0 + iter_range: { + CREATE_LIST [27] { + elements: { + CONSTANT [28] { value: 1 } + CONSTANT [29] { value: 2 } + } + } + } + accu_var: @x0:0 + accu_init: { + CREATE_LIST [30] { + elements: { + } + } + } + loop_condition: { + CONSTANT [31] { value: true } + } + loop_step: { + CALL [32] { + function: _+_ + args: { + IDENT [33] { + name: @x0:0 + } + IDENT [34] { + name: @index1 + } + } + } + } + result: { + IDENT [35] { + name: @x0:0 + } + } + } + } + } + CALL [36] { + function: _==_ + args: { + IDENT [37] { + name: @index2 + } + IDENT [38] { + name: @index0 + } + } + } + } +} +Test case: INCLUSION_LIST +Source: 1 in [1,2,3] && 2 in [1,2,3] && 3 in [3, [1,2,3]] && 1 in [1,2,3] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + CONSTANT [6] { value: 3 } + } + } + CALL [7] { + function: @in + args: { + CONSTANT [8] { value: 1 } + IDENT [9] { + name: @index0 + } + } + } + CALL [10] { + function: _&&_ + args: { + CALL [11] { + function: @in + args: { + CONSTANT [12] { value: 3 } + CREATE_LIST [13] { + elements: { + CONSTANT [14] { value: 3 } + IDENT [15] { + name: @index0 + } + } + } + } + } + IDENT [16] { + name: @index1 + } + } + } + CALL [17] { + function: _&&_ + args: { + IDENT [18] { + name: @index1 + } + CALL [19] { + function: @in + args: { + CONSTANT [20] { value: 2 } + IDENT [21] { + name: @index0 + } + } + } + } + } + } + } + CALL [22] { + function: _&&_ + args: { + IDENT [23] { + name: @index3 + } + IDENT [24] { + name: @index2 + } + } + } + } +} +Test case: INCLUSION_MAP +Source: 2 in {'a': 1, 2: {true: false}, 3: {true: false}} +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: true } + } + value: { + CONSTANT [6] { value: false } + } + } + } + CREATE_MAP [7] { + MAP_ENTRY [8] { + key: { + CONSTANT [9] { value: "a" } + } + value: { + CONSTANT [10] { value: 1 } + } + } + MAP_ENTRY [11] { + key: { + CONSTANT [12] { value: 2 } + } + value: { + IDENT [13] { + name: @index0 + } + } + } + MAP_ENTRY [14] { + key: { + CONSTANT [15] { value: 3 } + } + value: { + IDENT [16] { + name: @index0 + } + } + } + } + } + } + CALL [17] { + function: @in + args: { + CONSTANT [18] { value: 2 } + IDENT [19] { + name: @index1 + } + } + } + } +} +Test case: MACRO_ITER_VAR_NOT_REFERENCED +Source: [1,2].map(i, [1, 2].map(i, [3,4])) == [[[3, 4], [3, 4]], [[3, 4], [3, 4]]] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + } + } + CREATE_LIST [6] { + elements: { + CONSTANT [7] { value: 3 } + CONSTANT [8] { value: 4 } + } + } + CREATE_LIST [9] { + elements: { + IDENT [10] { + name: @index1 + } + IDENT [11] { + name: @index1 + } + } + } + CREATE_LIST [12] { + elements: { + IDENT [13] { + name: @index2 + } + IDENT [14] { + name: @index2 + } + } + } + CALL [15] { + function: _+_ + args: { + IDENT [16] { + name: @x0:0 + } + CREATE_LIST [17] { + elements: { + COMPREHENSION [18] { + iter_var: @c1:0 + iter_range: { + IDENT [19] { + name: @index0 + } + } + accu_var: @x1:0 + accu_init: { + CREATE_LIST [20] { + elements: { + } + } + } + loop_condition: { + CONSTANT [21] { value: true } + } + loop_step: { + CALL [22] { + function: _+_ + args: { + IDENT [23] { + name: @x1:0 + } + CREATE_LIST [24] { + elements: { + IDENT [25] { + name: @index1 + } + } + } + } + } + } + result: { + IDENT [26] { + name: @x1:0 + } + } + } + } + } + } + } + COMPREHENSION [27] { + iter_var: @c0:0 + iter_range: { + IDENT [28] { + name: @index0 + } + } + accu_var: @x0:0 + accu_init: { + CREATE_LIST [29] { + elements: { + } + } + } + loop_condition: { + CONSTANT [30] { value: true } + } + loop_step: { + IDENT [31] { + name: @index4 + } + } + result: { + IDENT [32] { + name: @x0:0 + } + } + } + } + } + CALL [33] { + function: _==_ + args: { + IDENT [34] { + name: @index5 + } + IDENT [35] { + name: @index3 + } + } + } + } +} +Test case: MACRO_SHADOWED_VARIABLE +Source: [x - 1 > 3 ? x - 1 : 5].exists(x, x - 1 > 3) || x - 1 > 3 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _-_ + args: { + IDENT [4] { + name: x + } + CONSTANT [5] { value: 1 } + } + } + CALL [6] { + function: _>_ + args: { + IDENT [7] { + name: @index0 + } + CONSTANT [8] { value: 3 } + } + } + COMPREHENSION [9] { + iter_var: @c0:0 + iter_range: { + CREATE_LIST [10] { + elements: { + CALL [11] { + function: _?_:_ + args: { + IDENT [12] { + name: @index1 + } + IDENT [13] { + name: @index0 + } + CONSTANT [14] { value: 5 } + } + } + } + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [15] { value: false } + } + loop_condition: { + CALL [16] { + function: @not_strictly_false + args: { + CALL [17] { + function: !_ + args: { + IDENT [18] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + CALL [19] { + function: _||_ + args: { + IDENT [20] { + name: @x0:0 + } + CALL [21] { + function: _>_ + args: { + CALL [22] { + function: _-_ + args: { + IDENT [23] { + name: @c0:0 + } + CONSTANT [24] { value: 1 } + } + } + CONSTANT [25] { value: 3 } + } + } + } + } + } + result: { + IDENT [26] { + name: @x0:0 + } + } + } + } + } + CALL [27] { + function: _||_ + args: { + IDENT [28] { + name: @index2 + } + IDENT [29] { + name: @index1 + } + } + } + } +} +Test case: MACRO_SHADOWED_VARIABLE_2 +Source: ["foo", "bar"].map(x, [x + x, x + x]).map(x, [x + x, x + x]) +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _+_ + args: { + IDENT [4] { + name: @c1:0 + } + IDENT [5] { + name: @c1:0 + } + } + } + CALL [6] { + function: _+_ + args: { + IDENT [7] { + name: @c0:0 + } + IDENT [8] { + name: @c0:0 + } + } + } + CALL [9] { + function: _+_ + args: { + IDENT [10] { + name: @x0:0 + } + CREATE_LIST [11] { + elements: { + CREATE_LIST [12] { + elements: { + IDENT [13] { + name: @index1 + } + IDENT [14] { + name: @index1 + } + } + } + } + } + } + } + COMPREHENSION [15] { + iter_var: @c1:0 + iter_range: { + CREATE_LIST [16] { + elements: { + CONSTANT [17] { value: "foo" } + CONSTANT [18] { value: "bar" } + } + } + } + accu_var: @x1:0 + accu_init: { + CREATE_LIST [19] { + elements: { + } + } + } + loop_condition: { + CONSTANT [20] { value: true } + } + loop_step: { + CALL [21] { + function: _+_ + args: { + IDENT [22] { + name: @x1:0 + } + CREATE_LIST [23] { + elements: { + CREATE_LIST [24] { + elements: { + IDENT [25] { + name: @index0 + } + IDENT [26] { + name: @index0 + } + } + } + } + } + } + } + } + result: { + IDENT [27] { + name: @x1:0 + } + } + } + } + } + COMPREHENSION [28] { + iter_var: @c0:0 + iter_range: { + IDENT [29] { + name: @index3 + } + } + accu_var: @x0:0 + accu_init: { + CREATE_LIST [30] { + elements: { + } + } + } + loop_condition: { + CONSTANT [31] { value: true } + } + loop_step: { + IDENT [32] { + name: @index2 + } + } + result: { + IDENT [33] { + name: @x0:0 + } + } + } + } +} +Test case: PRESENCE_TEST +Source: has({'a': true}.a) && {'a':true}['a'] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: "a" } + } + value: { + CONSTANT [6] { value: true } + } + } + } + CALL [7] { + function: _[_] + args: { + IDENT [8] { + name: @index0 + } + CONSTANT [9] { value: "a" } + } + } + } + } + CALL [10] { + function: _&&_ + args: { + SELECT [11] { + IDENT [12] { + name: @index0 + }.a~presence_test + } + IDENT [13] { + name: @index1 + } + } + } + } +} +Test case: PRESENCE_TEST_WITH_TERNARY +Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : 0) == 10 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + CALL [5] { + function: _?_:_ + args: { + SELECT [6] { + IDENT [7] { + name: @index0 + }.payload~presence_test + } + SELECT [8] { + SELECT [9] { + IDENT [10] { + name: @index0 + }.payload + }.single_int64 + } + CONSTANT [11] { value: 0 } + } + } + } + } + CALL [12] { + function: _==_ + args: { + IDENT [13] { + name: @index1 + } + CONSTANT [14] { value: 10 } + } + } + } +} +Test case: PRESENCE_TEST_WITH_TERNARY_2 +Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : msg.oneof_type.payload.single_int64 * 0) == 10 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.single_int64 + } + CALL [9] { + function: _?_:_ + args: { + SELECT [10] { + IDENT [11] { + name: @index0 + }.payload~presence_test + } + IDENT [12] { + name: @index2 + } + CALL [13] { + function: _*_ + args: { + IDENT [14] { + name: @index2 + } + CONSTANT [15] { value: 0 } + } + } + } + } + } + } + CALL [16] { + function: _==_ + args: { + IDENT [17] { + name: @index3 + } + CONSTANT [18] { value: 10 } + } + } + } +} +Test case: PRESENCE_TEST_WITH_TERNARY_3 +Source: (has(msg.oneof_type.payload.single_int64) ? msg.oneof_type.payload.single_int64 : msg.oneof_type.payload.single_int64 * 0) == 10 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.single_int64 + } + CALL [9] { + function: _?_:_ + args: { + SELECT [10] { + IDENT [11] { + name: @index1 + }.single_int64~presence_test + } + IDENT [12] { + name: @index2 + } + CALL [13] { + function: _*_ + args: { + IDENT [14] { + name: @index2 + } + CONSTANT [15] { value: 0 } + } + } + } + } + } + } + CALL [16] { + function: _==_ + args: { + IDENT [17] { + name: @index3 + } + CONSTANT [18] { value: 10 } + } + } + } +} +Test case: PRESENCE_TEST_WITH_TERNARY_NESTED +Source: (has(msg.oneof_type) && has(msg.oneof_type.payload) && has(msg.oneof_type.payload.single_int64)) ? ((has(msg.oneof_type.payload.map_string_string) && has(msg.oneof_type.payload.map_string_string.key)) ? msg.oneof_type.payload.map_string_string.key == 'A' : false) : false +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.map_string_string + } + CALL [9] { + function: _?_:_ + args: { + CALL [10] { + function: _&&_ + args: { + SELECT [11] { + IDENT [12] { + name: @index1 + }.map_string_string~presence_test + } + SELECT [13] { + IDENT [14] { + name: @index2 + }.key~presence_test + } + } + } + CALL [15] { + function: _==_ + args: { + SELECT [16] { + IDENT [17] { + name: @index2 + }.key + } + CONSTANT [18] { value: "A" } + } + } + CONSTANT [19] { value: false } + } + } + CALL [20] { + function: _&&_ + args: { + CALL [21] { + function: _&&_ + args: { + SELECT [22] { + IDENT [23] { + name: msg + }.oneof_type~presence_test + } + SELECT [24] { + IDENT [25] { + name: @index0 + }.payload~presence_test + } + } + } + SELECT [26] { + IDENT [27] { + name: @index1 + }.single_int64~presence_test + } + } + } + } + } + CALL [28] { + function: _?_:_ + args: { + IDENT [29] { + name: @index4 + } + IDENT [30] { + name: @index3 + } + CONSTANT [31] { value: false } + } + } + } +} +Test case: OPTIONAL_LIST +Source: [10, ?optional.none(), [?optional.none(), ?opt_x], [?optional.none(), ?opt_x]] == [10, [5], [5]] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: optional.none + args: { + } + } + CREATE_LIST [4] { + elements: { + IDENT [5] { + name: @index0 + } + IDENT [6] { + name: opt_x + } + } + optional_indices: [0, 1] + } + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 5 } + } + } + CREATE_LIST [9] { + elements: { + CONSTANT [10] { value: 10 } + IDENT [11] { + name: @index2 + } + IDENT [12] { + name: @index2 + } + } + } + CREATE_LIST [13] { + elements: { + CONSTANT [14] { value: 10 } + IDENT [15] { + name: @index0 + } + IDENT [16] { + name: @index1 + } + IDENT [17] { + name: @index1 + } + } + optional_indices: [0] + } + } + } + CALL [18] { + function: _==_ + args: { + IDENT [19] { + name: @index4 + } + IDENT [20] { + name: @index3 + } + } + } + } +} +Test case: OPTIONAL_MAP +Source: {?'hello': optional.of('hello')}['hello'] + {?'hello': optional.of('hello')}['hello'] == 'hellohello' +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: optional.of + args: { + CONSTANT [4] { value: "hello" } + } + } + CREATE_MAP [5] { + MAP_ENTRY [6] { + key: { + CONSTANT [7] { value: "hello" } + } + optional_entry: true + value: { + IDENT [8] { + name: @index0 + } + } + } + } + CALL [9] { + function: _[_] + args: { + IDENT [10] { + name: @index1 + } + CONSTANT [11] { value: "hello" } + } + } + CALL [12] { + function: _+_ + args: { + IDENT [13] { + name: @index2 + } + IDENT [14] { + name: @index2 + } + } + } + } + } + CALL [15] { + function: _==_ + args: { + IDENT [16] { + name: @index3 + } + CONSTANT [17] { value: "hellohello" } + } + } + } +} +Test case: OPTIONAL_MAP_CHAINED +Source: {?'key': optional.of('test')}[?'bogus'].or({'key': 'test'}[?'bogus']).orValue({'key': 'test'}['key']) == 'test' +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: "key" } + } + value: { + CONSTANT [6] { value: "test" } + } + } + } + CALL [7] { + function: orValue + target: { + CALL [8] { + function: or + target: { + CALL [9] { + function: _[?_] + args: { + CREATE_MAP [10] { + MAP_ENTRY [11] { + key: { + CONSTANT [12] { value: "key" } + } + optional_entry: true + value: { + CALL [13] { + function: optional.of + args: { + CONSTANT [14] { value: "test" } + } + } + } + } + } + CONSTANT [15] { value: "bogus" } + } + } + } + args: { + CALL [16] { + function: _[?_] + args: { + IDENT [17] { + name: @index0 + } + CONSTANT [18] { value: "bogus" } + } + } + } + } + } + args: { + CALL [19] { + function: _[_] + args: { + IDENT [20] { + name: @index0 + } + CONSTANT [21] { value: "key" } + } + } + } + } + } + } + CALL [22] { + function: _==_ + args: { + IDENT [23] { + name: @index1 + } + CONSTANT [24] { value: "test" } + } + } + } +} +Test case: OPTIONAL_MESSAGE +Source: TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}.single_int32 + TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}.single_int64 == 5 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: optional.ofNonZeroValue + args: { + CONSTANT [4] { value: 1 } + } + } + CALL [5] { + function: optional.of + args: { + CONSTANT [6] { value: 4 } + } + } + CREATE_STRUCT [7] { + name: TestAllTypes + entries: { + ENTRY [8] { + field_key: single_int64 + optional_entry: true + value: { + IDENT [9] { + name: @index0 + } + } + } + ENTRY [10] { + field_key: single_int32 + optional_entry: true + value: { + IDENT [11] { + name: @index1 + } + } + } + } + } + CALL [12] { + function: _+_ + args: { + SELECT [13] { + IDENT [14] { + name: @index2 + }.single_int32 + } + SELECT [15] { + IDENT [16] { + name: @index2 + }.single_int64 + } + } + } + } + } + CALL [17] { + function: _==_ + args: { + IDENT [18] { + name: @index3 + } + CONSTANT [19] { value: 5 } + } + } + } +} +Test case: CALL +Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('h' + 'e' + 'l' + 'l' + 'o') +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _+_ + args: { + CONSTANT [4] { value: "h" } + CONSTANT [5] { value: "e" } + } + } + CALL [6] { + function: _+_ + args: { + IDENT [7] { + name: @index0 + } + CONSTANT [8] { value: "l" } + } + } + CALL [9] { + function: _+_ + args: { + IDENT [10] { + name: @index1 + } + CONSTANT [11] { value: "l" } + } + } + CALL [12] { + function: _+_ + args: { + IDENT [13] { + name: @index2 + } + CONSTANT [14] { value: "o" } + } + } + CALL [15] { + function: _+_ + args: { + IDENT [16] { + name: @index3 + } + CONSTANT [17] { value: " world" } + } + } + } + } + CALL [18] { + function: matches + target: { + IDENT [19] { + name: @index4 + } + } + args: { + IDENT [20] { + name: @index3 + } + } + } + } +} +Test case: CALL_ARGUMENT_NESTED_NO_COMMON_SUBEXPR +Source: 'hello world'.matches('h' + 'e' + 'l' + 'l' + 'o') +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _+_ + args: { + CALL [4] { + function: _+_ + args: { + CALL [5] { + function: _+_ + args: { + CALL [6] { + function: _+_ + args: { + CONSTANT [7] { value: "h" } + CONSTANT [8] { value: "e" } + } + } + CONSTANT [9] { value: "l" } + } + } + CONSTANT [10] { value: "l" } + } + } + CONSTANT [11] { value: "o" } + } + } + } + } + CALL [12] { + function: matches + target: { + CONSTANT [13] { value: "hello world" } + } + args: { + IDENT [14] { + name: @index0 + } + } + } + } +} +Test case: CALL_TARGET_NESTED_NO_COMMON_SUBEXPR +Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('hello') +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _+_ + args: { + CALL [4] { + function: _+_ + args: { + CALL [5] { + function: _+_ + args: { + CALL [6] { + function: _+_ + args: { + CALL [7] { + function: _+_ + args: { + CONSTANT [8] { value: "h" } + CONSTANT [9] { value: "e" } + } + } + CONSTANT [10] { value: "l" } + } + } + CONSTANT [11] { value: "l" } + } + } + CONSTANT [12] { value: "o" } + } + } + CONSTANT [13] { value: " world" } + } + } + } + } + CALL [14] { + function: matches + target: { + IDENT [15] { + name: @index0 + } + } + args: { + CONSTANT [16] { value: "hello" } + } + } + } +} +Test case: CALL_BOTH_ARGUMENT_TARGET_NESTED_NO_COMMON_SUBEXPR +Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('w' + 'o' + 'r' + 'l' + 'd') +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _+_ + args: { + CALL [4] { + function: _+_ + args: { + CALL [5] { + function: _+_ + args: { + CALL [6] { + function: _+_ + args: { + CONSTANT [7] { value: "w" } + CONSTANT [8] { value: "o" } + } + } + CONSTANT [9] { value: "r" } + } + } + CONSTANT [10] { value: "l" } + } + } + CONSTANT [11] { value: "d" } + } + } + CALL [12] { + function: _+_ + args: { + CALL [13] { + function: _+_ + args: { + CALL [14] { + function: _+_ + args: { + CALL [15] { + function: _+_ + args: { + CALL [16] { + function: _+_ + args: { + CONSTANT [17] { value: "h" } + CONSTANT [18] { value: "e" } + } + } + CONSTANT [19] { value: "l" } + } + } + CONSTANT [20] { value: "l" } + } + } + CONSTANT [21] { value: "o" } + } + } + CONSTANT [22] { value: " world" } + } + } + } + } + CALL [23] { + function: matches + target: { + IDENT [24] { + name: @index1 + } + } + args: { + IDENT [25] { + name: @index0 + } + } + } + } +} diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_6.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_6.baseline new file mode 100644 index 000000000..fb329babc --- /dev/null +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_6.baseline @@ -0,0 +1,3293 @@ +Test case: SIZE_1 +Source: size([1,2]) + size([1,2]) + 1 == 5 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + } + } + CALL [6] { + function: size + args: { + IDENT [7] { + name: @index0 + } + } + } + CALL [8] { + function: _+_ + args: { + CALL [9] { + function: _+_ + args: { + IDENT [10] { + name: @index1 + } + IDENT [11] { + name: @index1 + } + } + } + CONSTANT [12] { value: 1 } + } + } + } + } + CALL [13] { + function: _==_ + args: { + IDENT [14] { + name: @index2 + } + CONSTANT [15] { value: 5 } + } + } + } +} +Test case: SIZE_2 +Source: 2 + size([1,2]) + size([1,2]) + 1 == 7 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + } + } + CALL [6] { + function: size + args: { + IDENT [7] { + name: @index0 + } + } + } + CALL [8] { + function: _+_ + args: { + CALL [9] { + function: _+_ + args: { + CALL [10] { + function: _+_ + args: { + CONSTANT [11] { value: 2 } + IDENT [12] { + name: @index1 + } + } + } + IDENT [13] { + name: @index1 + } + } + } + CONSTANT [14] { value: 1 } + } + } + } + } + CALL [15] { + function: _==_ + args: { + IDENT [16] { + name: @index2 + } + CONSTANT [17] { value: 7 } + } + } + } +} +Test case: SIZE_3 +Source: size([0]) + size([0]) + size([1,2]) + size([1,2]) == 6 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 0 } + } + } + CALL [5] { + function: size + args: { + IDENT [6] { + name: @index0 + } + } + } + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 1 } + CONSTANT [9] { value: 2 } + } + } + CALL [10] { + function: size + args: { + IDENT [11] { + name: @index2 + } + } + } + CALL [12] { + function: _+_ + args: { + CALL [13] { + function: _+_ + args: { + CALL [14] { + function: _+_ + args: { + IDENT [15] { + name: @index1 + } + IDENT [16] { + name: @index1 + } + } + } + IDENT [17] { + name: @index3 + } + } + } + IDENT [18] { + name: @index3 + } + } + } + } + } + CALL [19] { + function: _==_ + args: { + IDENT [20] { + name: @index4 + } + CONSTANT [21] { value: 6 } + } + } + } +} +Test case: SIZE_4 +Source: 5 + size([0]) + size([0]) + size([1,2]) + size([1,2]) + size([1,2,3]) + size([1,2,3]) == 17 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 0 } + } + } + CALL [5] { + function: size + args: { + IDENT [6] { + name: @index0 + } + } + } + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 1 } + CONSTANT [9] { value: 2 } + } + } + CALL [10] { + function: size + args: { + IDENT [11] { + name: @index2 + } + } + } + CREATE_LIST [12] { + elements: { + CONSTANT [13] { value: 1 } + CONSTANT [14] { value: 2 } + CONSTANT [15] { value: 3 } + } + } + CALL [16] { + function: size + args: { + IDENT [17] { + name: @index4 + } + } + } + CALL [18] { + function: _+_ + args: { + CALL [19] { + function: _+_ + args: { + CALL [20] { + function: _+_ + args: { + CALL [21] { + function: _+_ + args: { + CALL [22] { + function: _+_ + args: { + CALL [23] { + function: _+_ + args: { + CONSTANT [24] { value: 5 } + IDENT [25] { + name: @index1 + } + } + } + IDENT [26] { + name: @index1 + } + } + } + IDENT [27] { + name: @index3 + } + } + } + IDENT [28] { + name: @index3 + } + } + } + IDENT [29] { + name: @index5 + } + } + } + IDENT [30] { + name: @index5 + } + } + } + } + } + CALL [31] { + function: _==_ + args: { + IDENT [32] { + name: @index6 + } + CONSTANT [33] { value: 17 } + } + } + } +} +Test case: TIMESTAMP +Source: timestamp(int(timestamp(1000000000))).getFullYear() + timestamp(int(timestamp(75))).getFullYear() + timestamp(int(timestamp(50))).getFullYear() + timestamp(int(timestamp(1000000000))).getFullYear() + timestamp(int(timestamp(50))).getSeconds() + timestamp(int(timestamp(200))).getFullYear() + timestamp(int(timestamp(200))).getFullYear() + timestamp(int(timestamp(75))).getMinutes() + timestamp(int(timestamp(1000000000))).getFullYear() == 13934 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: timestamp + args: { + CONSTANT [4] { value: 1000000000 } + } + } + CALL [5] { + function: int + args: { + IDENT [6] { + name: @index0 + } + } + } + CALL [7] { + function: timestamp + args: { + IDENT [8] { + name: @index1 + } + } + } + CALL [9] { + function: getFullYear + target: { + IDENT [10] { + name: @index2 + } + } + args: { + } + } + CALL [11] { + function: timestamp + args: { + CONSTANT [12] { value: 50 } + } + } + CALL [13] { + function: int + args: { + IDENT [14] { + name: @index4 + } + } + } + CALL [15] { + function: timestamp + args: { + IDENT [16] { + name: @index5 + } + } + } + CALL [17] { + function: timestamp + args: { + CONSTANT [18] { value: 200 } + } + } + CALL [19] { + function: int + args: { + IDENT [20] { + name: @index7 + } + } + } + CALL [21] { + function: timestamp + args: { + IDENT [22] { + name: @index8 + } + } + } + CALL [23] { + function: getFullYear + target: { + IDENT [24] { + name: @index9 + } + } + args: { + } + } + CALL [25] { + function: timestamp + args: { + CONSTANT [26] { value: 75 } + } + } + CALL [27] { + function: int + args: { + IDENT [28] { + name: @index11 + } + } + } + CALL [29] { + function: timestamp + args: { + IDENT [30] { + name: @index12 + } + } + } + CALL [31] { + function: getMinutes + target: { + IDENT [32] { + name: @index13 + } + } + args: { + } + } + CALL [33] { + function: _+_ + args: { + CALL [34] { + function: _+_ + args: { + CALL [35] { + function: _+_ + args: { + CALL [36] { + function: _+_ + args: { + CALL [37] { + function: _+_ + args: { + IDENT [38] { + name: @index3 + } + CALL [39] { + function: getFullYear + target: { + IDENT [40] { + name: @index13 + } + } + args: { + } + } + } + } + CALL [41] { + function: getFullYear + target: { + IDENT [42] { + name: @index6 + } + } + args: { + } + } + } + } + IDENT [43] { + name: @index3 + } + } + } + CALL [44] { + function: getSeconds + target: { + IDENT [45] { + name: @index6 + } + } + args: { + } + } + } + } + IDENT [46] { + name: @index10 + } + } + } + CALL [47] { + function: _+_ + args: { + CALL [48] { + function: _+_ + args: { + CALL [49] { + function: _+_ + args: { + IDENT [50] { + name: @index15 + } + IDENT [51] { + name: @index10 + } + } + } + IDENT [52] { + name: @index14 + } + } + } + IDENT [53] { + name: @index3 + } + } + } + } + } + CALL [54] { + function: _==_ + args: { + IDENT [55] { + name: @index16 + } + CONSTANT [56] { value: 13934 } + } + } + } +} +Test case: MAP_INDEX +Source: {"a": 2}["a"] + {"a": 2}["a"] * {"a": 2}["a"] == 6 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: "a" } + } + value: { + CONSTANT [6] { value: 2 } + } + } + } + CALL [7] { + function: _[_] + args: { + IDENT [8] { + name: @index0 + } + CONSTANT [9] { value: "a" } + } + } + CALL [10] { + function: _+_ + args: { + IDENT [11] { + name: @index1 + } + CALL [12] { + function: _*_ + args: { + IDENT [13] { + name: @index1 + } + IDENT [14] { + name: @index1 + } + } + } + } + } + } + } + CALL [15] { + function: _==_ + args: { + IDENT [16] { + name: @index2 + } + CONSTANT [17] { value: 6 } + } + } + } +} +Test case: NESTED_MAP_CONSTRUCTION +Source: {'a': {'b': 1}, 'c': {'b': 1}, 'd': {'e': {'b': 1}}, 'e': {'e': {'b': 1}}} +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: "b" } + } + value: { + CONSTANT [6] { value: 1 } + } + } + } + CREATE_MAP [7] { + MAP_ENTRY [8] { + key: { + CONSTANT [9] { value: "e" } + } + value: { + IDENT [10] { + name: @index0 + } + } + } + } + } + } + CREATE_MAP [11] { + MAP_ENTRY [12] { + key: { + CONSTANT [13] { value: "a" } + } + value: { + IDENT [14] { + name: @index0 + } + } + } + MAP_ENTRY [15] { + key: { + CONSTANT [16] { value: "c" } + } + value: { + IDENT [17] { + name: @index0 + } + } + } + MAP_ENTRY [18] { + key: { + CONSTANT [19] { value: "d" } + } + value: { + IDENT [20] { + name: @index1 + } + } + } + MAP_ENTRY [21] { + key: { + CONSTANT [22] { value: "e" } + } + value: { + IDENT [23] { + name: @index1 + } + } + } + } + } +} +Test case: NESTED_LIST_CONSTRUCTION +Source: [1, [1,2,3,4], 2, [1,2,3,4], 5, [1,2,3,4], 7, [[1,2], [1,2,3,4]], [1,2]] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + CONSTANT [6] { value: 3 } + CONSTANT [7] { value: 4 } + } + } + CREATE_LIST [8] { + elements: { + CONSTANT [9] { value: 1 } + CONSTANT [10] { value: 2 } + } + } + CREATE_LIST [11] { + elements: { + IDENT [12] { + name: @index1 + } + IDENT [13] { + name: @index0 + } + } + } + } + } + CREATE_LIST [14] { + elements: { + CONSTANT [15] { value: 1 } + IDENT [16] { + name: @index0 + } + CONSTANT [17] { value: 2 } + IDENT [18] { + name: @index0 + } + CONSTANT [19] { value: 5 } + IDENT [20] { + name: @index0 + } + CONSTANT [21] { value: 7 } + IDENT [22] { + name: @index2 + } + IDENT [23] { + name: @index1 + } + } + } + } +} +Test case: SELECT +Source: msg.single_int64 + msg.single_int64 == 6 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.single_int64 + } + CALL [5] { + function: _+_ + args: { + IDENT [6] { + name: @index0 + } + IDENT [7] { + name: @index0 + } + } + } + } + } + CALL [8] { + function: _==_ + args: { + IDENT [9] { + name: @index1 + } + CONSTANT [10] { value: 6 } + } + } + } +} +Test case: SELECT_NESTED_1 +Source: msg.oneof_type.payload.single_int64 + msg.oneof_type.payload.single_int32 + msg.oneof_type.payload.single_int64 + msg.single_int64 + msg.oneof_type.payload.oneof_type.payload.single_int64 == 31 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.single_int64 + } + CALL [9] { + function: _+_ + args: { + CALL [10] { + function: _+_ + args: { + CALL [11] { + function: _+_ + args: { + CALL [12] { + function: _+_ + args: { + IDENT [13] { + name: @index2 + } + SELECT [14] { + IDENT [15] { + name: @index1 + }.single_int32 + } + } + } + IDENT [16] { + name: @index2 + } + } + } + SELECT [17] { + IDENT [18] { + name: msg + }.single_int64 + } + } + } + SELECT [19] { + SELECT [20] { + SELECT [21] { + IDENT [22] { + name: @index1 + }.oneof_type + }.payload + }.single_int64 + } + } + } + } + } + CALL [23] { + function: _==_ + args: { + IDENT [24] { + name: @index3 + } + CONSTANT [25] { value: 31 } + } + } + } +} +Test case: SELECT_NESTED_2 +Source: true || msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload.single_bool || msg.oneof_type.payload.oneof_type.payload.oneof_type.child.child.payload.single_bool +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.oneof_type + } + SELECT [9] { + IDENT [10] { + name: @index2 + }.payload + } + SELECT [11] { + IDENT [12] { + name: @index3 + }.oneof_type + } + SELECT [13] { + SELECT [14] { + SELECT [15] { + SELECT [16] { + IDENT [17] { + name: @index4 + }.child + }.child + }.payload + }.single_bool + } + CALL [18] { + function: _||_ + args: { + CONSTANT [19] { value: true } + SELECT [20] { + SELECT [21] { + SELECT [22] { + SELECT [23] { + IDENT [24] { + name: @index4 + }.payload + }.oneof_type + }.payload + }.single_bool + } + } + } + } + } + CALL [25] { + function: _||_ + args: { + IDENT [26] { + name: @index6 + } + IDENT [27] { + name: @index5 + } + } + } + } +} +Test case: SELECT_NESTED_MESSAGE_MAP_INDEX_1 +Source: msg.oneof_type.payload.map_int32_int64[1] + msg.oneof_type.payload.map_int32_int64[1] + msg.oneof_type.payload.map_int32_int64[1] == 15 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.map_int32_int64 + } + CALL [9] { + function: _[_] + args: { + IDENT [10] { + name: @index2 + } + CONSTANT [11] { value: 1 } + } + } + CALL [12] { + function: _+_ + args: { + CALL [13] { + function: _+_ + args: { + IDENT [14] { + name: @index3 + } + IDENT [15] { + name: @index3 + } + } + } + IDENT [16] { + name: @index3 + } + } + } + } + } + CALL [17] { + function: _==_ + args: { + IDENT [18] { + name: @index4 + } + CONSTANT [19] { value: 15 } + } + } + } +} +Test case: SELECT_NESTED_MESSAGE_MAP_INDEX_2 +Source: msg.oneof_type.payload.map_int32_int64[0] + msg.oneof_type.payload.map_int32_int64[1] + msg.oneof_type.payload.map_int32_int64[2] == 8 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.map_int32_int64 + } + CALL [9] { + function: _+_ + args: { + CALL [10] { + function: _+_ + args: { + CALL [11] { + function: _[_] + args: { + IDENT [12] { + name: @index2 + } + CONSTANT [13] { value: 0 } + } + } + CALL [14] { + function: _[_] + args: { + IDENT [15] { + name: @index2 + } + CONSTANT [16] { value: 1 } + } + } + } + } + CALL [17] { + function: _[_] + args: { + IDENT [18] { + name: @index2 + } + CONSTANT [19] { value: 2 } + } + } + } + } + } + } + CALL [20] { + function: _==_ + args: { + IDENT [21] { + name: @index3 + } + CONSTANT [22] { value: 8 } + } + } + } +} +Test case: SELECT_NESTED_NO_COMMON_SUBEXPR +Source: msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload.single_int64 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + SELECT [4] { + SELECT [5] { + SELECT [6] { + SELECT [7] { + SELECT [8] { + IDENT [9] { + name: msg + }.oneof_type + }.payload + }.oneof_type + }.payload + }.oneof_type + }.payload + } + SELECT [10] { + SELECT [11] { + IDENT [12] { + name: @index0 + }.oneof_type + }.payload + } + } + } + SELECT [13] { + IDENT [14] { + name: @index1 + }.single_int64 + } + } +} +Test case: TERNARY +Source: (msg.single_int64 > 0 ? msg.single_int64 : 0) == 3 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.single_int64 + } + CALL [5] { + function: _?_:_ + args: { + CALL [6] { + function: _>_ + args: { + IDENT [7] { + name: @index0 + } + CONSTANT [8] { value: 0 } + } + } + IDENT [9] { + name: @index0 + } + CONSTANT [10] { value: 0 } + } + } + } + } + CALL [11] { + function: _==_ + args: { + IDENT [12] { + name: @index1 + } + CONSTANT [13] { value: 3 } + } + } + } +} +Test case: TERNARY_BIND_RHS_ONLY +Source: false ? false : (msg.single_int64) + ((msg.single_int64 + 1) * 2) == 11 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.single_int64 + } + CALL [5] { + function: _==_ + args: { + CALL [6] { + function: _+_ + args: { + IDENT [7] { + name: @index0 + } + CALL [8] { + function: _*_ + args: { + CALL [9] { + function: _+_ + args: { + IDENT [10] { + name: @index0 + } + CONSTANT [11] { value: 1 } + } + } + CONSTANT [12] { value: 2 } + } + } + } + } + CONSTANT [13] { value: 11 } + } + } + } + } + CALL [14] { + function: _?_:_ + args: { + CONSTANT [15] { value: false } + CONSTANT [16] { value: false } + IDENT [17] { + name: @index1 + } + } + } + } +} +Test case: NESTED_TERNARY +Source: (msg.single_int64 > 0 ? (msg.single_int32 > 0 ? msg.single_int64 + msg.single_int32 : 0) : 0) == 8 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.single_int64 + } + SELECT [5] { + IDENT [6] { + name: msg + }.single_int32 + } + CALL [7] { + function: _?_:_ + args: { + CALL [8] { + function: _>_ + args: { + IDENT [9] { + name: @index0 + } + CONSTANT [10] { value: 0 } + } + } + CALL [11] { + function: _?_:_ + args: { + CALL [12] { + function: _>_ + args: { + IDENT [13] { + name: @index1 + } + CONSTANT [14] { value: 0 } + } + } + CALL [15] { + function: _+_ + args: { + IDENT [16] { + name: @index0 + } + IDENT [17] { + name: @index1 + } + } + } + CONSTANT [18] { value: 0 } + } + } + CONSTANT [19] { value: 0 } + } + } + } + } + CALL [20] { + function: _==_ + args: { + IDENT [21] { + name: @index2 + } + CONSTANT [22] { value: 8 } + } + } + } +} +Test case: MULTIPLE_MACROS_1 +Source: size([[1].exists(i, i > 0)]) + size([[1].exists(j, j > 0)]) + size([[2].exists(k, k > 1)]) + size([[2].exists(l, l > 1)]) == 4 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + } + } + CALL [5] { + function: _>_ + args: { + IDENT [6] { + name: @c0:0 + } + CONSTANT [7] { value: 0 } + } + } + CALL [8] { + function: _||_ + args: { + IDENT [9] { + name: @x0:0 + } + IDENT [10] { + name: @index1 + } + } + } + COMPREHENSION [11] { + iter_var: @c0:0 + iter_range: { + IDENT [12] { + name: @index0 + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [13] { value: false } + } + loop_condition: { + CALL [14] { + function: @not_strictly_false + args: { + CALL [15] { + function: !_ + args: { + IDENT [16] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + IDENT [17] { + name: @index2 + } + } + result: { + IDENT [18] { + name: @x0:0 + } + } + } + CREATE_LIST [19] { + elements: { + IDENT [20] { + name: @index3 + } + } + } + CALL [21] { + function: size + args: { + IDENT [22] { + name: @index4 + } + } + } + CREATE_LIST [23] { + elements: { + CONSTANT [24] { value: 2 } + } + } + CALL [25] { + function: _>_ + args: { + IDENT [26] { + name: @c0:0 + } + CONSTANT [27] { value: 1 } + } + } + CALL [28] { + function: _||_ + args: { + IDENT [29] { + name: @x0:0 + } + IDENT [30] { + name: @index7 + } + } + } + COMPREHENSION [31] { + iter_var: @c0:0 + iter_range: { + IDENT [32] { + name: @index6 + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [33] { value: false } + } + loop_condition: { + CALL [34] { + function: @not_strictly_false + args: { + CALL [35] { + function: !_ + args: { + IDENT [36] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + IDENT [37] { + name: @index8 + } + } + result: { + IDENT [38] { + name: @x0:0 + } + } + } + CREATE_LIST [39] { + elements: { + IDENT [40] { + name: @index9 + } + } + } + CALL [41] { + function: size + args: { + IDENT [42] { + name: @index10 + } + } + } + CALL [43] { + function: _+_ + args: { + CALL [44] { + function: _+_ + args: { + CALL [45] { + function: _+_ + args: { + IDENT [46] { + name: @index5 + } + IDENT [47] { + name: @index5 + } + } + } + IDENT [48] { + name: @index11 + } + } + } + IDENT [49] { + name: @index11 + } + } + } + } + } + CALL [50] { + function: _==_ + args: { + IDENT [51] { + name: @index12 + } + CONSTANT [52] { value: 4 } + } + } + } +} +Test case: MULTIPLE_MACROS_2 +Source: [[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == 'a')] + [['a'].exists(l, l == 'a')] == [true, true, true, true] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + } + } + CALL [5] { + function: _>_ + args: { + IDENT [6] { + name: @c0:0 + } + CONSTANT [7] { value: 0 } + } + } + CALL [8] { + function: _||_ + args: { + IDENT [9] { + name: @x0:0 + } + IDENT [10] { + name: @index1 + } + } + } + COMPREHENSION [11] { + iter_var: @c0:0 + iter_range: { + IDENT [12] { + name: @index0 + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [13] { value: false } + } + loop_condition: { + CALL [14] { + function: @not_strictly_false + args: { + CALL [15] { + function: !_ + args: { + IDENT [16] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + IDENT [17] { + name: @index2 + } + } + result: { + IDENT [18] { + name: @x0:0 + } + } + } + CREATE_LIST [19] { + elements: { + IDENT [20] { + name: @index3 + } + } + } + CREATE_LIST [21] { + elements: { + CONSTANT [22] { value: "a" } + } + } + CALL [23] { + function: _==_ + args: { + IDENT [24] { + name: @c0:1 + } + CONSTANT [25] { value: "a" } + } + } + CALL [26] { + function: _||_ + args: { + IDENT [27] { + name: @x0:1 + } + IDENT [28] { + name: @index6 + } + } + } + COMPREHENSION [29] { + iter_var: @c0:1 + iter_range: { + IDENT [30] { + name: @index5 + } + } + accu_var: @x0:1 + accu_init: { + CONSTANT [31] { value: false } + } + loop_condition: { + CALL [32] { + function: @not_strictly_false + args: { + CALL [33] { + function: !_ + args: { + IDENT [34] { + name: @x0:1 + } + } + } + } + } + } + loop_step: { + IDENT [35] { + name: @index7 + } + } + result: { + IDENT [36] { + name: @x0:1 + } + } + } + CREATE_LIST [37] { + elements: { + IDENT [38] { + name: @index8 + } + } + } + CREATE_LIST [39] { + elements: { + CONSTANT [40] { value: true } + CONSTANT [41] { value: true } + CONSTANT [42] { value: true } + CONSTANT [43] { value: true } + } + } + CALL [44] { + function: _+_ + args: { + CALL [45] { + function: _+_ + args: { + CALL [46] { + function: _+_ + args: { + IDENT [47] { + name: @index4 + } + IDENT [48] { + name: @index4 + } + } + } + IDENT [49] { + name: @index9 + } + } + } + IDENT [50] { + name: @index9 + } + } + } + } + } + CALL [51] { + function: _==_ + args: { + IDENT [52] { + name: @index11 + } + IDENT [53] { + name: @index10 + } + } + } + } +} +Test case: NESTED_MACROS +Source: [1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [[2, 3, 4], [2, 3, 4], [2, 3, 4]] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + CONSTANT [6] { value: 3 } + } + } + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 2 } + CONSTANT [9] { value: 3 } + CONSTANT [10] { value: 4 } + } + } + CREATE_LIST [11] { + elements: { + IDENT [12] { + name: @index1 + } + IDENT [13] { + name: @index1 + } + IDENT [14] { + name: @index1 + } + } + } + CALL [15] { + function: _+_ + args: { + IDENT [16] { + name: @x0:0 + } + CREATE_LIST [17] { + elements: { + COMPREHENSION [18] { + iter_var: @c1:0 + iter_range: { + IDENT [19] { + name: @index0 + } + } + accu_var: @x1:0 + accu_init: { + CREATE_LIST [20] { + elements: { + } + } + } + loop_condition: { + CONSTANT [21] { value: true } + } + loop_step: { + CALL [22] { + function: _+_ + args: { + IDENT [23] { + name: @x1:0 + } + CREATE_LIST [24] { + elements: { + CALL [25] { + function: _+_ + args: { + IDENT [26] { + name: @c1:0 + } + CONSTANT [27] { value: 1 } + } + } + } + } + } + } + } + result: { + IDENT [28] { + name: @x1:0 + } + } + } + } + } + } + } + COMPREHENSION [29] { + iter_var: @c0:0 + iter_range: { + IDENT [30] { + name: @index0 + } + } + accu_var: @x0:0 + accu_init: { + CREATE_LIST [31] { + elements: { + } + } + } + loop_condition: { + CONSTANT [32] { value: true } + } + loop_step: { + IDENT [33] { + name: @index3 + } + } + result: { + IDENT [34] { + name: @x0:0 + } + } + } + } + } + CALL [35] { + function: _==_ + args: { + IDENT [36] { + name: @index4 + } + IDENT [37] { + name: @index2 + } + } + } + } +} +Test case: NESTED_MACROS_2 +Source: [1, 2].map(y, [1, 2, 3].filter(x, x == y)) == [[1], [2]] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CREATE_LIST [4] { + elements: { + CONSTANT [5] { value: 1 } + } + } + CREATE_LIST [6] { + elements: { + CONSTANT [7] { value: 2 } + } + } + } + } + CALL [8] { + function: _+_ + args: { + IDENT [9] { + name: @x0:0 + } + CREATE_LIST [10] { + elements: { + COMPREHENSION [11] { + iter_var: @c1:0 + iter_range: { + CREATE_LIST [12] { + elements: { + CONSTANT [13] { value: 1 } + CONSTANT [14] { value: 2 } + CONSTANT [15] { value: 3 } + } + } + } + accu_var: @x1:0 + accu_init: { + CREATE_LIST [16] { + elements: { + } + } + } + loop_condition: { + CONSTANT [17] { value: true } + } + loop_step: { + CALL [18] { + function: _?_:_ + args: { + CALL [19] { + function: _==_ + args: { + IDENT [20] { + name: @c1:0 + } + IDENT [21] { + name: @c0:0 + } + } + } + CALL [22] { + function: _+_ + args: { + IDENT [23] { + name: @x1:0 + } + CREATE_LIST [24] { + elements: { + IDENT [25] { + name: @c1:0 + } + } + } + } + } + IDENT [26] { + name: @x1:0 + } + } + } + } + result: { + IDENT [27] { + name: @x1:0 + } + } + } + } + } + } + } + COMPREHENSION [28] { + iter_var: @c0:0 + iter_range: { + CREATE_LIST [29] { + elements: { + CONSTANT [30] { value: 1 } + CONSTANT [31] { value: 2 } + } + } + } + accu_var: @x0:0 + accu_init: { + CREATE_LIST [32] { + elements: { + } + } + } + loop_condition: { + CONSTANT [33] { value: true } + } + loop_step: { + IDENT [34] { + name: @index1 + } + } + result: { + IDENT [35] { + name: @x0:0 + } + } + } + } + } + CALL [36] { + function: _==_ + args: { + IDENT [37] { + name: @index2 + } + IDENT [38] { + name: @index0 + } + } + } + } +} +Test case: INCLUSION_LIST +Source: 1 in [1,2,3] && 2 in [1,2,3] && 3 in [3, [1,2,3]] && 1 in [1,2,3] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + CONSTANT [6] { value: 3 } + } + } + CALL [7] { + function: @in + args: { + CONSTANT [8] { value: 1 } + IDENT [9] { + name: @index0 + } + } + } + CALL [10] { + function: _&&_ + args: { + CALL [11] { + function: @in + args: { + CONSTANT [12] { value: 3 } + CREATE_LIST [13] { + elements: { + CONSTANT [14] { value: 3 } + IDENT [15] { + name: @index0 + } + } + } + } + } + IDENT [16] { + name: @index1 + } + } + } + CALL [17] { + function: _&&_ + args: { + IDENT [18] { + name: @index1 + } + CALL [19] { + function: @in + args: { + CONSTANT [20] { value: 2 } + IDENT [21] { + name: @index0 + } + } + } + } + } + } + } + CALL [22] { + function: _&&_ + args: { + IDENT [23] { + name: @index3 + } + IDENT [24] { + name: @index2 + } + } + } + } +} +Test case: INCLUSION_MAP +Source: 2 in {'a': 1, 2: {true: false}, 3: {true: false}} +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: true } + } + value: { + CONSTANT [6] { value: false } + } + } + } + CREATE_MAP [7] { + MAP_ENTRY [8] { + key: { + CONSTANT [9] { value: "a" } + } + value: { + CONSTANT [10] { value: 1 } + } + } + MAP_ENTRY [11] { + key: { + CONSTANT [12] { value: 2 } + } + value: { + IDENT [13] { + name: @index0 + } + } + } + MAP_ENTRY [14] { + key: { + CONSTANT [15] { value: 3 } + } + value: { + IDENT [16] { + name: @index0 + } + } + } + } + } + } + CALL [17] { + function: @in + args: { + CONSTANT [18] { value: 2 } + IDENT [19] { + name: @index1 + } + } + } + } +} +Test case: MACRO_ITER_VAR_NOT_REFERENCED +Source: [1,2].map(i, [1, 2].map(i, [3,4])) == [[[3, 4], [3, 4]], [[3, 4], [3, 4]]] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + } + } + CREATE_LIST [6] { + elements: { + CONSTANT [7] { value: 3 } + CONSTANT [8] { value: 4 } + } + } + CREATE_LIST [9] { + elements: { + IDENT [10] { + name: @index1 + } + IDENT [11] { + name: @index1 + } + } + } + CREATE_LIST [12] { + elements: { + IDENT [13] { + name: @index2 + } + IDENT [14] { + name: @index2 + } + } + } + COMPREHENSION [15] { + iter_var: @c0:0 + iter_range: { + IDENT [16] { + name: @index0 + } + } + accu_var: @x0:0 + accu_init: { + CREATE_LIST [17] { + elements: { + } + } + } + loop_condition: { + CONSTANT [18] { value: true } + } + loop_step: { + CALL [19] { + function: _+_ + args: { + IDENT [20] { + name: @x0:0 + } + CREATE_LIST [21] { + elements: { + COMPREHENSION [22] { + iter_var: @c1:0 + iter_range: { + IDENT [23] { + name: @index0 + } + } + accu_var: @x1:0 + accu_init: { + CREATE_LIST [24] { + elements: { + } + } + } + loop_condition: { + CONSTANT [25] { value: true } + } + loop_step: { + CALL [26] { + function: _+_ + args: { + IDENT [27] { + name: @x1:0 + } + CREATE_LIST [28] { + elements: { + IDENT [29] { + name: @index1 + } + } + } + } + } + } + result: { + IDENT [30] { + name: @x1:0 + } + } + } + } + } + } + } + } + result: { + IDENT [31] { + name: @x0:0 + } + } + } + } + } + CALL [32] { + function: _==_ + args: { + IDENT [33] { + name: @index4 + } + IDENT [34] { + name: @index3 + } + } + } + } +} +Test case: MACRO_SHADOWED_VARIABLE +Source: [x - 1 > 3 ? x - 1 : 5].exists(x, x - 1 > 3) || x - 1 > 3 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _-_ + args: { + IDENT [4] { + name: x + } + CONSTANT [5] { value: 1 } + } + } + CALL [6] { + function: _>_ + args: { + IDENT [7] { + name: @index0 + } + CONSTANT [8] { value: 3 } + } + } + COMPREHENSION [9] { + iter_var: @c0:0 + iter_range: { + CREATE_LIST [10] { + elements: { + CALL [11] { + function: _?_:_ + args: { + IDENT [12] { + name: @index1 + } + IDENT [13] { + name: @index0 + } + CONSTANT [14] { value: 5 } + } + } + } + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [15] { value: false } + } + loop_condition: { + CALL [16] { + function: @not_strictly_false + args: { + CALL [17] { + function: !_ + args: { + IDENT [18] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + CALL [19] { + function: _||_ + args: { + IDENT [20] { + name: @x0:0 + } + CALL [21] { + function: _>_ + args: { + CALL [22] { + function: _-_ + args: { + IDENT [23] { + name: @c0:0 + } + CONSTANT [24] { value: 1 } + } + } + CONSTANT [25] { value: 3 } + } + } + } + } + } + result: { + IDENT [26] { + name: @x0:0 + } + } + } + } + } + CALL [27] { + function: _||_ + args: { + IDENT [28] { + name: @index2 + } + IDENT [29] { + name: @index1 + } + } + } + } +} +Test case: MACRO_SHADOWED_VARIABLE_2 +Source: ["foo", "bar"].map(x, [x + x, x + x]).map(x, [x + x, x + x]) +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _+_ + args: { + IDENT [4] { + name: @c1:0 + } + IDENT [5] { + name: @c1:0 + } + } + } + CALL [6] { + function: _+_ + args: { + IDENT [7] { + name: @c0:0 + } + IDENT [8] { + name: @c0:0 + } + } + } + CALL [9] { + function: _+_ + args: { + IDENT [10] { + name: @x0:0 + } + CREATE_LIST [11] { + elements: { + CREATE_LIST [12] { + elements: { + IDENT [13] { + name: @index1 + } + IDENT [14] { + name: @index1 + } + } + } + } + } + } + } + COMPREHENSION [15] { + iter_var: @c1:0 + iter_range: { + CREATE_LIST [16] { + elements: { + CONSTANT [17] { value: "foo" } + CONSTANT [18] { value: "bar" } + } + } + } + accu_var: @x1:0 + accu_init: { + CREATE_LIST [19] { + elements: { + } + } + } + loop_condition: { + CONSTANT [20] { value: true } + } + loop_step: { + CALL [21] { + function: _+_ + args: { + IDENT [22] { + name: @x1:0 + } + CREATE_LIST [23] { + elements: { + CREATE_LIST [24] { + elements: { + IDENT [25] { + name: @index0 + } + IDENT [26] { + name: @index0 + } + } + } + } + } + } + } + } + result: { + IDENT [27] { + name: @x1:0 + } + } + } + } + } + COMPREHENSION [28] { + iter_var: @c0:0 + iter_range: { + IDENT [29] { + name: @index3 + } + } + accu_var: @x0:0 + accu_init: { + CREATE_LIST [30] { + elements: { + } + } + } + loop_condition: { + CONSTANT [31] { value: true } + } + loop_step: { + IDENT [32] { + name: @index2 + } + } + result: { + IDENT [33] { + name: @x0:0 + } + } + } + } +} +Test case: PRESENCE_TEST +Source: has({'a': true}.a) && {'a':true}['a'] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: "a" } + } + value: { + CONSTANT [6] { value: true } + } + } + } + CALL [7] { + function: _[_] + args: { + IDENT [8] { + name: @index0 + } + CONSTANT [9] { value: "a" } + } + } + } + } + CALL [10] { + function: _&&_ + args: { + SELECT [11] { + IDENT [12] { + name: @index0 + }.a~presence_test + } + IDENT [13] { + name: @index1 + } + } + } + } +} +Test case: PRESENCE_TEST_WITH_TERNARY +Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : 0) == 10 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + CALL [5] { + function: _?_:_ + args: { + SELECT [6] { + IDENT [7] { + name: @index0 + }.payload~presence_test + } + SELECT [8] { + SELECT [9] { + IDENT [10] { + name: @index0 + }.payload + }.single_int64 + } + CONSTANT [11] { value: 0 } + } + } + } + } + CALL [12] { + function: _==_ + args: { + IDENT [13] { + name: @index1 + } + CONSTANT [14] { value: 10 } + } + } + } +} +Test case: PRESENCE_TEST_WITH_TERNARY_2 +Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : msg.oneof_type.payload.single_int64 * 0) == 10 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.single_int64 + } + CALL [9] { + function: _?_:_ + args: { + SELECT [10] { + IDENT [11] { + name: @index0 + }.payload~presence_test + } + IDENT [12] { + name: @index2 + } + CALL [13] { + function: _*_ + args: { + IDENT [14] { + name: @index2 + } + CONSTANT [15] { value: 0 } + } + } + } + } + } + } + CALL [16] { + function: _==_ + args: { + IDENT [17] { + name: @index3 + } + CONSTANT [18] { value: 10 } + } + } + } +} +Test case: PRESENCE_TEST_WITH_TERNARY_3 +Source: (has(msg.oneof_type.payload.single_int64) ? msg.oneof_type.payload.single_int64 : msg.oneof_type.payload.single_int64 * 0) == 10 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.single_int64 + } + CALL [9] { + function: _?_:_ + args: { + SELECT [10] { + IDENT [11] { + name: @index1 + }.single_int64~presence_test + } + IDENT [12] { + name: @index2 + } + CALL [13] { + function: _*_ + args: { + IDENT [14] { + name: @index2 + } + CONSTANT [15] { value: 0 } + } + } + } + } + } + } + CALL [16] { + function: _==_ + args: { + IDENT [17] { + name: @index3 + } + CONSTANT [18] { value: 10 } + } + } + } +} +Test case: PRESENCE_TEST_WITH_TERNARY_NESTED +Source: (has(msg.oneof_type) && has(msg.oneof_type.payload) && has(msg.oneof_type.payload.single_int64)) ? ((has(msg.oneof_type.payload.map_string_string) && has(msg.oneof_type.payload.map_string_string.key)) ? msg.oneof_type.payload.map_string_string.key == 'A' : false) : false +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.map_string_string + } + CALL [9] { + function: _?_:_ + args: { + CALL [10] { + function: _&&_ + args: { + SELECT [11] { + IDENT [12] { + name: @index1 + }.map_string_string~presence_test + } + SELECT [13] { + IDENT [14] { + name: @index2 + }.key~presence_test + } + } + } + CALL [15] { + function: _==_ + args: { + SELECT [16] { + IDENT [17] { + name: @index2 + }.key + } + CONSTANT [18] { value: "A" } + } + } + CONSTANT [19] { value: false } + } + } + CALL [20] { + function: _&&_ + args: { + CALL [21] { + function: _&&_ + args: { + SELECT [22] { + IDENT [23] { + name: msg + }.oneof_type~presence_test + } + SELECT [24] { + IDENT [25] { + name: @index0 + }.payload~presence_test + } + } + } + SELECT [26] { + IDENT [27] { + name: @index1 + }.single_int64~presence_test + } + } + } + } + } + CALL [28] { + function: _?_:_ + args: { + IDENT [29] { + name: @index4 + } + IDENT [30] { + name: @index3 + } + CONSTANT [31] { value: false } + } + } + } +} +Test case: OPTIONAL_LIST +Source: [10, ?optional.none(), [?optional.none(), ?opt_x], [?optional.none(), ?opt_x]] == [10, [5], [5]] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: optional.none + args: { + } + } + CREATE_LIST [4] { + elements: { + IDENT [5] { + name: @index0 + } + IDENT [6] { + name: opt_x + } + } + optional_indices: [0, 1] + } + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 5 } + } + } + CREATE_LIST [9] { + elements: { + CONSTANT [10] { value: 10 } + IDENT [11] { + name: @index2 + } + IDENT [12] { + name: @index2 + } + } + } + CREATE_LIST [13] { + elements: { + CONSTANT [14] { value: 10 } + IDENT [15] { + name: @index0 + } + IDENT [16] { + name: @index1 + } + IDENT [17] { + name: @index1 + } + } + optional_indices: [0] + } + } + } + CALL [18] { + function: _==_ + args: { + IDENT [19] { + name: @index4 + } + IDENT [20] { + name: @index3 + } + } + } + } +} +Test case: OPTIONAL_MAP +Source: {?'hello': optional.of('hello')}['hello'] + {?'hello': optional.of('hello')}['hello'] == 'hellohello' +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: optional.of + args: { + CONSTANT [4] { value: "hello" } + } + } + CREATE_MAP [5] { + MAP_ENTRY [6] { + key: { + CONSTANT [7] { value: "hello" } + } + optional_entry: true + value: { + IDENT [8] { + name: @index0 + } + } + } + } + CALL [9] { + function: _[_] + args: { + IDENT [10] { + name: @index1 + } + CONSTANT [11] { value: "hello" } + } + } + CALL [12] { + function: _+_ + args: { + IDENT [13] { + name: @index2 + } + IDENT [14] { + name: @index2 + } + } + } + } + } + CALL [15] { + function: _==_ + args: { + IDENT [16] { + name: @index3 + } + CONSTANT [17] { value: "hellohello" } + } + } + } +} +Test case: OPTIONAL_MAP_CHAINED +Source: {?'key': optional.of('test')}[?'bogus'].or({'key': 'test'}[?'bogus']).orValue({'key': 'test'}['key']) == 'test' +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: "key" } + } + value: { + CONSTANT [6] { value: "test" } + } + } + } + CALL [7] { + function: orValue + target: { + CALL [8] { + function: or + target: { + CALL [9] { + function: _[?_] + args: { + CREATE_MAP [10] { + MAP_ENTRY [11] { + key: { + CONSTANT [12] { value: "key" } + } + optional_entry: true + value: { + CALL [13] { + function: optional.of + args: { + CONSTANT [14] { value: "test" } + } + } + } + } + } + CONSTANT [15] { value: "bogus" } + } + } + } + args: { + CALL [16] { + function: _[?_] + args: { + IDENT [17] { + name: @index0 + } + CONSTANT [18] { value: "bogus" } + } + } + } + } + } + args: { + CALL [19] { + function: _[_] + args: { + IDENT [20] { + name: @index0 + } + CONSTANT [21] { value: "key" } + } + } + } + } + } + } + CALL [22] { + function: _==_ + args: { + IDENT [23] { + name: @index1 + } + CONSTANT [24] { value: "test" } + } + } + } +} +Test case: OPTIONAL_MESSAGE +Source: TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}.single_int32 + TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}.single_int64 == 5 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: optional.ofNonZeroValue + args: { + CONSTANT [4] { value: 1 } + } + } + CALL [5] { + function: optional.of + args: { + CONSTANT [6] { value: 4 } + } + } + CREATE_STRUCT [7] { + name: TestAllTypes + entries: { + ENTRY [8] { + field_key: single_int64 + optional_entry: true + value: { + IDENT [9] { + name: @index0 + } + } + } + ENTRY [10] { + field_key: single_int32 + optional_entry: true + value: { + IDENT [11] { + name: @index1 + } + } + } + } + } + CALL [12] { + function: _+_ + args: { + SELECT [13] { + IDENT [14] { + name: @index2 + }.single_int32 + } + SELECT [15] { + IDENT [16] { + name: @index2 + }.single_int64 + } + } + } + } + } + CALL [17] { + function: _==_ + args: { + IDENT [18] { + name: @index3 + } + CONSTANT [19] { value: 5 } + } + } + } +} +Test case: CALL +Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('h' + 'e' + 'l' + 'l' + 'o') +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _+_ + args: { + CONSTANT [4] { value: "h" } + CONSTANT [5] { value: "e" } + } + } + CALL [6] { + function: _+_ + args: { + IDENT [7] { + name: @index0 + } + CONSTANT [8] { value: "l" } + } + } + CALL [9] { + function: _+_ + args: { + IDENT [10] { + name: @index1 + } + CONSTANT [11] { value: "l" } + } + } + CALL [12] { + function: _+_ + args: { + IDENT [13] { + name: @index2 + } + CONSTANT [14] { value: "o" } + } + } + CALL [15] { + function: _+_ + args: { + IDENT [16] { + name: @index3 + } + CONSTANT [17] { value: " world" } + } + } + } + } + CALL [18] { + function: matches + target: { + IDENT [19] { + name: @index4 + } + } + args: { + IDENT [20] { + name: @index3 + } + } + } + } +} +Test case: CALL_ARGUMENT_NESTED_NO_COMMON_SUBEXPR +Source: 'hello world'.matches('h' + 'e' + 'l' + 'l' + 'o') +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _+_ + args: { + CALL [4] { + function: _+_ + args: { + CALL [5] { + function: _+_ + args: { + CALL [6] { + function: _+_ + args: { + CONSTANT [7] { value: "h" } + CONSTANT [8] { value: "e" } + } + } + CONSTANT [9] { value: "l" } + } + } + CONSTANT [10] { value: "l" } + } + } + CONSTANT [11] { value: "o" } + } + } + } + } + CALL [12] { + function: matches + target: { + CONSTANT [13] { value: "hello world" } + } + args: { + IDENT [14] { + name: @index0 + } + } + } + } +} +Test case: CALL_TARGET_NESTED_NO_COMMON_SUBEXPR +Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('hello') +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _+_ + args: { + CALL [4] { + function: _+_ + args: { + CALL [5] { + function: _+_ + args: { + CALL [6] { + function: _+_ + args: { + CALL [7] { + function: _+_ + args: { + CONSTANT [8] { value: "h" } + CONSTANT [9] { value: "e" } + } + } + CONSTANT [10] { value: "l" } + } + } + CONSTANT [11] { value: "l" } + } + } + CONSTANT [12] { value: "o" } + } + } + CONSTANT [13] { value: " world" } + } + } + } + } + CALL [14] { + function: matches + target: { + IDENT [15] { + name: @index0 + } + } + args: { + CONSTANT [16] { value: "hello" } + } + } + } +} +Test case: CALL_BOTH_ARGUMENT_TARGET_NESTED_NO_COMMON_SUBEXPR +Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('w' + 'o' + 'r' + 'l' + 'd') +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _+_ + args: { + CALL [4] { + function: _+_ + args: { + CALL [5] { + function: _+_ + args: { + CALL [6] { + function: _+_ + args: { + CONSTANT [7] { value: "w" } + CONSTANT [8] { value: "o" } + } + } + CONSTANT [9] { value: "r" } + } + } + CONSTANT [10] { value: "l" } + } + } + CONSTANT [11] { value: "d" } + } + } + CALL [12] { + function: _+_ + args: { + CALL [13] { + function: _+_ + args: { + CALL [14] { + function: _+_ + args: { + CALL [15] { + function: _+_ + args: { + CALL [16] { + function: _+_ + args: { + CONSTANT [17] { value: "h" } + CONSTANT [18] { value: "e" } + } + } + CONSTANT [19] { value: "l" } + } + } + CONSTANT [20] { value: "l" } + } + } + CONSTANT [21] { value: "o" } + } + } + CONSTANT [22] { value: " world" } + } + } + } + } + CALL [23] { + function: matches + target: { + IDENT [24] { + name: @index1 + } + } + args: { + IDENT [25] { + name: @index0 + } + } + } + } +} diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_7.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_7.baseline new file mode 100644 index 000000000..c318f8779 --- /dev/null +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_7.baseline @@ -0,0 +1,3287 @@ +Test case: SIZE_1 +Source: size([1,2]) + size([1,2]) + 1 == 5 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + } + } + CALL [6] { + function: size + args: { + IDENT [7] { + name: @index0 + } + } + } + CALL [8] { + function: _+_ + args: { + CALL [9] { + function: _+_ + args: { + IDENT [10] { + name: @index1 + } + IDENT [11] { + name: @index1 + } + } + } + CONSTANT [12] { value: 1 } + } + } + } + } + CALL [13] { + function: _==_ + args: { + IDENT [14] { + name: @index2 + } + CONSTANT [15] { value: 5 } + } + } + } +} +Test case: SIZE_2 +Source: 2 + size([1,2]) + size([1,2]) + 1 == 7 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + } + } + CALL [6] { + function: size + args: { + IDENT [7] { + name: @index0 + } + } + } + CALL [8] { + function: _+_ + args: { + CALL [9] { + function: _+_ + args: { + CALL [10] { + function: _+_ + args: { + CONSTANT [11] { value: 2 } + IDENT [12] { + name: @index1 + } + } + } + IDENT [13] { + name: @index1 + } + } + } + CONSTANT [14] { value: 1 } + } + } + } + } + CALL [15] { + function: _==_ + args: { + IDENT [16] { + name: @index2 + } + CONSTANT [17] { value: 7 } + } + } + } +} +Test case: SIZE_3 +Source: size([0]) + size([0]) + size([1,2]) + size([1,2]) == 6 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 0 } + } + } + CALL [5] { + function: size + args: { + IDENT [6] { + name: @index0 + } + } + } + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 1 } + CONSTANT [9] { value: 2 } + } + } + CALL [10] { + function: size + args: { + IDENT [11] { + name: @index2 + } + } + } + CALL [12] { + function: _+_ + args: { + CALL [13] { + function: _+_ + args: { + CALL [14] { + function: _+_ + args: { + IDENT [15] { + name: @index1 + } + IDENT [16] { + name: @index1 + } + } + } + IDENT [17] { + name: @index3 + } + } + } + IDENT [18] { + name: @index3 + } + } + } + } + } + CALL [19] { + function: _==_ + args: { + IDENT [20] { + name: @index4 + } + CONSTANT [21] { value: 6 } + } + } + } +} +Test case: SIZE_4 +Source: 5 + size([0]) + size([0]) + size([1,2]) + size([1,2]) + size([1,2,3]) + size([1,2,3]) == 17 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 0 } + } + } + CALL [5] { + function: size + args: { + IDENT [6] { + name: @index0 + } + } + } + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 1 } + CONSTANT [9] { value: 2 } + } + } + CALL [10] { + function: size + args: { + IDENT [11] { + name: @index2 + } + } + } + CREATE_LIST [12] { + elements: { + CONSTANT [13] { value: 1 } + CONSTANT [14] { value: 2 } + CONSTANT [15] { value: 3 } + } + } + CALL [16] { + function: size + args: { + IDENT [17] { + name: @index4 + } + } + } + CALL [18] { + function: _+_ + args: { + CALL [19] { + function: _+_ + args: { + CALL [20] { + function: _+_ + args: { + CALL [21] { + function: _+_ + args: { + CALL [22] { + function: _+_ + args: { + CALL [23] { + function: _+_ + args: { + CONSTANT [24] { value: 5 } + IDENT [25] { + name: @index1 + } + } + } + IDENT [26] { + name: @index1 + } + } + } + IDENT [27] { + name: @index3 + } + } + } + IDENT [28] { + name: @index3 + } + } + } + IDENT [29] { + name: @index5 + } + } + } + IDENT [30] { + name: @index5 + } + } + } + } + } + CALL [31] { + function: _==_ + args: { + IDENT [32] { + name: @index6 + } + CONSTANT [33] { value: 17 } + } + } + } +} +Test case: TIMESTAMP +Source: timestamp(int(timestamp(1000000000))).getFullYear() + timestamp(int(timestamp(75))).getFullYear() + timestamp(int(timestamp(50))).getFullYear() + timestamp(int(timestamp(1000000000))).getFullYear() + timestamp(int(timestamp(50))).getSeconds() + timestamp(int(timestamp(200))).getFullYear() + timestamp(int(timestamp(200))).getFullYear() + timestamp(int(timestamp(75))).getMinutes() + timestamp(int(timestamp(1000000000))).getFullYear() == 13934 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: timestamp + args: { + CONSTANT [4] { value: 1000000000 } + } + } + CALL [5] { + function: int + args: { + IDENT [6] { + name: @index0 + } + } + } + CALL [7] { + function: timestamp + args: { + IDENT [8] { + name: @index1 + } + } + } + CALL [9] { + function: getFullYear + target: { + IDENT [10] { + name: @index2 + } + } + args: { + } + } + CALL [11] { + function: timestamp + args: { + CONSTANT [12] { value: 50 } + } + } + CALL [13] { + function: int + args: { + IDENT [14] { + name: @index4 + } + } + } + CALL [15] { + function: timestamp + args: { + IDENT [16] { + name: @index5 + } + } + } + CALL [17] { + function: timestamp + args: { + CONSTANT [18] { value: 200 } + } + } + CALL [19] { + function: int + args: { + IDENT [20] { + name: @index7 + } + } + } + CALL [21] { + function: timestamp + args: { + IDENT [22] { + name: @index8 + } + } + } + CALL [23] { + function: getFullYear + target: { + IDENT [24] { + name: @index9 + } + } + args: { + } + } + CALL [25] { + function: timestamp + args: { + CONSTANT [26] { value: 75 } + } + } + CALL [27] { + function: int + args: { + IDENT [28] { + name: @index11 + } + } + } + CALL [29] { + function: timestamp + args: { + IDENT [30] { + name: @index12 + } + } + } + CALL [31] { + function: getMinutes + target: { + IDENT [32] { + name: @index13 + } + } + args: { + } + } + CALL [33] { + function: _+_ + args: { + CALL [34] { + function: _+_ + args: { + CALL [35] { + function: _+_ + args: { + CALL [36] { + function: _+_ + args: { + CALL [37] { + function: _+_ + args: { + CALL [38] { + function: _+_ + args: { + IDENT [39] { + name: @index3 + } + CALL [40] { + function: getFullYear + target: { + IDENT [41] { + name: @index13 + } + } + args: { + } + } + } + } + CALL [42] { + function: getFullYear + target: { + IDENT [43] { + name: @index6 + } + } + args: { + } + } + } + } + IDENT [44] { + name: @index3 + } + } + } + CALL [45] { + function: getSeconds + target: { + IDENT [46] { + name: @index6 + } + } + args: { + } + } + } + } + IDENT [47] { + name: @index10 + } + } + } + IDENT [48] { + name: @index10 + } + } + } + CALL [49] { + function: _+_ + args: { + CALL [50] { + function: _+_ + args: { + IDENT [51] { + name: @index15 + } + IDENT [52] { + name: @index14 + } + } + } + IDENT [53] { + name: @index3 + } + } + } + } + } + CALL [54] { + function: _==_ + args: { + IDENT [55] { + name: @index16 + } + CONSTANT [56] { value: 13934 } + } + } + } +} +Test case: MAP_INDEX +Source: {"a": 2}["a"] + {"a": 2}["a"] * {"a": 2}["a"] == 6 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: "a" } + } + value: { + CONSTANT [6] { value: 2 } + } + } + } + CALL [7] { + function: _[_] + args: { + IDENT [8] { + name: @index0 + } + CONSTANT [9] { value: "a" } + } + } + CALL [10] { + function: _+_ + args: { + IDENT [11] { + name: @index1 + } + CALL [12] { + function: _*_ + args: { + IDENT [13] { + name: @index1 + } + IDENT [14] { + name: @index1 + } + } + } + } + } + } + } + CALL [15] { + function: _==_ + args: { + IDENT [16] { + name: @index2 + } + CONSTANT [17] { value: 6 } + } + } + } +} +Test case: NESTED_MAP_CONSTRUCTION +Source: {'a': {'b': 1}, 'c': {'b': 1}, 'd': {'e': {'b': 1}}, 'e': {'e': {'b': 1}}} +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: "b" } + } + value: { + CONSTANT [6] { value: 1 } + } + } + } + CREATE_MAP [7] { + MAP_ENTRY [8] { + key: { + CONSTANT [9] { value: "e" } + } + value: { + IDENT [10] { + name: @index0 + } + } + } + } + } + } + CREATE_MAP [11] { + MAP_ENTRY [12] { + key: { + CONSTANT [13] { value: "a" } + } + value: { + IDENT [14] { + name: @index0 + } + } + } + MAP_ENTRY [15] { + key: { + CONSTANT [16] { value: "c" } + } + value: { + IDENT [17] { + name: @index0 + } + } + } + MAP_ENTRY [18] { + key: { + CONSTANT [19] { value: "d" } + } + value: { + IDENT [20] { + name: @index1 + } + } + } + MAP_ENTRY [21] { + key: { + CONSTANT [22] { value: "e" } + } + value: { + IDENT [23] { + name: @index1 + } + } + } + } + } +} +Test case: NESTED_LIST_CONSTRUCTION +Source: [1, [1,2,3,4], 2, [1,2,3,4], 5, [1,2,3,4], 7, [[1,2], [1,2,3,4]], [1,2]] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + CONSTANT [6] { value: 3 } + CONSTANT [7] { value: 4 } + } + } + CREATE_LIST [8] { + elements: { + CONSTANT [9] { value: 1 } + CONSTANT [10] { value: 2 } + } + } + CREATE_LIST [11] { + elements: { + IDENT [12] { + name: @index1 + } + IDENT [13] { + name: @index0 + } + } + } + } + } + CREATE_LIST [14] { + elements: { + CONSTANT [15] { value: 1 } + IDENT [16] { + name: @index0 + } + CONSTANT [17] { value: 2 } + IDENT [18] { + name: @index0 + } + CONSTANT [19] { value: 5 } + IDENT [20] { + name: @index0 + } + CONSTANT [21] { value: 7 } + IDENT [22] { + name: @index2 + } + IDENT [23] { + name: @index1 + } + } + } + } +} +Test case: SELECT +Source: msg.single_int64 + msg.single_int64 == 6 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.single_int64 + } + CALL [5] { + function: _+_ + args: { + IDENT [6] { + name: @index0 + } + IDENT [7] { + name: @index0 + } + } + } + } + } + CALL [8] { + function: _==_ + args: { + IDENT [9] { + name: @index1 + } + CONSTANT [10] { value: 6 } + } + } + } +} +Test case: SELECT_NESTED_1 +Source: msg.oneof_type.payload.single_int64 + msg.oneof_type.payload.single_int32 + msg.oneof_type.payload.single_int64 + msg.single_int64 + msg.oneof_type.payload.oneof_type.payload.single_int64 == 31 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.single_int64 + } + CALL [9] { + function: _+_ + args: { + CALL [10] { + function: _+_ + args: { + CALL [11] { + function: _+_ + args: { + CALL [12] { + function: _+_ + args: { + IDENT [13] { + name: @index2 + } + SELECT [14] { + IDENT [15] { + name: @index1 + }.single_int32 + } + } + } + IDENT [16] { + name: @index2 + } + } + } + SELECT [17] { + IDENT [18] { + name: msg + }.single_int64 + } + } + } + SELECT [19] { + SELECT [20] { + SELECT [21] { + IDENT [22] { + name: @index1 + }.oneof_type + }.payload + }.single_int64 + } + } + } + } + } + CALL [23] { + function: _==_ + args: { + IDENT [24] { + name: @index3 + } + CONSTANT [25] { value: 31 } + } + } + } +} +Test case: SELECT_NESTED_2 +Source: true || msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload.single_bool || msg.oneof_type.payload.oneof_type.payload.oneof_type.child.child.payload.single_bool +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.oneof_type + } + SELECT [9] { + IDENT [10] { + name: @index2 + }.payload + } + SELECT [11] { + IDENT [12] { + name: @index3 + }.oneof_type + } + SELECT [13] { + SELECT [14] { + SELECT [15] { + SELECT [16] { + IDENT [17] { + name: @index4 + }.child + }.child + }.payload + }.single_bool + } + CALL [18] { + function: _||_ + args: { + CONSTANT [19] { value: true } + SELECT [20] { + SELECT [21] { + SELECT [22] { + SELECT [23] { + IDENT [24] { + name: @index4 + }.payload + }.oneof_type + }.payload + }.single_bool + } + } + } + } + } + CALL [25] { + function: _||_ + args: { + IDENT [26] { + name: @index6 + } + IDENT [27] { + name: @index5 + } + } + } + } +} +Test case: SELECT_NESTED_MESSAGE_MAP_INDEX_1 +Source: msg.oneof_type.payload.map_int32_int64[1] + msg.oneof_type.payload.map_int32_int64[1] + msg.oneof_type.payload.map_int32_int64[1] == 15 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.map_int32_int64 + } + CALL [9] { + function: _[_] + args: { + IDENT [10] { + name: @index2 + } + CONSTANT [11] { value: 1 } + } + } + CALL [12] { + function: _+_ + args: { + CALL [13] { + function: _+_ + args: { + IDENT [14] { + name: @index3 + } + IDENT [15] { + name: @index3 + } + } + } + IDENT [16] { + name: @index3 + } + } + } + } + } + CALL [17] { + function: _==_ + args: { + IDENT [18] { + name: @index4 + } + CONSTANT [19] { value: 15 } + } + } + } +} +Test case: SELECT_NESTED_MESSAGE_MAP_INDEX_2 +Source: msg.oneof_type.payload.map_int32_int64[0] + msg.oneof_type.payload.map_int32_int64[1] + msg.oneof_type.payload.map_int32_int64[2] == 8 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.map_int32_int64 + } + CALL [9] { + function: _+_ + args: { + CALL [10] { + function: _+_ + args: { + CALL [11] { + function: _[_] + args: { + IDENT [12] { + name: @index2 + } + CONSTANT [13] { value: 0 } + } + } + CALL [14] { + function: _[_] + args: { + IDENT [15] { + name: @index2 + } + CONSTANT [16] { value: 1 } + } + } + } + } + CALL [17] { + function: _[_] + args: { + IDENT [18] { + name: @index2 + } + CONSTANT [19] { value: 2 } + } + } + } + } + } + } + CALL [20] { + function: _==_ + args: { + IDENT [21] { + name: @index3 + } + CONSTANT [22] { value: 8 } + } + } + } +} +Test case: SELECT_NESTED_NO_COMMON_SUBEXPR +Source: msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload.single_int64 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + SELECT [4] { + SELECT [5] { + SELECT [6] { + SELECT [7] { + SELECT [8] { + SELECT [9] { + IDENT [10] { + name: msg + }.oneof_type + }.payload + }.oneof_type + }.payload + }.oneof_type + }.payload + }.oneof_type + } + SELECT [11] { + IDENT [12] { + name: @index0 + }.payload + } + } + } + SELECT [13] { + IDENT [14] { + name: @index1 + }.single_int64 + } + } +} +Test case: TERNARY +Source: (msg.single_int64 > 0 ? msg.single_int64 : 0) == 3 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.single_int64 + } + CALL [5] { + function: _?_:_ + args: { + CALL [6] { + function: _>_ + args: { + IDENT [7] { + name: @index0 + } + CONSTANT [8] { value: 0 } + } + } + IDENT [9] { + name: @index0 + } + CONSTANT [10] { value: 0 } + } + } + } + } + CALL [11] { + function: _==_ + args: { + IDENT [12] { + name: @index1 + } + CONSTANT [13] { value: 3 } + } + } + } +} +Test case: TERNARY_BIND_RHS_ONLY +Source: false ? false : (msg.single_int64) + ((msg.single_int64 + 1) * 2) == 11 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.single_int64 + } + CALL [5] { + function: _==_ + args: { + CALL [6] { + function: _+_ + args: { + IDENT [7] { + name: @index0 + } + CALL [8] { + function: _*_ + args: { + CALL [9] { + function: _+_ + args: { + IDENT [10] { + name: @index0 + } + CONSTANT [11] { value: 1 } + } + } + CONSTANT [12] { value: 2 } + } + } + } + } + CONSTANT [13] { value: 11 } + } + } + } + } + CALL [14] { + function: _?_:_ + args: { + CONSTANT [15] { value: false } + CONSTANT [16] { value: false } + IDENT [17] { + name: @index1 + } + } + } + } +} +Test case: NESTED_TERNARY +Source: (msg.single_int64 > 0 ? (msg.single_int32 > 0 ? msg.single_int64 + msg.single_int32 : 0) : 0) == 8 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.single_int64 + } + SELECT [5] { + IDENT [6] { + name: msg + }.single_int32 + } + CALL [7] { + function: _?_:_ + args: { + CALL [8] { + function: _>_ + args: { + IDENT [9] { + name: @index0 + } + CONSTANT [10] { value: 0 } + } + } + CALL [11] { + function: _?_:_ + args: { + CALL [12] { + function: _>_ + args: { + IDENT [13] { + name: @index1 + } + CONSTANT [14] { value: 0 } + } + } + CALL [15] { + function: _+_ + args: { + IDENT [16] { + name: @index0 + } + IDENT [17] { + name: @index1 + } + } + } + CONSTANT [18] { value: 0 } + } + } + CONSTANT [19] { value: 0 } + } + } + } + } + CALL [20] { + function: _==_ + args: { + IDENT [21] { + name: @index2 + } + CONSTANT [22] { value: 8 } + } + } + } +} +Test case: MULTIPLE_MACROS_1 +Source: size([[1].exists(i, i > 0)]) + size([[1].exists(j, j > 0)]) + size([[2].exists(k, k > 1)]) + size([[2].exists(l, l > 1)]) == 4 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + } + } + CALL [5] { + function: _>_ + args: { + IDENT [6] { + name: @c0:0 + } + CONSTANT [7] { value: 0 } + } + } + CALL [8] { + function: _||_ + args: { + IDENT [9] { + name: @x0:0 + } + IDENT [10] { + name: @index1 + } + } + } + COMPREHENSION [11] { + iter_var: @c0:0 + iter_range: { + IDENT [12] { + name: @index0 + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [13] { value: false } + } + loop_condition: { + CALL [14] { + function: @not_strictly_false + args: { + CALL [15] { + function: !_ + args: { + IDENT [16] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + IDENT [17] { + name: @index2 + } + } + result: { + IDENT [18] { + name: @x0:0 + } + } + } + CREATE_LIST [19] { + elements: { + IDENT [20] { + name: @index3 + } + } + } + CALL [21] { + function: size + args: { + IDENT [22] { + name: @index4 + } + } + } + CREATE_LIST [23] { + elements: { + CONSTANT [24] { value: 2 } + } + } + CALL [25] { + function: _>_ + args: { + IDENT [26] { + name: @c0:0 + } + CONSTANT [27] { value: 1 } + } + } + CALL [28] { + function: _||_ + args: { + IDENT [29] { + name: @x0:0 + } + IDENT [30] { + name: @index7 + } + } + } + COMPREHENSION [31] { + iter_var: @c0:0 + iter_range: { + IDENT [32] { + name: @index6 + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [33] { value: false } + } + loop_condition: { + CALL [34] { + function: @not_strictly_false + args: { + CALL [35] { + function: !_ + args: { + IDENT [36] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + IDENT [37] { + name: @index8 + } + } + result: { + IDENT [38] { + name: @x0:0 + } + } + } + CREATE_LIST [39] { + elements: { + IDENT [40] { + name: @index9 + } + } + } + CALL [41] { + function: size + args: { + IDENT [42] { + name: @index10 + } + } + } + CALL [43] { + function: _+_ + args: { + CALL [44] { + function: _+_ + args: { + CALL [45] { + function: _+_ + args: { + IDENT [46] { + name: @index5 + } + IDENT [47] { + name: @index5 + } + } + } + IDENT [48] { + name: @index11 + } + } + } + IDENT [49] { + name: @index11 + } + } + } + } + } + CALL [50] { + function: _==_ + args: { + IDENT [51] { + name: @index12 + } + CONSTANT [52] { value: 4 } + } + } + } +} +Test case: MULTIPLE_MACROS_2 +Source: [[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == 'a')] + [['a'].exists(l, l == 'a')] == [true, true, true, true] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + } + } + CALL [5] { + function: _>_ + args: { + IDENT [6] { + name: @c0:0 + } + CONSTANT [7] { value: 0 } + } + } + CALL [8] { + function: _||_ + args: { + IDENT [9] { + name: @x0:0 + } + IDENT [10] { + name: @index1 + } + } + } + COMPREHENSION [11] { + iter_var: @c0:0 + iter_range: { + IDENT [12] { + name: @index0 + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [13] { value: false } + } + loop_condition: { + CALL [14] { + function: @not_strictly_false + args: { + CALL [15] { + function: !_ + args: { + IDENT [16] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + IDENT [17] { + name: @index2 + } + } + result: { + IDENT [18] { + name: @x0:0 + } + } + } + CREATE_LIST [19] { + elements: { + IDENT [20] { + name: @index3 + } + } + } + CREATE_LIST [21] { + elements: { + CONSTANT [22] { value: "a" } + } + } + CALL [23] { + function: _==_ + args: { + IDENT [24] { + name: @c0:1 + } + CONSTANT [25] { value: "a" } + } + } + CALL [26] { + function: _||_ + args: { + IDENT [27] { + name: @x0:1 + } + IDENT [28] { + name: @index6 + } + } + } + COMPREHENSION [29] { + iter_var: @c0:1 + iter_range: { + IDENT [30] { + name: @index5 + } + } + accu_var: @x0:1 + accu_init: { + CONSTANT [31] { value: false } + } + loop_condition: { + CALL [32] { + function: @not_strictly_false + args: { + CALL [33] { + function: !_ + args: { + IDENT [34] { + name: @x0:1 + } + } + } + } + } + } + loop_step: { + IDENT [35] { + name: @index7 + } + } + result: { + IDENT [36] { + name: @x0:1 + } + } + } + CREATE_LIST [37] { + elements: { + IDENT [38] { + name: @index8 + } + } + } + CREATE_LIST [39] { + elements: { + CONSTANT [40] { value: true } + CONSTANT [41] { value: true } + CONSTANT [42] { value: true } + CONSTANT [43] { value: true } + } + } + CALL [44] { + function: _+_ + args: { + CALL [45] { + function: _+_ + args: { + CALL [46] { + function: _+_ + args: { + IDENT [47] { + name: @index4 + } + IDENT [48] { + name: @index4 + } + } + } + IDENT [49] { + name: @index9 + } + } + } + IDENT [50] { + name: @index9 + } + } + } + } + } + CALL [51] { + function: _==_ + args: { + IDENT [52] { + name: @index11 + } + IDENT [53] { + name: @index10 + } + } + } + } +} +Test case: NESTED_MACROS +Source: [1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [[2, 3, 4], [2, 3, 4], [2, 3, 4]] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + CONSTANT [6] { value: 3 } + } + } + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 2 } + CONSTANT [9] { value: 3 } + CONSTANT [10] { value: 4 } + } + } + CREATE_LIST [11] { + elements: { + IDENT [12] { + name: @index1 + } + IDENT [13] { + name: @index1 + } + IDENT [14] { + name: @index1 + } + } + } + COMPREHENSION [15] { + iter_var: @c0:0 + iter_range: { + IDENT [16] { + name: @index0 + } + } + accu_var: @x0:0 + accu_init: { + CREATE_LIST [17] { + elements: { + } + } + } + loop_condition: { + CONSTANT [18] { value: true } + } + loop_step: { + CALL [19] { + function: _+_ + args: { + IDENT [20] { + name: @x0:0 + } + CREATE_LIST [21] { + elements: { + COMPREHENSION [22] { + iter_var: @c1:0 + iter_range: { + IDENT [23] { + name: @index0 + } + } + accu_var: @x1:0 + accu_init: { + CREATE_LIST [24] { + elements: { + } + } + } + loop_condition: { + CONSTANT [25] { value: true } + } + loop_step: { + CALL [26] { + function: _+_ + args: { + IDENT [27] { + name: @x1:0 + } + CREATE_LIST [28] { + elements: { + CALL [29] { + function: _+_ + args: { + IDENT [30] { + name: @c1:0 + } + CONSTANT [31] { value: 1 } + } + } + } + } + } + } + } + result: { + IDENT [32] { + name: @x1:0 + } + } + } + } + } + } + } + } + result: { + IDENT [33] { + name: @x0:0 + } + } + } + } + } + CALL [34] { + function: _==_ + args: { + IDENT [35] { + name: @index3 + } + IDENT [36] { + name: @index2 + } + } + } + } +} +Test case: NESTED_MACROS_2 +Source: [1, 2].map(y, [1, 2, 3].filter(x, x == y)) == [[1], [2]] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CREATE_LIST [4] { + elements: { + CONSTANT [5] { value: 1 } + } + } + CREATE_LIST [6] { + elements: { + CONSTANT [7] { value: 2 } + } + } + } + } + COMPREHENSION [8] { + iter_var: @c0:0 + iter_range: { + CREATE_LIST [9] { + elements: { + CONSTANT [10] { value: 1 } + CONSTANT [11] { value: 2 } + } + } + } + accu_var: @x0:0 + accu_init: { + CREATE_LIST [12] { + elements: { + } + } + } + loop_condition: { + CONSTANT [13] { value: true } + } + loop_step: { + CALL [14] { + function: _+_ + args: { + IDENT [15] { + name: @x0:0 + } + CREATE_LIST [16] { + elements: { + COMPREHENSION [17] { + iter_var: @c1:0 + iter_range: { + CREATE_LIST [18] { + elements: { + CONSTANT [19] { value: 1 } + CONSTANT [20] { value: 2 } + CONSTANT [21] { value: 3 } + } + } + } + accu_var: @x1:0 + accu_init: { + CREATE_LIST [22] { + elements: { + } + } + } + loop_condition: { + CONSTANT [23] { value: true } + } + loop_step: { + CALL [24] { + function: _?_:_ + args: { + CALL [25] { + function: _==_ + args: { + IDENT [26] { + name: @c1:0 + } + IDENT [27] { + name: @c0:0 + } + } + } + CALL [28] { + function: _+_ + args: { + IDENT [29] { + name: @x1:0 + } + CREATE_LIST [30] { + elements: { + IDENT [31] { + name: @c1:0 + } + } + } + } + } + IDENT [32] { + name: @x1:0 + } + } + } + } + result: { + IDENT [33] { + name: @x1:0 + } + } + } + } + } + } + } + } + result: { + IDENT [34] { + name: @x0:0 + } + } + } + } + } + CALL [35] { + function: _==_ + args: { + IDENT [36] { + name: @index1 + } + IDENT [37] { + name: @index0 + } + } + } + } +} +Test case: INCLUSION_LIST +Source: 1 in [1,2,3] && 2 in [1,2,3] && 3 in [3, [1,2,3]] && 1 in [1,2,3] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + CONSTANT [6] { value: 3 } + } + } + CALL [7] { + function: @in + args: { + CONSTANT [8] { value: 1 } + IDENT [9] { + name: @index0 + } + } + } + CALL [10] { + function: _&&_ + args: { + CALL [11] { + function: @in + args: { + CONSTANT [12] { value: 3 } + CREATE_LIST [13] { + elements: { + CONSTANT [14] { value: 3 } + IDENT [15] { + name: @index0 + } + } + } + } + } + IDENT [16] { + name: @index1 + } + } + } + CALL [17] { + function: _&&_ + args: { + IDENT [18] { + name: @index1 + } + CALL [19] { + function: @in + args: { + CONSTANT [20] { value: 2 } + IDENT [21] { + name: @index0 + } + } + } + } + } + } + } + CALL [22] { + function: _&&_ + args: { + IDENT [23] { + name: @index3 + } + IDENT [24] { + name: @index2 + } + } + } + } +} +Test case: INCLUSION_MAP +Source: 2 in {'a': 1, 2: {true: false}, 3: {true: false}} +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: true } + } + value: { + CONSTANT [6] { value: false } + } + } + } + CREATE_MAP [7] { + MAP_ENTRY [8] { + key: { + CONSTANT [9] { value: "a" } + } + value: { + CONSTANT [10] { value: 1 } + } + } + MAP_ENTRY [11] { + key: { + CONSTANT [12] { value: 2 } + } + value: { + IDENT [13] { + name: @index0 + } + } + } + MAP_ENTRY [14] { + key: { + CONSTANT [15] { value: 3 } + } + value: { + IDENT [16] { + name: @index0 + } + } + } + } + } + } + CALL [17] { + function: @in + args: { + CONSTANT [18] { value: 2 } + IDENT [19] { + name: @index1 + } + } + } + } +} +Test case: MACRO_ITER_VAR_NOT_REFERENCED +Source: [1,2].map(i, [1, 2].map(i, [3,4])) == [[[3, 4], [3, 4]], [[3, 4], [3, 4]]] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + } + } + CREATE_LIST [6] { + elements: { + CONSTANT [7] { value: 3 } + CONSTANT [8] { value: 4 } + } + } + CREATE_LIST [9] { + elements: { + IDENT [10] { + name: @index1 + } + IDENT [11] { + name: @index1 + } + } + } + CREATE_LIST [12] { + elements: { + IDENT [13] { + name: @index2 + } + IDENT [14] { + name: @index2 + } + } + } + COMPREHENSION [15] { + iter_var: @c0:0 + iter_range: { + IDENT [16] { + name: @index0 + } + } + accu_var: @x0:0 + accu_init: { + CREATE_LIST [17] { + elements: { + } + } + } + loop_condition: { + CONSTANT [18] { value: true } + } + loop_step: { + CALL [19] { + function: _+_ + args: { + IDENT [20] { + name: @x0:0 + } + CREATE_LIST [21] { + elements: { + COMPREHENSION [22] { + iter_var: @c1:0 + iter_range: { + IDENT [23] { + name: @index0 + } + } + accu_var: @x1:0 + accu_init: { + CREATE_LIST [24] { + elements: { + } + } + } + loop_condition: { + CONSTANT [25] { value: true } + } + loop_step: { + CALL [26] { + function: _+_ + args: { + IDENT [27] { + name: @x1:0 + } + CREATE_LIST [28] { + elements: { + IDENT [29] { + name: @index1 + } + } + } + } + } + } + result: { + IDENT [30] { + name: @x1:0 + } + } + } + } + } + } + } + } + result: { + IDENT [31] { + name: @x0:0 + } + } + } + } + } + CALL [32] { + function: _==_ + args: { + IDENT [33] { + name: @index4 + } + IDENT [34] { + name: @index3 + } + } + } + } +} +Test case: MACRO_SHADOWED_VARIABLE +Source: [x - 1 > 3 ? x - 1 : 5].exists(x, x - 1 > 3) || x - 1 > 3 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _-_ + args: { + IDENT [4] { + name: x + } + CONSTANT [5] { value: 1 } + } + } + CALL [6] { + function: _>_ + args: { + IDENT [7] { + name: @index0 + } + CONSTANT [8] { value: 3 } + } + } + COMPREHENSION [9] { + iter_var: @c0:0 + iter_range: { + CREATE_LIST [10] { + elements: { + CALL [11] { + function: _?_:_ + args: { + IDENT [12] { + name: @index1 + } + IDENT [13] { + name: @index0 + } + CONSTANT [14] { value: 5 } + } + } + } + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [15] { value: false } + } + loop_condition: { + CALL [16] { + function: @not_strictly_false + args: { + CALL [17] { + function: !_ + args: { + IDENT [18] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + CALL [19] { + function: _||_ + args: { + IDENT [20] { + name: @x0:0 + } + CALL [21] { + function: _>_ + args: { + CALL [22] { + function: _-_ + args: { + IDENT [23] { + name: @c0:0 + } + CONSTANT [24] { value: 1 } + } + } + CONSTANT [25] { value: 3 } + } + } + } + } + } + result: { + IDENT [26] { + name: @x0:0 + } + } + } + } + } + CALL [27] { + function: _||_ + args: { + IDENT [28] { + name: @index2 + } + IDENT [29] { + name: @index1 + } + } + } + } +} +Test case: MACRO_SHADOWED_VARIABLE_2 +Source: ["foo", "bar"].map(x, [x + x, x + x]).map(x, [x + x, x + x]) +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _+_ + args: { + IDENT [4] { + name: @c1:0 + } + IDENT [5] { + name: @c1:0 + } + } + } + CALL [6] { + function: _+_ + args: { + IDENT [7] { + name: @c0:0 + } + IDENT [8] { + name: @c0:0 + } + } + } + CALL [9] { + function: _+_ + args: { + IDENT [10] { + name: @x0:0 + } + CREATE_LIST [11] { + elements: { + CREATE_LIST [12] { + elements: { + IDENT [13] { + name: @index1 + } + IDENT [14] { + name: @index1 + } + } + } + } + } + } + } + COMPREHENSION [15] { + iter_var: @c1:0 + iter_range: { + CREATE_LIST [16] { + elements: { + CONSTANT [17] { value: "foo" } + CONSTANT [18] { value: "bar" } + } + } + } + accu_var: @x1:0 + accu_init: { + CREATE_LIST [19] { + elements: { + } + } + } + loop_condition: { + CONSTANT [20] { value: true } + } + loop_step: { + CALL [21] { + function: _+_ + args: { + IDENT [22] { + name: @x1:0 + } + CREATE_LIST [23] { + elements: { + CREATE_LIST [24] { + elements: { + IDENT [25] { + name: @index0 + } + IDENT [26] { + name: @index0 + } + } + } + } + } + } + } + } + result: { + IDENT [27] { + name: @x1:0 + } + } + } + } + } + COMPREHENSION [28] { + iter_var: @c0:0 + iter_range: { + IDENT [29] { + name: @index3 + } + } + accu_var: @x0:0 + accu_init: { + CREATE_LIST [30] { + elements: { + } + } + } + loop_condition: { + CONSTANT [31] { value: true } + } + loop_step: { + IDENT [32] { + name: @index2 + } + } + result: { + IDENT [33] { + name: @x0:0 + } + } + } + } +} +Test case: PRESENCE_TEST +Source: has({'a': true}.a) && {'a':true}['a'] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: "a" } + } + value: { + CONSTANT [6] { value: true } + } + } + } + CALL [7] { + function: _[_] + args: { + IDENT [8] { + name: @index0 + } + CONSTANT [9] { value: "a" } + } + } + } + } + CALL [10] { + function: _&&_ + args: { + SELECT [11] { + IDENT [12] { + name: @index0 + }.a~presence_test + } + IDENT [13] { + name: @index1 + } + } + } + } +} +Test case: PRESENCE_TEST_WITH_TERNARY +Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : 0) == 10 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + CALL [5] { + function: _?_:_ + args: { + SELECT [6] { + IDENT [7] { + name: @index0 + }.payload~presence_test + } + SELECT [8] { + SELECT [9] { + IDENT [10] { + name: @index0 + }.payload + }.single_int64 + } + CONSTANT [11] { value: 0 } + } + } + } + } + CALL [12] { + function: _==_ + args: { + IDENT [13] { + name: @index1 + } + CONSTANT [14] { value: 10 } + } + } + } +} +Test case: PRESENCE_TEST_WITH_TERNARY_2 +Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : msg.oneof_type.payload.single_int64 * 0) == 10 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.single_int64 + } + CALL [9] { + function: _?_:_ + args: { + SELECT [10] { + IDENT [11] { + name: @index0 + }.payload~presence_test + } + IDENT [12] { + name: @index2 + } + CALL [13] { + function: _*_ + args: { + IDENT [14] { + name: @index2 + } + CONSTANT [15] { value: 0 } + } + } + } + } + } + } + CALL [16] { + function: _==_ + args: { + IDENT [17] { + name: @index3 + } + CONSTANT [18] { value: 10 } + } + } + } +} +Test case: PRESENCE_TEST_WITH_TERNARY_3 +Source: (has(msg.oneof_type.payload.single_int64) ? msg.oneof_type.payload.single_int64 : msg.oneof_type.payload.single_int64 * 0) == 10 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.single_int64 + } + CALL [9] { + function: _?_:_ + args: { + SELECT [10] { + IDENT [11] { + name: @index1 + }.single_int64~presence_test + } + IDENT [12] { + name: @index2 + } + CALL [13] { + function: _*_ + args: { + IDENT [14] { + name: @index2 + } + CONSTANT [15] { value: 0 } + } + } + } + } + } + } + CALL [16] { + function: _==_ + args: { + IDENT [17] { + name: @index3 + } + CONSTANT [18] { value: 10 } + } + } + } +} +Test case: PRESENCE_TEST_WITH_TERNARY_NESTED +Source: (has(msg.oneof_type) && has(msg.oneof_type.payload) && has(msg.oneof_type.payload.single_int64)) ? ((has(msg.oneof_type.payload.map_string_string) && has(msg.oneof_type.payload.map_string_string.key)) ? msg.oneof_type.payload.map_string_string.key == 'A' : false) : false +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.map_string_string + } + CALL [9] { + function: _?_:_ + args: { + CALL [10] { + function: _&&_ + args: { + SELECT [11] { + IDENT [12] { + name: @index1 + }.map_string_string~presence_test + } + SELECT [13] { + IDENT [14] { + name: @index2 + }.key~presence_test + } + } + } + CALL [15] { + function: _==_ + args: { + SELECT [16] { + IDENT [17] { + name: @index2 + }.key + } + CONSTANT [18] { value: "A" } + } + } + CONSTANT [19] { value: false } + } + } + CALL [20] { + function: _&&_ + args: { + CALL [21] { + function: _&&_ + args: { + SELECT [22] { + IDENT [23] { + name: msg + }.oneof_type~presence_test + } + SELECT [24] { + IDENT [25] { + name: @index0 + }.payload~presence_test + } + } + } + SELECT [26] { + IDENT [27] { + name: @index1 + }.single_int64~presence_test + } + } + } + } + } + CALL [28] { + function: _?_:_ + args: { + IDENT [29] { + name: @index4 + } + IDENT [30] { + name: @index3 + } + CONSTANT [31] { value: false } + } + } + } +} +Test case: OPTIONAL_LIST +Source: [10, ?optional.none(), [?optional.none(), ?opt_x], [?optional.none(), ?opt_x]] == [10, [5], [5]] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: optional.none + args: { + } + } + CREATE_LIST [4] { + elements: { + IDENT [5] { + name: @index0 + } + IDENT [6] { + name: opt_x + } + } + optional_indices: [0, 1] + } + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 5 } + } + } + CREATE_LIST [9] { + elements: { + CONSTANT [10] { value: 10 } + IDENT [11] { + name: @index2 + } + IDENT [12] { + name: @index2 + } + } + } + CREATE_LIST [13] { + elements: { + CONSTANT [14] { value: 10 } + IDENT [15] { + name: @index0 + } + IDENT [16] { + name: @index1 + } + IDENT [17] { + name: @index1 + } + } + optional_indices: [0] + } + } + } + CALL [18] { + function: _==_ + args: { + IDENT [19] { + name: @index4 + } + IDENT [20] { + name: @index3 + } + } + } + } +} +Test case: OPTIONAL_MAP +Source: {?'hello': optional.of('hello')}['hello'] + {?'hello': optional.of('hello')}['hello'] == 'hellohello' +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: optional.of + args: { + CONSTANT [4] { value: "hello" } + } + } + CREATE_MAP [5] { + MAP_ENTRY [6] { + key: { + CONSTANT [7] { value: "hello" } + } + optional_entry: true + value: { + IDENT [8] { + name: @index0 + } + } + } + } + CALL [9] { + function: _[_] + args: { + IDENT [10] { + name: @index1 + } + CONSTANT [11] { value: "hello" } + } + } + CALL [12] { + function: _+_ + args: { + IDENT [13] { + name: @index2 + } + IDENT [14] { + name: @index2 + } + } + } + } + } + CALL [15] { + function: _==_ + args: { + IDENT [16] { + name: @index3 + } + CONSTANT [17] { value: "hellohello" } + } + } + } +} +Test case: OPTIONAL_MAP_CHAINED +Source: {?'key': optional.of('test')}[?'bogus'].or({'key': 'test'}[?'bogus']).orValue({'key': 'test'}['key']) == 'test' +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: "key" } + } + value: { + CONSTANT [6] { value: "test" } + } + } + } + CALL [7] { + function: orValue + target: { + CALL [8] { + function: or + target: { + CALL [9] { + function: _[?_] + args: { + CREATE_MAP [10] { + MAP_ENTRY [11] { + key: { + CONSTANT [12] { value: "key" } + } + optional_entry: true + value: { + CALL [13] { + function: optional.of + args: { + CONSTANT [14] { value: "test" } + } + } + } + } + } + CONSTANT [15] { value: "bogus" } + } + } + } + args: { + CALL [16] { + function: _[?_] + args: { + IDENT [17] { + name: @index0 + } + CONSTANT [18] { value: "bogus" } + } + } + } + } + } + args: { + CALL [19] { + function: _[_] + args: { + IDENT [20] { + name: @index0 + } + CONSTANT [21] { value: "key" } + } + } + } + } + } + } + CALL [22] { + function: _==_ + args: { + IDENT [23] { + name: @index1 + } + CONSTANT [24] { value: "test" } + } + } + } +} +Test case: OPTIONAL_MESSAGE +Source: TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}.single_int32 + TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}.single_int64 == 5 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: optional.ofNonZeroValue + args: { + CONSTANT [4] { value: 1 } + } + } + CALL [5] { + function: optional.of + args: { + CONSTANT [6] { value: 4 } + } + } + CREATE_STRUCT [7] { + name: TestAllTypes + entries: { + ENTRY [8] { + field_key: single_int64 + optional_entry: true + value: { + IDENT [9] { + name: @index0 + } + } + } + ENTRY [10] { + field_key: single_int32 + optional_entry: true + value: { + IDENT [11] { + name: @index1 + } + } + } + } + } + CALL [12] { + function: _+_ + args: { + SELECT [13] { + IDENT [14] { + name: @index2 + }.single_int32 + } + SELECT [15] { + IDENT [16] { + name: @index2 + }.single_int64 + } + } + } + } + } + CALL [17] { + function: _==_ + args: { + IDENT [18] { + name: @index3 + } + CONSTANT [19] { value: 5 } + } + } + } +} +Test case: CALL +Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('h' + 'e' + 'l' + 'l' + 'o') +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _+_ + args: { + CONSTANT [4] { value: "h" } + CONSTANT [5] { value: "e" } + } + } + CALL [6] { + function: _+_ + args: { + IDENT [7] { + name: @index0 + } + CONSTANT [8] { value: "l" } + } + } + CALL [9] { + function: _+_ + args: { + IDENT [10] { + name: @index1 + } + CONSTANT [11] { value: "l" } + } + } + CALL [12] { + function: _+_ + args: { + IDENT [13] { + name: @index2 + } + CONSTANT [14] { value: "o" } + } + } + CALL [15] { + function: _+_ + args: { + IDENT [16] { + name: @index3 + } + CONSTANT [17] { value: " world" } + } + } + } + } + CALL [18] { + function: matches + target: { + IDENT [19] { + name: @index4 + } + } + args: { + IDENT [20] { + name: @index3 + } + } + } + } +} +Test case: CALL_ARGUMENT_NESTED_NO_COMMON_SUBEXPR +Source: 'hello world'.matches('h' + 'e' + 'l' + 'l' + 'o') +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _+_ + args: { + CALL [4] { + function: _+_ + args: { + CALL [5] { + function: _+_ + args: { + CALL [6] { + function: _+_ + args: { + CONSTANT [7] { value: "h" } + CONSTANT [8] { value: "e" } + } + } + CONSTANT [9] { value: "l" } + } + } + CONSTANT [10] { value: "l" } + } + } + CONSTANT [11] { value: "o" } + } + } + } + } + CALL [12] { + function: matches + target: { + CONSTANT [13] { value: "hello world" } + } + args: { + IDENT [14] { + name: @index0 + } + } + } + } +} +Test case: CALL_TARGET_NESTED_NO_COMMON_SUBEXPR +Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('hello') +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _+_ + args: { + CALL [4] { + function: _+_ + args: { + CALL [5] { + function: _+_ + args: { + CALL [6] { + function: _+_ + args: { + CALL [7] { + function: _+_ + args: { + CONSTANT [8] { value: "h" } + CONSTANT [9] { value: "e" } + } + } + CONSTANT [10] { value: "l" } + } + } + CONSTANT [11] { value: "l" } + } + } + CONSTANT [12] { value: "o" } + } + } + CONSTANT [13] { value: " world" } + } + } + } + } + CALL [14] { + function: matches + target: { + IDENT [15] { + name: @index0 + } + } + args: { + CONSTANT [16] { value: "hello" } + } + } + } +} +Test case: CALL_BOTH_ARGUMENT_TARGET_NESTED_NO_COMMON_SUBEXPR +Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('w' + 'o' + 'r' + 'l' + 'd') +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _+_ + args: { + CALL [4] { + function: _+_ + args: { + CALL [5] { + function: _+_ + args: { + CALL [6] { + function: _+_ + args: { + CONSTANT [7] { value: "w" } + CONSTANT [8] { value: "o" } + } + } + CONSTANT [9] { value: "r" } + } + } + CONSTANT [10] { value: "l" } + } + } + CONSTANT [11] { value: "d" } + } + } + CALL [12] { + function: _+_ + args: { + CALL [13] { + function: _+_ + args: { + CALL [14] { + function: _+_ + args: { + CALL [15] { + function: _+_ + args: { + CALL [16] { + function: _+_ + args: { + CONSTANT [17] { value: "h" } + CONSTANT [18] { value: "e" } + } + } + CONSTANT [19] { value: "l" } + } + } + CONSTANT [20] { value: "l" } + } + } + CONSTANT [21] { value: "o" } + } + } + CONSTANT [22] { value: " world" } + } + } + } + } + CALL [23] { + function: matches + target: { + IDENT [24] { + name: @index1 + } + } + args: { + IDENT [25] { + name: @index0 + } + } + } + } +} diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_8.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_8.baseline new file mode 100644 index 000000000..10e94e557 --- /dev/null +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_8.baseline @@ -0,0 +1,3281 @@ +Test case: SIZE_1 +Source: size([1,2]) + size([1,2]) + 1 == 5 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + } + } + CALL [6] { + function: size + args: { + IDENT [7] { + name: @index0 + } + } + } + CALL [8] { + function: _+_ + args: { + CALL [9] { + function: _+_ + args: { + IDENT [10] { + name: @index1 + } + IDENT [11] { + name: @index1 + } + } + } + CONSTANT [12] { value: 1 } + } + } + } + } + CALL [13] { + function: _==_ + args: { + IDENT [14] { + name: @index2 + } + CONSTANT [15] { value: 5 } + } + } + } +} +Test case: SIZE_2 +Source: 2 + size([1,2]) + size([1,2]) + 1 == 7 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + } + } + CALL [6] { + function: size + args: { + IDENT [7] { + name: @index0 + } + } + } + CALL [8] { + function: _+_ + args: { + CALL [9] { + function: _+_ + args: { + CALL [10] { + function: _+_ + args: { + CONSTANT [11] { value: 2 } + IDENT [12] { + name: @index1 + } + } + } + IDENT [13] { + name: @index1 + } + } + } + CONSTANT [14] { value: 1 } + } + } + } + } + CALL [15] { + function: _==_ + args: { + IDENT [16] { + name: @index2 + } + CONSTANT [17] { value: 7 } + } + } + } +} +Test case: SIZE_3 +Source: size([0]) + size([0]) + size([1,2]) + size([1,2]) == 6 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 0 } + } + } + CALL [5] { + function: size + args: { + IDENT [6] { + name: @index0 + } + } + } + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 1 } + CONSTANT [9] { value: 2 } + } + } + CALL [10] { + function: size + args: { + IDENT [11] { + name: @index2 + } + } + } + CALL [12] { + function: _+_ + args: { + CALL [13] { + function: _+_ + args: { + CALL [14] { + function: _+_ + args: { + IDENT [15] { + name: @index1 + } + IDENT [16] { + name: @index1 + } + } + } + IDENT [17] { + name: @index3 + } + } + } + IDENT [18] { + name: @index3 + } + } + } + } + } + CALL [19] { + function: _==_ + args: { + IDENT [20] { + name: @index4 + } + CONSTANT [21] { value: 6 } + } + } + } +} +Test case: SIZE_4 +Source: 5 + size([0]) + size([0]) + size([1,2]) + size([1,2]) + size([1,2,3]) + size([1,2,3]) == 17 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 0 } + } + } + CALL [5] { + function: size + args: { + IDENT [6] { + name: @index0 + } + } + } + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 1 } + CONSTANT [9] { value: 2 } + } + } + CALL [10] { + function: size + args: { + IDENT [11] { + name: @index2 + } + } + } + CREATE_LIST [12] { + elements: { + CONSTANT [13] { value: 1 } + CONSTANT [14] { value: 2 } + CONSTANT [15] { value: 3 } + } + } + CALL [16] { + function: size + args: { + IDENT [17] { + name: @index4 + } + } + } + CALL [18] { + function: _+_ + args: { + CALL [19] { + function: _+_ + args: { + CALL [20] { + function: _+_ + args: { + CALL [21] { + function: _+_ + args: { + CALL [22] { + function: _+_ + args: { + CALL [23] { + function: _+_ + args: { + CONSTANT [24] { value: 5 } + IDENT [25] { + name: @index1 + } + } + } + IDENT [26] { + name: @index1 + } + } + } + IDENT [27] { + name: @index3 + } + } + } + IDENT [28] { + name: @index3 + } + } + } + IDENT [29] { + name: @index5 + } + } + } + IDENT [30] { + name: @index5 + } + } + } + } + } + CALL [31] { + function: _==_ + args: { + IDENT [32] { + name: @index6 + } + CONSTANT [33] { value: 17 } + } + } + } +} +Test case: TIMESTAMP +Source: timestamp(int(timestamp(1000000000))).getFullYear() + timestamp(int(timestamp(75))).getFullYear() + timestamp(int(timestamp(50))).getFullYear() + timestamp(int(timestamp(1000000000))).getFullYear() + timestamp(int(timestamp(50))).getSeconds() + timestamp(int(timestamp(200))).getFullYear() + timestamp(int(timestamp(200))).getFullYear() + timestamp(int(timestamp(75))).getMinutes() + timestamp(int(timestamp(1000000000))).getFullYear() == 13934 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: timestamp + args: { + CONSTANT [4] { value: 1000000000 } + } + } + CALL [5] { + function: int + args: { + IDENT [6] { + name: @index0 + } + } + } + CALL [7] { + function: timestamp + args: { + IDENT [8] { + name: @index1 + } + } + } + CALL [9] { + function: getFullYear + target: { + IDENT [10] { + name: @index2 + } + } + args: { + } + } + CALL [11] { + function: timestamp + args: { + CONSTANT [12] { value: 50 } + } + } + CALL [13] { + function: int + args: { + IDENT [14] { + name: @index4 + } + } + } + CALL [15] { + function: timestamp + args: { + IDENT [16] { + name: @index5 + } + } + } + CALL [17] { + function: timestamp + args: { + CONSTANT [18] { value: 200 } + } + } + CALL [19] { + function: int + args: { + IDENT [20] { + name: @index7 + } + } + } + CALL [21] { + function: timestamp + args: { + IDENT [22] { + name: @index8 + } + } + } + CALL [23] { + function: getFullYear + target: { + IDENT [24] { + name: @index9 + } + } + args: { + } + } + CALL [25] { + function: timestamp + args: { + CONSTANT [26] { value: 75 } + } + } + CALL [27] { + function: int + args: { + IDENT [28] { + name: @index11 + } + } + } + CALL [29] { + function: timestamp + args: { + IDENT [30] { + name: @index12 + } + } + } + CALL [31] { + function: _+_ + args: { + CALL [32] { + function: _+_ + args: { + CALL [33] { + function: _+_ + args: { + CALL [34] { + function: _+_ + args: { + CALL [35] { + function: _+_ + args: { + CALL [36] { + function: _+_ + args: { + CALL [37] { + function: _+_ + args: { + IDENT [38] { + name: @index3 + } + CALL [39] { + function: getFullYear + target: { + IDENT [40] { + name: @index13 + } + } + args: { + } + } + } + } + CALL [41] { + function: getFullYear + target: { + IDENT [42] { + name: @index6 + } + } + args: { + } + } + } + } + IDENT [43] { + name: @index3 + } + } + } + CALL [44] { + function: getSeconds + target: { + IDENT [45] { + name: @index6 + } + } + args: { + } + } + } + } + IDENT [46] { + name: @index10 + } + } + } + IDENT [47] { + name: @index10 + } + } + } + CALL [48] { + function: getMinutes + target: { + IDENT [49] { + name: @index13 + } + } + args: { + } + } + } + } + CALL [50] { + function: _+_ + args: { + IDENT [51] { + name: @index14 + } + IDENT [52] { + name: @index3 + } + } + } + } + } + CALL [53] { + function: _==_ + args: { + IDENT [54] { + name: @index15 + } + CONSTANT [55] { value: 13934 } + } + } + } +} +Test case: MAP_INDEX +Source: {"a": 2}["a"] + {"a": 2}["a"] * {"a": 2}["a"] == 6 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: "a" } + } + value: { + CONSTANT [6] { value: 2 } + } + } + } + CALL [7] { + function: _[_] + args: { + IDENT [8] { + name: @index0 + } + CONSTANT [9] { value: "a" } + } + } + CALL [10] { + function: _+_ + args: { + IDENT [11] { + name: @index1 + } + CALL [12] { + function: _*_ + args: { + IDENT [13] { + name: @index1 + } + IDENT [14] { + name: @index1 + } + } + } + } + } + } + } + CALL [15] { + function: _==_ + args: { + IDENT [16] { + name: @index2 + } + CONSTANT [17] { value: 6 } + } + } + } +} +Test case: NESTED_MAP_CONSTRUCTION +Source: {'a': {'b': 1}, 'c': {'b': 1}, 'd': {'e': {'b': 1}}, 'e': {'e': {'b': 1}}} +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: "b" } + } + value: { + CONSTANT [6] { value: 1 } + } + } + } + CREATE_MAP [7] { + MAP_ENTRY [8] { + key: { + CONSTANT [9] { value: "e" } + } + value: { + IDENT [10] { + name: @index0 + } + } + } + } + } + } + CREATE_MAP [11] { + MAP_ENTRY [12] { + key: { + CONSTANT [13] { value: "a" } + } + value: { + IDENT [14] { + name: @index0 + } + } + } + MAP_ENTRY [15] { + key: { + CONSTANT [16] { value: "c" } + } + value: { + IDENT [17] { + name: @index0 + } + } + } + MAP_ENTRY [18] { + key: { + CONSTANT [19] { value: "d" } + } + value: { + IDENT [20] { + name: @index1 + } + } + } + MAP_ENTRY [21] { + key: { + CONSTANT [22] { value: "e" } + } + value: { + IDENT [23] { + name: @index1 + } + } + } + } + } +} +Test case: NESTED_LIST_CONSTRUCTION +Source: [1, [1,2,3,4], 2, [1,2,3,4], 5, [1,2,3,4], 7, [[1,2], [1,2,3,4]], [1,2]] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + CONSTANT [6] { value: 3 } + CONSTANT [7] { value: 4 } + } + } + CREATE_LIST [8] { + elements: { + CONSTANT [9] { value: 1 } + CONSTANT [10] { value: 2 } + } + } + CREATE_LIST [11] { + elements: { + IDENT [12] { + name: @index1 + } + IDENT [13] { + name: @index0 + } + } + } + } + } + CREATE_LIST [14] { + elements: { + CONSTANT [15] { value: 1 } + IDENT [16] { + name: @index0 + } + CONSTANT [17] { value: 2 } + IDENT [18] { + name: @index0 + } + CONSTANT [19] { value: 5 } + IDENT [20] { + name: @index0 + } + CONSTANT [21] { value: 7 } + IDENT [22] { + name: @index2 + } + IDENT [23] { + name: @index1 + } + } + } + } +} +Test case: SELECT +Source: msg.single_int64 + msg.single_int64 == 6 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.single_int64 + } + CALL [5] { + function: _+_ + args: { + IDENT [6] { + name: @index0 + } + IDENT [7] { + name: @index0 + } + } + } + } + } + CALL [8] { + function: _==_ + args: { + IDENT [9] { + name: @index1 + } + CONSTANT [10] { value: 6 } + } + } + } +} +Test case: SELECT_NESTED_1 +Source: msg.oneof_type.payload.single_int64 + msg.oneof_type.payload.single_int32 + msg.oneof_type.payload.single_int64 + msg.single_int64 + msg.oneof_type.payload.oneof_type.payload.single_int64 == 31 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.single_int64 + } + CALL [9] { + function: _+_ + args: { + CALL [10] { + function: _+_ + args: { + CALL [11] { + function: _+_ + args: { + CALL [12] { + function: _+_ + args: { + IDENT [13] { + name: @index2 + } + SELECT [14] { + IDENT [15] { + name: @index1 + }.single_int32 + } + } + } + IDENT [16] { + name: @index2 + } + } + } + SELECT [17] { + IDENT [18] { + name: msg + }.single_int64 + } + } + } + SELECT [19] { + SELECT [20] { + SELECT [21] { + IDENT [22] { + name: @index1 + }.oneof_type + }.payload + }.single_int64 + } + } + } + } + } + CALL [23] { + function: _==_ + args: { + IDENT [24] { + name: @index3 + } + CONSTANT [25] { value: 31 } + } + } + } +} +Test case: SELECT_NESTED_2 +Source: true || msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload.single_bool || msg.oneof_type.payload.oneof_type.payload.oneof_type.child.child.payload.single_bool +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.oneof_type + } + SELECT [9] { + IDENT [10] { + name: @index2 + }.payload + } + SELECT [11] { + IDENT [12] { + name: @index3 + }.oneof_type + } + SELECT [13] { + SELECT [14] { + SELECT [15] { + SELECT [16] { + IDENT [17] { + name: @index4 + }.child + }.child + }.payload + }.single_bool + } + CALL [18] { + function: _||_ + args: { + CONSTANT [19] { value: true } + SELECT [20] { + SELECT [21] { + SELECT [22] { + SELECT [23] { + IDENT [24] { + name: @index4 + }.payload + }.oneof_type + }.payload + }.single_bool + } + } + } + } + } + CALL [25] { + function: _||_ + args: { + IDENT [26] { + name: @index6 + } + IDENT [27] { + name: @index5 + } + } + } + } +} +Test case: SELECT_NESTED_MESSAGE_MAP_INDEX_1 +Source: msg.oneof_type.payload.map_int32_int64[1] + msg.oneof_type.payload.map_int32_int64[1] + msg.oneof_type.payload.map_int32_int64[1] == 15 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.map_int32_int64 + } + CALL [9] { + function: _[_] + args: { + IDENT [10] { + name: @index2 + } + CONSTANT [11] { value: 1 } + } + } + CALL [12] { + function: _+_ + args: { + CALL [13] { + function: _+_ + args: { + IDENT [14] { + name: @index3 + } + IDENT [15] { + name: @index3 + } + } + } + IDENT [16] { + name: @index3 + } + } + } + } + } + CALL [17] { + function: _==_ + args: { + IDENT [18] { + name: @index4 + } + CONSTANT [19] { value: 15 } + } + } + } +} +Test case: SELECT_NESTED_MESSAGE_MAP_INDEX_2 +Source: msg.oneof_type.payload.map_int32_int64[0] + msg.oneof_type.payload.map_int32_int64[1] + msg.oneof_type.payload.map_int32_int64[2] == 8 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.map_int32_int64 + } + CALL [9] { + function: _+_ + args: { + CALL [10] { + function: _+_ + args: { + CALL [11] { + function: _[_] + args: { + IDENT [12] { + name: @index2 + } + CONSTANT [13] { value: 0 } + } + } + CALL [14] { + function: _[_] + args: { + IDENT [15] { + name: @index2 + } + CONSTANT [16] { value: 1 } + } + } + } + } + CALL [17] { + function: _[_] + args: { + IDENT [18] { + name: @index2 + } + CONSTANT [19] { value: 2 } + } + } + } + } + } + } + CALL [20] { + function: _==_ + args: { + IDENT [21] { + name: @index3 + } + CONSTANT [22] { value: 8 } + } + } + } +} +Test case: SELECT_NESTED_NO_COMMON_SUBEXPR +Source: msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload.single_int64 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + SELECT [4] { + SELECT [5] { + SELECT [6] { + SELECT [7] { + SELECT [8] { + SELECT [9] { + SELECT [10] { + IDENT [11] { + name: msg + }.oneof_type + }.payload + }.oneof_type + }.payload + }.oneof_type + }.payload + }.oneof_type + }.payload + } + } + } + SELECT [12] { + IDENT [13] { + name: @index0 + }.single_int64 + } + } +} +Test case: TERNARY +Source: (msg.single_int64 > 0 ? msg.single_int64 : 0) == 3 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.single_int64 + } + CALL [5] { + function: _?_:_ + args: { + CALL [6] { + function: _>_ + args: { + IDENT [7] { + name: @index0 + } + CONSTANT [8] { value: 0 } + } + } + IDENT [9] { + name: @index0 + } + CONSTANT [10] { value: 0 } + } + } + } + } + CALL [11] { + function: _==_ + args: { + IDENT [12] { + name: @index1 + } + CONSTANT [13] { value: 3 } + } + } + } +} +Test case: TERNARY_BIND_RHS_ONLY +Source: false ? false : (msg.single_int64) + ((msg.single_int64 + 1) * 2) == 11 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.single_int64 + } + CALL [5] { + function: _==_ + args: { + CALL [6] { + function: _+_ + args: { + IDENT [7] { + name: @index0 + } + CALL [8] { + function: _*_ + args: { + CALL [9] { + function: _+_ + args: { + IDENT [10] { + name: @index0 + } + CONSTANT [11] { value: 1 } + } + } + CONSTANT [12] { value: 2 } + } + } + } + } + CONSTANT [13] { value: 11 } + } + } + } + } + CALL [14] { + function: _?_:_ + args: { + CONSTANT [15] { value: false } + CONSTANT [16] { value: false } + IDENT [17] { + name: @index1 + } + } + } + } +} +Test case: NESTED_TERNARY +Source: (msg.single_int64 > 0 ? (msg.single_int32 > 0 ? msg.single_int64 + msg.single_int32 : 0) : 0) == 8 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.single_int64 + } + SELECT [5] { + IDENT [6] { + name: msg + }.single_int32 + } + CALL [7] { + function: _?_:_ + args: { + CALL [8] { + function: _>_ + args: { + IDENT [9] { + name: @index0 + } + CONSTANT [10] { value: 0 } + } + } + CALL [11] { + function: _?_:_ + args: { + CALL [12] { + function: _>_ + args: { + IDENT [13] { + name: @index1 + } + CONSTANT [14] { value: 0 } + } + } + CALL [15] { + function: _+_ + args: { + IDENT [16] { + name: @index0 + } + IDENT [17] { + name: @index1 + } + } + } + CONSTANT [18] { value: 0 } + } + } + CONSTANT [19] { value: 0 } + } + } + } + } + CALL [20] { + function: _==_ + args: { + IDENT [21] { + name: @index2 + } + CONSTANT [22] { value: 8 } + } + } + } +} +Test case: MULTIPLE_MACROS_1 +Source: size([[1].exists(i, i > 0)]) + size([[1].exists(j, j > 0)]) + size([[2].exists(k, k > 1)]) + size([[2].exists(l, l > 1)]) == 4 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + } + } + CALL [5] { + function: _>_ + args: { + IDENT [6] { + name: @c0:0 + } + CONSTANT [7] { value: 0 } + } + } + CALL [8] { + function: _||_ + args: { + IDENT [9] { + name: @x0:0 + } + IDENT [10] { + name: @index1 + } + } + } + COMPREHENSION [11] { + iter_var: @c0:0 + iter_range: { + IDENT [12] { + name: @index0 + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [13] { value: false } + } + loop_condition: { + CALL [14] { + function: @not_strictly_false + args: { + CALL [15] { + function: !_ + args: { + IDENT [16] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + IDENT [17] { + name: @index2 + } + } + result: { + IDENT [18] { + name: @x0:0 + } + } + } + CREATE_LIST [19] { + elements: { + IDENT [20] { + name: @index3 + } + } + } + CALL [21] { + function: size + args: { + IDENT [22] { + name: @index4 + } + } + } + CREATE_LIST [23] { + elements: { + CONSTANT [24] { value: 2 } + } + } + CALL [25] { + function: _>_ + args: { + IDENT [26] { + name: @c0:0 + } + CONSTANT [27] { value: 1 } + } + } + CALL [28] { + function: _||_ + args: { + IDENT [29] { + name: @x0:0 + } + IDENT [30] { + name: @index7 + } + } + } + COMPREHENSION [31] { + iter_var: @c0:0 + iter_range: { + IDENT [32] { + name: @index6 + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [33] { value: false } + } + loop_condition: { + CALL [34] { + function: @not_strictly_false + args: { + CALL [35] { + function: !_ + args: { + IDENT [36] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + IDENT [37] { + name: @index8 + } + } + result: { + IDENT [38] { + name: @x0:0 + } + } + } + CREATE_LIST [39] { + elements: { + IDENT [40] { + name: @index9 + } + } + } + CALL [41] { + function: size + args: { + IDENT [42] { + name: @index10 + } + } + } + CALL [43] { + function: _+_ + args: { + CALL [44] { + function: _+_ + args: { + CALL [45] { + function: _+_ + args: { + IDENT [46] { + name: @index5 + } + IDENT [47] { + name: @index5 + } + } + } + IDENT [48] { + name: @index11 + } + } + } + IDENT [49] { + name: @index11 + } + } + } + } + } + CALL [50] { + function: _==_ + args: { + IDENT [51] { + name: @index12 + } + CONSTANT [52] { value: 4 } + } + } + } +} +Test case: MULTIPLE_MACROS_2 +Source: [[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == 'a')] + [['a'].exists(l, l == 'a')] == [true, true, true, true] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + } + } + CALL [5] { + function: _>_ + args: { + IDENT [6] { + name: @c0:0 + } + CONSTANT [7] { value: 0 } + } + } + CALL [8] { + function: _||_ + args: { + IDENT [9] { + name: @x0:0 + } + IDENT [10] { + name: @index1 + } + } + } + COMPREHENSION [11] { + iter_var: @c0:0 + iter_range: { + IDENT [12] { + name: @index0 + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [13] { value: false } + } + loop_condition: { + CALL [14] { + function: @not_strictly_false + args: { + CALL [15] { + function: !_ + args: { + IDENT [16] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + IDENT [17] { + name: @index2 + } + } + result: { + IDENT [18] { + name: @x0:0 + } + } + } + CREATE_LIST [19] { + elements: { + IDENT [20] { + name: @index3 + } + } + } + CREATE_LIST [21] { + elements: { + CONSTANT [22] { value: "a" } + } + } + CALL [23] { + function: _==_ + args: { + IDENT [24] { + name: @c0:1 + } + CONSTANT [25] { value: "a" } + } + } + CALL [26] { + function: _||_ + args: { + IDENT [27] { + name: @x0:1 + } + IDENT [28] { + name: @index6 + } + } + } + COMPREHENSION [29] { + iter_var: @c0:1 + iter_range: { + IDENT [30] { + name: @index5 + } + } + accu_var: @x0:1 + accu_init: { + CONSTANT [31] { value: false } + } + loop_condition: { + CALL [32] { + function: @not_strictly_false + args: { + CALL [33] { + function: !_ + args: { + IDENT [34] { + name: @x0:1 + } + } + } + } + } + } + loop_step: { + IDENT [35] { + name: @index7 + } + } + result: { + IDENT [36] { + name: @x0:1 + } + } + } + CREATE_LIST [37] { + elements: { + IDENT [38] { + name: @index8 + } + } + } + CREATE_LIST [39] { + elements: { + CONSTANT [40] { value: true } + CONSTANT [41] { value: true } + CONSTANT [42] { value: true } + CONSTANT [43] { value: true } + } + } + CALL [44] { + function: _+_ + args: { + CALL [45] { + function: _+_ + args: { + CALL [46] { + function: _+_ + args: { + IDENT [47] { + name: @index4 + } + IDENT [48] { + name: @index4 + } + } + } + IDENT [49] { + name: @index9 + } + } + } + IDENT [50] { + name: @index9 + } + } + } + } + } + CALL [51] { + function: _==_ + args: { + IDENT [52] { + name: @index11 + } + IDENT [53] { + name: @index10 + } + } + } + } +} +Test case: NESTED_MACROS +Source: [1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [[2, 3, 4], [2, 3, 4], [2, 3, 4]] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + CONSTANT [6] { value: 3 } + } + } + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 2 } + CONSTANT [9] { value: 3 } + CONSTANT [10] { value: 4 } + } + } + CREATE_LIST [11] { + elements: { + IDENT [12] { + name: @index1 + } + IDENT [13] { + name: @index1 + } + IDENT [14] { + name: @index1 + } + } + } + COMPREHENSION [15] { + iter_var: @c0:0 + iter_range: { + IDENT [16] { + name: @index0 + } + } + accu_var: @x0:0 + accu_init: { + CREATE_LIST [17] { + elements: { + } + } + } + loop_condition: { + CONSTANT [18] { value: true } + } + loop_step: { + CALL [19] { + function: _+_ + args: { + IDENT [20] { + name: @x0:0 + } + CREATE_LIST [21] { + elements: { + COMPREHENSION [22] { + iter_var: @c1:0 + iter_range: { + IDENT [23] { + name: @index0 + } + } + accu_var: @x1:0 + accu_init: { + CREATE_LIST [24] { + elements: { + } + } + } + loop_condition: { + CONSTANT [25] { value: true } + } + loop_step: { + CALL [26] { + function: _+_ + args: { + IDENT [27] { + name: @x1:0 + } + CREATE_LIST [28] { + elements: { + CALL [29] { + function: _+_ + args: { + IDENT [30] { + name: @c1:0 + } + CONSTANT [31] { value: 1 } + } + } + } + } + } + } + } + result: { + IDENT [32] { + name: @x1:0 + } + } + } + } + } + } + } + } + result: { + IDENT [33] { + name: @x0:0 + } + } + } + } + } + CALL [34] { + function: _==_ + args: { + IDENT [35] { + name: @index3 + } + IDENT [36] { + name: @index2 + } + } + } + } +} +Test case: NESTED_MACROS_2 +Source: [1, 2].map(y, [1, 2, 3].filter(x, x == y)) == [[1], [2]] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CREATE_LIST [4] { + elements: { + CONSTANT [5] { value: 1 } + } + } + CREATE_LIST [6] { + elements: { + CONSTANT [7] { value: 2 } + } + } + } + } + COMPREHENSION [8] { + iter_var: @c0:0 + iter_range: { + CREATE_LIST [9] { + elements: { + CONSTANT [10] { value: 1 } + CONSTANT [11] { value: 2 } + } + } + } + accu_var: @x0:0 + accu_init: { + CREATE_LIST [12] { + elements: { + } + } + } + loop_condition: { + CONSTANT [13] { value: true } + } + loop_step: { + CALL [14] { + function: _+_ + args: { + IDENT [15] { + name: @x0:0 + } + CREATE_LIST [16] { + elements: { + COMPREHENSION [17] { + iter_var: @c1:0 + iter_range: { + CREATE_LIST [18] { + elements: { + CONSTANT [19] { value: 1 } + CONSTANT [20] { value: 2 } + CONSTANT [21] { value: 3 } + } + } + } + accu_var: @x1:0 + accu_init: { + CREATE_LIST [22] { + elements: { + } + } + } + loop_condition: { + CONSTANT [23] { value: true } + } + loop_step: { + CALL [24] { + function: _?_:_ + args: { + CALL [25] { + function: _==_ + args: { + IDENT [26] { + name: @c1:0 + } + IDENT [27] { + name: @c0:0 + } + } + } + CALL [28] { + function: _+_ + args: { + IDENT [29] { + name: @x1:0 + } + CREATE_LIST [30] { + elements: { + IDENT [31] { + name: @c1:0 + } + } + } + } + } + IDENT [32] { + name: @x1:0 + } + } + } + } + result: { + IDENT [33] { + name: @x1:0 + } + } + } + } + } + } + } + } + result: { + IDENT [34] { + name: @x0:0 + } + } + } + } + } + CALL [35] { + function: _==_ + args: { + IDENT [36] { + name: @index1 + } + IDENT [37] { + name: @index0 + } + } + } + } +} +Test case: INCLUSION_LIST +Source: 1 in [1,2,3] && 2 in [1,2,3] && 3 in [3, [1,2,3]] && 1 in [1,2,3] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + CONSTANT [6] { value: 3 } + } + } + CALL [7] { + function: @in + args: { + CONSTANT [8] { value: 1 } + IDENT [9] { + name: @index0 + } + } + } + CALL [10] { + function: _&&_ + args: { + CALL [11] { + function: @in + args: { + CONSTANT [12] { value: 3 } + CREATE_LIST [13] { + elements: { + CONSTANT [14] { value: 3 } + IDENT [15] { + name: @index0 + } + } + } + } + } + IDENT [16] { + name: @index1 + } + } + } + CALL [17] { + function: _&&_ + args: { + IDENT [18] { + name: @index1 + } + CALL [19] { + function: @in + args: { + CONSTANT [20] { value: 2 } + IDENT [21] { + name: @index0 + } + } + } + } + } + } + } + CALL [22] { + function: _&&_ + args: { + IDENT [23] { + name: @index3 + } + IDENT [24] { + name: @index2 + } + } + } + } +} +Test case: INCLUSION_MAP +Source: 2 in {'a': 1, 2: {true: false}, 3: {true: false}} +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: true } + } + value: { + CONSTANT [6] { value: false } + } + } + } + CREATE_MAP [7] { + MAP_ENTRY [8] { + key: { + CONSTANT [9] { value: "a" } + } + value: { + CONSTANT [10] { value: 1 } + } + } + MAP_ENTRY [11] { + key: { + CONSTANT [12] { value: 2 } + } + value: { + IDENT [13] { + name: @index0 + } + } + } + MAP_ENTRY [14] { + key: { + CONSTANT [15] { value: 3 } + } + value: { + IDENT [16] { + name: @index0 + } + } + } + } + } + } + CALL [17] { + function: @in + args: { + CONSTANT [18] { value: 2 } + IDENT [19] { + name: @index1 + } + } + } + } +} +Test case: MACRO_ITER_VAR_NOT_REFERENCED +Source: [1,2].map(i, [1, 2].map(i, [3,4])) == [[[3, 4], [3, 4]], [[3, 4], [3, 4]]] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + } + } + CREATE_LIST [6] { + elements: { + CONSTANT [7] { value: 3 } + CONSTANT [8] { value: 4 } + } + } + CREATE_LIST [9] { + elements: { + IDENT [10] { + name: @index1 + } + IDENT [11] { + name: @index1 + } + } + } + CREATE_LIST [12] { + elements: { + IDENT [13] { + name: @index2 + } + IDENT [14] { + name: @index2 + } + } + } + COMPREHENSION [15] { + iter_var: @c0:0 + iter_range: { + IDENT [16] { + name: @index0 + } + } + accu_var: @x0:0 + accu_init: { + CREATE_LIST [17] { + elements: { + } + } + } + loop_condition: { + CONSTANT [18] { value: true } + } + loop_step: { + CALL [19] { + function: _+_ + args: { + IDENT [20] { + name: @x0:0 + } + CREATE_LIST [21] { + elements: { + COMPREHENSION [22] { + iter_var: @c1:0 + iter_range: { + IDENT [23] { + name: @index0 + } + } + accu_var: @x1:0 + accu_init: { + CREATE_LIST [24] { + elements: { + } + } + } + loop_condition: { + CONSTANT [25] { value: true } + } + loop_step: { + CALL [26] { + function: _+_ + args: { + IDENT [27] { + name: @x1:0 + } + CREATE_LIST [28] { + elements: { + IDENT [29] { + name: @index1 + } + } + } + } + } + } + result: { + IDENT [30] { + name: @x1:0 + } + } + } + } + } + } + } + } + result: { + IDENT [31] { + name: @x0:0 + } + } + } + } + } + CALL [32] { + function: _==_ + args: { + IDENT [33] { + name: @index4 + } + IDENT [34] { + name: @index3 + } + } + } + } +} +Test case: MACRO_SHADOWED_VARIABLE +Source: [x - 1 > 3 ? x - 1 : 5].exists(x, x - 1 > 3) || x - 1 > 3 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _-_ + args: { + IDENT [4] { + name: x + } + CONSTANT [5] { value: 1 } + } + } + CALL [6] { + function: _>_ + args: { + IDENT [7] { + name: @index0 + } + CONSTANT [8] { value: 3 } + } + } + COMPREHENSION [9] { + iter_var: @c0:0 + iter_range: { + CREATE_LIST [10] { + elements: { + CALL [11] { + function: _?_:_ + args: { + IDENT [12] { + name: @index1 + } + IDENT [13] { + name: @index0 + } + CONSTANT [14] { value: 5 } + } + } + } + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [15] { value: false } + } + loop_condition: { + CALL [16] { + function: @not_strictly_false + args: { + CALL [17] { + function: !_ + args: { + IDENT [18] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + CALL [19] { + function: _||_ + args: { + IDENT [20] { + name: @x0:0 + } + CALL [21] { + function: _>_ + args: { + CALL [22] { + function: _-_ + args: { + IDENT [23] { + name: @c0:0 + } + CONSTANT [24] { value: 1 } + } + } + CONSTANT [25] { value: 3 } + } + } + } + } + } + result: { + IDENT [26] { + name: @x0:0 + } + } + } + } + } + CALL [27] { + function: _||_ + args: { + IDENT [28] { + name: @index2 + } + IDENT [29] { + name: @index1 + } + } + } + } +} +Test case: MACRO_SHADOWED_VARIABLE_2 +Source: ["foo", "bar"].map(x, [x + x, x + x]).map(x, [x + x, x + x]) +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _+_ + args: { + IDENT [4] { + name: @c1:0 + } + IDENT [5] { + name: @c1:0 + } + } + } + CALL [6] { + function: _+_ + args: { + IDENT [7] { + name: @c0:0 + } + IDENT [8] { + name: @c0:0 + } + } + } + CALL [9] { + function: _+_ + args: { + IDENT [10] { + name: @x0:0 + } + CREATE_LIST [11] { + elements: { + CREATE_LIST [12] { + elements: { + IDENT [13] { + name: @index1 + } + IDENT [14] { + name: @index1 + } + } + } + } + } + } + } + COMPREHENSION [15] { + iter_var: @c1:0 + iter_range: { + CREATE_LIST [16] { + elements: { + CONSTANT [17] { value: "foo" } + CONSTANT [18] { value: "bar" } + } + } + } + accu_var: @x1:0 + accu_init: { + CREATE_LIST [19] { + elements: { + } + } + } + loop_condition: { + CONSTANT [20] { value: true } + } + loop_step: { + CALL [21] { + function: _+_ + args: { + IDENT [22] { + name: @x1:0 + } + CREATE_LIST [23] { + elements: { + CREATE_LIST [24] { + elements: { + IDENT [25] { + name: @index0 + } + IDENT [26] { + name: @index0 + } + } + } + } + } + } + } + } + result: { + IDENT [27] { + name: @x1:0 + } + } + } + } + } + COMPREHENSION [28] { + iter_var: @c0:0 + iter_range: { + IDENT [29] { + name: @index3 + } + } + accu_var: @x0:0 + accu_init: { + CREATE_LIST [30] { + elements: { + } + } + } + loop_condition: { + CONSTANT [31] { value: true } + } + loop_step: { + IDENT [32] { + name: @index2 + } + } + result: { + IDENT [33] { + name: @x0:0 + } + } + } + } +} +Test case: PRESENCE_TEST +Source: has({'a': true}.a) && {'a':true}['a'] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: "a" } + } + value: { + CONSTANT [6] { value: true } + } + } + } + CALL [7] { + function: _[_] + args: { + IDENT [8] { + name: @index0 + } + CONSTANT [9] { value: "a" } + } + } + } + } + CALL [10] { + function: _&&_ + args: { + SELECT [11] { + IDENT [12] { + name: @index0 + }.a~presence_test + } + IDENT [13] { + name: @index1 + } + } + } + } +} +Test case: PRESENCE_TEST_WITH_TERNARY +Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : 0) == 10 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + CALL [5] { + function: _?_:_ + args: { + SELECT [6] { + IDENT [7] { + name: @index0 + }.payload~presence_test + } + SELECT [8] { + SELECT [9] { + IDENT [10] { + name: @index0 + }.payload + }.single_int64 + } + CONSTANT [11] { value: 0 } + } + } + } + } + CALL [12] { + function: _==_ + args: { + IDENT [13] { + name: @index1 + } + CONSTANT [14] { value: 10 } + } + } + } +} +Test case: PRESENCE_TEST_WITH_TERNARY_2 +Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : msg.oneof_type.payload.single_int64 * 0) == 10 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.single_int64 + } + CALL [9] { + function: _?_:_ + args: { + SELECT [10] { + IDENT [11] { + name: @index0 + }.payload~presence_test + } + IDENT [12] { + name: @index2 + } + CALL [13] { + function: _*_ + args: { + IDENT [14] { + name: @index2 + } + CONSTANT [15] { value: 0 } + } + } + } + } + } + } + CALL [16] { + function: _==_ + args: { + IDENT [17] { + name: @index3 + } + CONSTANT [18] { value: 10 } + } + } + } +} +Test case: PRESENCE_TEST_WITH_TERNARY_3 +Source: (has(msg.oneof_type.payload.single_int64) ? msg.oneof_type.payload.single_int64 : msg.oneof_type.payload.single_int64 * 0) == 10 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.single_int64 + } + CALL [9] { + function: _?_:_ + args: { + SELECT [10] { + IDENT [11] { + name: @index1 + }.single_int64~presence_test + } + IDENT [12] { + name: @index2 + } + CALL [13] { + function: _*_ + args: { + IDENT [14] { + name: @index2 + } + CONSTANT [15] { value: 0 } + } + } + } + } + } + } + CALL [16] { + function: _==_ + args: { + IDENT [17] { + name: @index3 + } + CONSTANT [18] { value: 10 } + } + } + } +} +Test case: PRESENCE_TEST_WITH_TERNARY_NESTED +Source: (has(msg.oneof_type) && has(msg.oneof_type.payload) && has(msg.oneof_type.payload.single_int64)) ? ((has(msg.oneof_type.payload.map_string_string) && has(msg.oneof_type.payload.map_string_string.key)) ? msg.oneof_type.payload.map_string_string.key == 'A' : false) : false +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.map_string_string + } + CALL [9] { + function: _?_:_ + args: { + CALL [10] { + function: _&&_ + args: { + SELECT [11] { + IDENT [12] { + name: @index1 + }.map_string_string~presence_test + } + SELECT [13] { + IDENT [14] { + name: @index2 + }.key~presence_test + } + } + } + CALL [15] { + function: _==_ + args: { + SELECT [16] { + IDENT [17] { + name: @index2 + }.key + } + CONSTANT [18] { value: "A" } + } + } + CONSTANT [19] { value: false } + } + } + CALL [20] { + function: _&&_ + args: { + CALL [21] { + function: _&&_ + args: { + SELECT [22] { + IDENT [23] { + name: msg + }.oneof_type~presence_test + } + SELECT [24] { + IDENT [25] { + name: @index0 + }.payload~presence_test + } + } + } + SELECT [26] { + IDENT [27] { + name: @index1 + }.single_int64~presence_test + } + } + } + } + } + CALL [28] { + function: _?_:_ + args: { + IDENT [29] { + name: @index4 + } + IDENT [30] { + name: @index3 + } + CONSTANT [31] { value: false } + } + } + } +} +Test case: OPTIONAL_LIST +Source: [10, ?optional.none(), [?optional.none(), ?opt_x], [?optional.none(), ?opt_x]] == [10, [5], [5]] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: optional.none + args: { + } + } + CREATE_LIST [4] { + elements: { + IDENT [5] { + name: @index0 + } + IDENT [6] { + name: opt_x + } + } + optional_indices: [0, 1] + } + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 5 } + } + } + CREATE_LIST [9] { + elements: { + CONSTANT [10] { value: 10 } + IDENT [11] { + name: @index2 + } + IDENT [12] { + name: @index2 + } + } + } + CREATE_LIST [13] { + elements: { + CONSTANT [14] { value: 10 } + IDENT [15] { + name: @index0 + } + IDENT [16] { + name: @index1 + } + IDENT [17] { + name: @index1 + } + } + optional_indices: [0] + } + } + } + CALL [18] { + function: _==_ + args: { + IDENT [19] { + name: @index4 + } + IDENT [20] { + name: @index3 + } + } + } + } +} +Test case: OPTIONAL_MAP +Source: {?'hello': optional.of('hello')}['hello'] + {?'hello': optional.of('hello')}['hello'] == 'hellohello' +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: optional.of + args: { + CONSTANT [4] { value: "hello" } + } + } + CREATE_MAP [5] { + MAP_ENTRY [6] { + key: { + CONSTANT [7] { value: "hello" } + } + optional_entry: true + value: { + IDENT [8] { + name: @index0 + } + } + } + } + CALL [9] { + function: _[_] + args: { + IDENT [10] { + name: @index1 + } + CONSTANT [11] { value: "hello" } + } + } + CALL [12] { + function: _+_ + args: { + IDENT [13] { + name: @index2 + } + IDENT [14] { + name: @index2 + } + } + } + } + } + CALL [15] { + function: _==_ + args: { + IDENT [16] { + name: @index3 + } + CONSTANT [17] { value: "hellohello" } + } + } + } +} +Test case: OPTIONAL_MAP_CHAINED +Source: {?'key': optional.of('test')}[?'bogus'].or({'key': 'test'}[?'bogus']).orValue({'key': 'test'}['key']) == 'test' +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: "key" } + } + value: { + CONSTANT [6] { value: "test" } + } + } + } + CALL [7] { + function: orValue + target: { + CALL [8] { + function: or + target: { + CALL [9] { + function: _[?_] + args: { + CREATE_MAP [10] { + MAP_ENTRY [11] { + key: { + CONSTANT [12] { value: "key" } + } + optional_entry: true + value: { + CALL [13] { + function: optional.of + args: { + CONSTANT [14] { value: "test" } + } + } + } + } + } + CONSTANT [15] { value: "bogus" } + } + } + } + args: { + CALL [16] { + function: _[?_] + args: { + IDENT [17] { + name: @index0 + } + CONSTANT [18] { value: "bogus" } + } + } + } + } + } + args: { + CALL [19] { + function: _[_] + args: { + IDENT [20] { + name: @index0 + } + CONSTANT [21] { value: "key" } + } + } + } + } + } + } + CALL [22] { + function: _==_ + args: { + IDENT [23] { + name: @index1 + } + CONSTANT [24] { value: "test" } + } + } + } +} +Test case: OPTIONAL_MESSAGE +Source: TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}.single_int32 + TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}.single_int64 == 5 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: optional.ofNonZeroValue + args: { + CONSTANT [4] { value: 1 } + } + } + CALL [5] { + function: optional.of + args: { + CONSTANT [6] { value: 4 } + } + } + CREATE_STRUCT [7] { + name: TestAllTypes + entries: { + ENTRY [8] { + field_key: single_int64 + optional_entry: true + value: { + IDENT [9] { + name: @index0 + } + } + } + ENTRY [10] { + field_key: single_int32 + optional_entry: true + value: { + IDENT [11] { + name: @index1 + } + } + } + } + } + CALL [12] { + function: _+_ + args: { + SELECT [13] { + IDENT [14] { + name: @index2 + }.single_int32 + } + SELECT [15] { + IDENT [16] { + name: @index2 + }.single_int64 + } + } + } + } + } + CALL [17] { + function: _==_ + args: { + IDENT [18] { + name: @index3 + } + CONSTANT [19] { value: 5 } + } + } + } +} +Test case: CALL +Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('h' + 'e' + 'l' + 'l' + 'o') +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _+_ + args: { + CONSTANT [4] { value: "h" } + CONSTANT [5] { value: "e" } + } + } + CALL [6] { + function: _+_ + args: { + IDENT [7] { + name: @index0 + } + CONSTANT [8] { value: "l" } + } + } + CALL [9] { + function: _+_ + args: { + IDENT [10] { + name: @index1 + } + CONSTANT [11] { value: "l" } + } + } + CALL [12] { + function: _+_ + args: { + IDENT [13] { + name: @index2 + } + CONSTANT [14] { value: "o" } + } + } + CALL [15] { + function: _+_ + args: { + IDENT [16] { + name: @index3 + } + CONSTANT [17] { value: " world" } + } + } + } + } + CALL [18] { + function: matches + target: { + IDENT [19] { + name: @index4 + } + } + args: { + IDENT [20] { + name: @index3 + } + } + } + } +} +Test case: CALL_ARGUMENT_NESTED_NO_COMMON_SUBEXPR +Source: 'hello world'.matches('h' + 'e' + 'l' + 'l' + 'o') +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _+_ + args: { + CALL [4] { + function: _+_ + args: { + CALL [5] { + function: _+_ + args: { + CALL [6] { + function: _+_ + args: { + CONSTANT [7] { value: "h" } + CONSTANT [8] { value: "e" } + } + } + CONSTANT [9] { value: "l" } + } + } + CONSTANT [10] { value: "l" } + } + } + CONSTANT [11] { value: "o" } + } + } + } + } + CALL [12] { + function: matches + target: { + CONSTANT [13] { value: "hello world" } + } + args: { + IDENT [14] { + name: @index0 + } + } + } + } +} +Test case: CALL_TARGET_NESTED_NO_COMMON_SUBEXPR +Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('hello') +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _+_ + args: { + CALL [4] { + function: _+_ + args: { + CALL [5] { + function: _+_ + args: { + CALL [6] { + function: _+_ + args: { + CALL [7] { + function: _+_ + args: { + CONSTANT [8] { value: "h" } + CONSTANT [9] { value: "e" } + } + } + CONSTANT [10] { value: "l" } + } + } + CONSTANT [11] { value: "l" } + } + } + CONSTANT [12] { value: "o" } + } + } + CONSTANT [13] { value: " world" } + } + } + } + } + CALL [14] { + function: matches + target: { + IDENT [15] { + name: @index0 + } + } + args: { + CONSTANT [16] { value: "hello" } + } + } + } +} +Test case: CALL_BOTH_ARGUMENT_TARGET_NESTED_NO_COMMON_SUBEXPR +Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('w' + 'o' + 'r' + 'l' + 'd') +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _+_ + args: { + CALL [4] { + function: _+_ + args: { + CALL [5] { + function: _+_ + args: { + CALL [6] { + function: _+_ + args: { + CONSTANT [7] { value: "w" } + CONSTANT [8] { value: "o" } + } + } + CONSTANT [9] { value: "r" } + } + } + CONSTANT [10] { value: "l" } + } + } + CONSTANT [11] { value: "d" } + } + } + CALL [12] { + function: _+_ + args: { + CALL [13] { + function: _+_ + args: { + CALL [14] { + function: _+_ + args: { + CALL [15] { + function: _+_ + args: { + CALL [16] { + function: _+_ + args: { + CONSTANT [17] { value: "h" } + CONSTANT [18] { value: "e" } + } + } + CONSTANT [19] { value: "l" } + } + } + CONSTANT [20] { value: "l" } + } + } + CONSTANT [21] { value: "o" } + } + } + CONSTANT [22] { value: " world" } + } + } + } + } + CALL [23] { + function: matches + target: { + IDENT [24] { + name: @index1 + } + } + args: { + IDENT [25] { + name: @index0 + } + } + } + } +} diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_9.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_9.baseline new file mode 100644 index 000000000..0988f15f9 --- /dev/null +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_9.baseline @@ -0,0 +1,3278 @@ +Test case: SIZE_1 +Source: size([1,2]) + size([1,2]) + 1 == 5 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + } + } + CALL [6] { + function: size + args: { + IDENT [7] { + name: @index0 + } + } + } + CALL [8] { + function: _+_ + args: { + CALL [9] { + function: _+_ + args: { + IDENT [10] { + name: @index1 + } + IDENT [11] { + name: @index1 + } + } + } + CONSTANT [12] { value: 1 } + } + } + } + } + CALL [13] { + function: _==_ + args: { + IDENT [14] { + name: @index2 + } + CONSTANT [15] { value: 5 } + } + } + } +} +Test case: SIZE_2 +Source: 2 + size([1,2]) + size([1,2]) + 1 == 7 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + } + } + CALL [6] { + function: size + args: { + IDENT [7] { + name: @index0 + } + } + } + CALL [8] { + function: _+_ + args: { + CALL [9] { + function: _+_ + args: { + CALL [10] { + function: _+_ + args: { + CONSTANT [11] { value: 2 } + IDENT [12] { + name: @index1 + } + } + } + IDENT [13] { + name: @index1 + } + } + } + CONSTANT [14] { value: 1 } + } + } + } + } + CALL [15] { + function: _==_ + args: { + IDENT [16] { + name: @index2 + } + CONSTANT [17] { value: 7 } + } + } + } +} +Test case: SIZE_3 +Source: size([0]) + size([0]) + size([1,2]) + size([1,2]) == 6 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 0 } + } + } + CALL [5] { + function: size + args: { + IDENT [6] { + name: @index0 + } + } + } + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 1 } + CONSTANT [9] { value: 2 } + } + } + CALL [10] { + function: size + args: { + IDENT [11] { + name: @index2 + } + } + } + CALL [12] { + function: _+_ + args: { + CALL [13] { + function: _+_ + args: { + CALL [14] { + function: _+_ + args: { + IDENT [15] { + name: @index1 + } + IDENT [16] { + name: @index1 + } + } + } + IDENT [17] { + name: @index3 + } + } + } + IDENT [18] { + name: @index3 + } + } + } + } + } + CALL [19] { + function: _==_ + args: { + IDENT [20] { + name: @index4 + } + CONSTANT [21] { value: 6 } + } + } + } +} +Test case: SIZE_4 +Source: 5 + size([0]) + size([0]) + size([1,2]) + size([1,2]) + size([1,2,3]) + size([1,2,3]) == 17 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 0 } + } + } + CALL [5] { + function: size + args: { + IDENT [6] { + name: @index0 + } + } + } + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 1 } + CONSTANT [9] { value: 2 } + } + } + CALL [10] { + function: size + args: { + IDENT [11] { + name: @index2 + } + } + } + CREATE_LIST [12] { + elements: { + CONSTANT [13] { value: 1 } + CONSTANT [14] { value: 2 } + CONSTANT [15] { value: 3 } + } + } + CALL [16] { + function: size + args: { + IDENT [17] { + name: @index4 + } + } + } + CALL [18] { + function: _+_ + args: { + CALL [19] { + function: _+_ + args: { + CALL [20] { + function: _+_ + args: { + CALL [21] { + function: _+_ + args: { + CALL [22] { + function: _+_ + args: { + CALL [23] { + function: _+_ + args: { + CONSTANT [24] { value: 5 } + IDENT [25] { + name: @index1 + } + } + } + IDENT [26] { + name: @index1 + } + } + } + IDENT [27] { + name: @index3 + } + } + } + IDENT [28] { + name: @index3 + } + } + } + IDENT [29] { + name: @index5 + } + } + } + IDENT [30] { + name: @index5 + } + } + } + } + } + CALL [31] { + function: _==_ + args: { + IDENT [32] { + name: @index6 + } + CONSTANT [33] { value: 17 } + } + } + } +} +Test case: TIMESTAMP +Source: timestamp(int(timestamp(1000000000))).getFullYear() + timestamp(int(timestamp(75))).getFullYear() + timestamp(int(timestamp(50))).getFullYear() + timestamp(int(timestamp(1000000000))).getFullYear() + timestamp(int(timestamp(50))).getSeconds() + timestamp(int(timestamp(200))).getFullYear() + timestamp(int(timestamp(200))).getFullYear() + timestamp(int(timestamp(75))).getMinutes() + timestamp(int(timestamp(1000000000))).getFullYear() == 13934 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: timestamp + args: { + CONSTANT [4] { value: 1000000000 } + } + } + CALL [5] { + function: int + args: { + IDENT [6] { + name: @index0 + } + } + } + CALL [7] { + function: timestamp + args: { + IDENT [8] { + name: @index1 + } + } + } + CALL [9] { + function: getFullYear + target: { + IDENT [10] { + name: @index2 + } + } + args: { + } + } + CALL [11] { + function: timestamp + args: { + CONSTANT [12] { value: 50 } + } + } + CALL [13] { + function: int + args: { + IDENT [14] { + name: @index4 + } + } + } + CALL [15] { + function: timestamp + args: { + IDENT [16] { + name: @index5 + } + } + } + CALL [17] { + function: timestamp + args: { + CONSTANT [18] { value: 200 } + } + } + CALL [19] { + function: int + args: { + IDENT [20] { + name: @index7 + } + } + } + CALL [21] { + function: timestamp + args: { + IDENT [22] { + name: @index8 + } + } + } + CALL [23] { + function: getFullYear + target: { + IDENT [24] { + name: @index9 + } + } + args: { + } + } + CALL [25] { + function: timestamp + args: { + CONSTANT [26] { value: 75 } + } + } + CALL [27] { + function: int + args: { + IDENT [28] { + name: @index11 + } + } + } + CALL [29] { + function: timestamp + args: { + IDENT [30] { + name: @index12 + } + } + } + CALL [31] { + function: _+_ + args: { + CALL [32] { + function: _+_ + args: { + CALL [33] { + function: _+_ + args: { + CALL [34] { + function: _+_ + args: { + CALL [35] { + function: _+_ + args: { + CALL [36] { + function: _+_ + args: { + CALL [37] { + function: _+_ + args: { + CALL [38] { + function: _+_ + args: { + IDENT [39] { + name: @index3 + } + CALL [40] { + function: getFullYear + target: { + IDENT [41] { + name: @index13 + } + } + args: { + } + } + } + } + CALL [42] { + function: getFullYear + target: { + IDENT [43] { + name: @index6 + } + } + args: { + } + } + } + } + IDENT [44] { + name: @index3 + } + } + } + CALL [45] { + function: getSeconds + target: { + IDENT [46] { + name: @index6 + } + } + args: { + } + } + } + } + IDENT [47] { + name: @index10 + } + } + } + IDENT [48] { + name: @index10 + } + } + } + CALL [49] { + function: getMinutes + target: { + IDENT [50] { + name: @index13 + } + } + args: { + } + } + } + } + IDENT [51] { + name: @index3 + } + } + } + } + } + CALL [52] { + function: _==_ + args: { + IDENT [53] { + name: @index14 + } + CONSTANT [54] { value: 13934 } + } + } + } +} +Test case: MAP_INDEX +Source: {"a": 2}["a"] + {"a": 2}["a"] * {"a": 2}["a"] == 6 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: "a" } + } + value: { + CONSTANT [6] { value: 2 } + } + } + } + CALL [7] { + function: _[_] + args: { + IDENT [8] { + name: @index0 + } + CONSTANT [9] { value: "a" } + } + } + CALL [10] { + function: _+_ + args: { + IDENT [11] { + name: @index1 + } + CALL [12] { + function: _*_ + args: { + IDENT [13] { + name: @index1 + } + IDENT [14] { + name: @index1 + } + } + } + } + } + } + } + CALL [15] { + function: _==_ + args: { + IDENT [16] { + name: @index2 + } + CONSTANT [17] { value: 6 } + } + } + } +} +Test case: NESTED_MAP_CONSTRUCTION +Source: {'a': {'b': 1}, 'c': {'b': 1}, 'd': {'e': {'b': 1}}, 'e': {'e': {'b': 1}}} +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: "b" } + } + value: { + CONSTANT [6] { value: 1 } + } + } + } + CREATE_MAP [7] { + MAP_ENTRY [8] { + key: { + CONSTANT [9] { value: "e" } + } + value: { + IDENT [10] { + name: @index0 + } + } + } + } + } + } + CREATE_MAP [11] { + MAP_ENTRY [12] { + key: { + CONSTANT [13] { value: "a" } + } + value: { + IDENT [14] { + name: @index0 + } + } + } + MAP_ENTRY [15] { + key: { + CONSTANT [16] { value: "c" } + } + value: { + IDENT [17] { + name: @index0 + } + } + } + MAP_ENTRY [18] { + key: { + CONSTANT [19] { value: "d" } + } + value: { + IDENT [20] { + name: @index1 + } + } + } + MAP_ENTRY [21] { + key: { + CONSTANT [22] { value: "e" } + } + value: { + IDENT [23] { + name: @index1 + } + } + } + } + } +} +Test case: NESTED_LIST_CONSTRUCTION +Source: [1, [1,2,3,4], 2, [1,2,3,4], 5, [1,2,3,4], 7, [[1,2], [1,2,3,4]], [1,2]] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + CONSTANT [6] { value: 3 } + CONSTANT [7] { value: 4 } + } + } + CREATE_LIST [8] { + elements: { + CONSTANT [9] { value: 1 } + CONSTANT [10] { value: 2 } + } + } + CREATE_LIST [11] { + elements: { + IDENT [12] { + name: @index1 + } + IDENT [13] { + name: @index0 + } + } + } + } + } + CREATE_LIST [14] { + elements: { + CONSTANT [15] { value: 1 } + IDENT [16] { + name: @index0 + } + CONSTANT [17] { value: 2 } + IDENT [18] { + name: @index0 + } + CONSTANT [19] { value: 5 } + IDENT [20] { + name: @index0 + } + CONSTANT [21] { value: 7 } + IDENT [22] { + name: @index2 + } + IDENT [23] { + name: @index1 + } + } + } + } +} +Test case: SELECT +Source: msg.single_int64 + msg.single_int64 == 6 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.single_int64 + } + CALL [5] { + function: _+_ + args: { + IDENT [6] { + name: @index0 + } + IDENT [7] { + name: @index0 + } + } + } + } + } + CALL [8] { + function: _==_ + args: { + IDENT [9] { + name: @index1 + } + CONSTANT [10] { value: 6 } + } + } + } +} +Test case: SELECT_NESTED_1 +Source: msg.oneof_type.payload.single_int64 + msg.oneof_type.payload.single_int32 + msg.oneof_type.payload.single_int64 + msg.single_int64 + msg.oneof_type.payload.oneof_type.payload.single_int64 == 31 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.single_int64 + } + CALL [9] { + function: _+_ + args: { + CALL [10] { + function: _+_ + args: { + CALL [11] { + function: _+_ + args: { + CALL [12] { + function: _+_ + args: { + IDENT [13] { + name: @index2 + } + SELECT [14] { + IDENT [15] { + name: @index1 + }.single_int32 + } + } + } + IDENT [16] { + name: @index2 + } + } + } + SELECT [17] { + IDENT [18] { + name: msg + }.single_int64 + } + } + } + SELECT [19] { + SELECT [20] { + SELECT [21] { + IDENT [22] { + name: @index1 + }.oneof_type + }.payload + }.single_int64 + } + } + } + } + } + CALL [23] { + function: _==_ + args: { + IDENT [24] { + name: @index3 + } + CONSTANT [25] { value: 31 } + } + } + } +} +Test case: SELECT_NESTED_2 +Source: true || msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload.single_bool || msg.oneof_type.payload.oneof_type.payload.oneof_type.child.child.payload.single_bool +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.oneof_type + } + SELECT [9] { + IDENT [10] { + name: @index2 + }.payload + } + SELECT [11] { + IDENT [12] { + name: @index3 + }.oneof_type + } + SELECT [13] { + SELECT [14] { + SELECT [15] { + SELECT [16] { + IDENT [17] { + name: @index4 + }.child + }.child + }.payload + }.single_bool + } + CALL [18] { + function: _||_ + args: { + CONSTANT [19] { value: true } + SELECT [20] { + SELECT [21] { + SELECT [22] { + SELECT [23] { + IDENT [24] { + name: @index4 + }.payload + }.oneof_type + }.payload + }.single_bool + } + } + } + } + } + CALL [25] { + function: _||_ + args: { + IDENT [26] { + name: @index6 + } + IDENT [27] { + name: @index5 + } + } + } + } +} +Test case: SELECT_NESTED_MESSAGE_MAP_INDEX_1 +Source: msg.oneof_type.payload.map_int32_int64[1] + msg.oneof_type.payload.map_int32_int64[1] + msg.oneof_type.payload.map_int32_int64[1] == 15 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.map_int32_int64 + } + CALL [9] { + function: _[_] + args: { + IDENT [10] { + name: @index2 + } + CONSTANT [11] { value: 1 } + } + } + CALL [12] { + function: _+_ + args: { + CALL [13] { + function: _+_ + args: { + IDENT [14] { + name: @index3 + } + IDENT [15] { + name: @index3 + } + } + } + IDENT [16] { + name: @index3 + } + } + } + } + } + CALL [17] { + function: _==_ + args: { + IDENT [18] { + name: @index4 + } + CONSTANT [19] { value: 15 } + } + } + } +} +Test case: SELECT_NESTED_MESSAGE_MAP_INDEX_2 +Source: msg.oneof_type.payload.map_int32_int64[0] + msg.oneof_type.payload.map_int32_int64[1] + msg.oneof_type.payload.map_int32_int64[2] == 8 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.map_int32_int64 + } + CALL [9] { + function: _+_ + args: { + CALL [10] { + function: _+_ + args: { + CALL [11] { + function: _[_] + args: { + IDENT [12] { + name: @index2 + } + CONSTANT [13] { value: 0 } + } + } + CALL [14] { + function: _[_] + args: { + IDENT [15] { + name: @index2 + } + CONSTANT [16] { value: 1 } + } + } + } + } + CALL [17] { + function: _[_] + args: { + IDENT [18] { + name: @index2 + } + CONSTANT [19] { value: 2 } + } + } + } + } + } + } + CALL [20] { + function: _==_ + args: { + IDENT [21] { + name: @index3 + } + CONSTANT [22] { value: 8 } + } + } + } +} +Test case: SELECT_NESTED_NO_COMMON_SUBEXPR +Source: msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload.single_int64 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + SELECT [4] { + SELECT [5] { + SELECT [6] { + SELECT [7] { + SELECT [8] { + SELECT [9] { + SELECT [10] { + IDENT [11] { + name: msg + }.oneof_type + }.payload + }.oneof_type + }.payload + }.oneof_type + }.payload + }.oneof_type + }.payload + } + } + } + SELECT [12] { + IDENT [13] { + name: @index0 + }.single_int64 + } + } +} +Test case: TERNARY +Source: (msg.single_int64 > 0 ? msg.single_int64 : 0) == 3 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.single_int64 + } + CALL [5] { + function: _?_:_ + args: { + CALL [6] { + function: _>_ + args: { + IDENT [7] { + name: @index0 + } + CONSTANT [8] { value: 0 } + } + } + IDENT [9] { + name: @index0 + } + CONSTANT [10] { value: 0 } + } + } + } + } + CALL [11] { + function: _==_ + args: { + IDENT [12] { + name: @index1 + } + CONSTANT [13] { value: 3 } + } + } + } +} +Test case: TERNARY_BIND_RHS_ONLY +Source: false ? false : (msg.single_int64) + ((msg.single_int64 + 1) * 2) == 11 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.single_int64 + } + CALL [5] { + function: _==_ + args: { + CALL [6] { + function: _+_ + args: { + IDENT [7] { + name: @index0 + } + CALL [8] { + function: _*_ + args: { + CALL [9] { + function: _+_ + args: { + IDENT [10] { + name: @index0 + } + CONSTANT [11] { value: 1 } + } + } + CONSTANT [12] { value: 2 } + } + } + } + } + CONSTANT [13] { value: 11 } + } + } + } + } + CALL [14] { + function: _?_:_ + args: { + CONSTANT [15] { value: false } + CONSTANT [16] { value: false } + IDENT [17] { + name: @index1 + } + } + } + } +} +Test case: NESTED_TERNARY +Source: (msg.single_int64 > 0 ? (msg.single_int32 > 0 ? msg.single_int64 + msg.single_int32 : 0) : 0) == 8 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.single_int64 + } + SELECT [5] { + IDENT [6] { + name: msg + }.single_int32 + } + CALL [7] { + function: _?_:_ + args: { + CALL [8] { + function: _>_ + args: { + IDENT [9] { + name: @index0 + } + CONSTANT [10] { value: 0 } + } + } + CALL [11] { + function: _?_:_ + args: { + CALL [12] { + function: _>_ + args: { + IDENT [13] { + name: @index1 + } + CONSTANT [14] { value: 0 } + } + } + CALL [15] { + function: _+_ + args: { + IDENT [16] { + name: @index0 + } + IDENT [17] { + name: @index1 + } + } + } + CONSTANT [18] { value: 0 } + } + } + CONSTANT [19] { value: 0 } + } + } + } + } + CALL [20] { + function: _==_ + args: { + IDENT [21] { + name: @index2 + } + CONSTANT [22] { value: 8 } + } + } + } +} +Test case: MULTIPLE_MACROS_1 +Source: size([[1].exists(i, i > 0)]) + size([[1].exists(j, j > 0)]) + size([[2].exists(k, k > 1)]) + size([[2].exists(l, l > 1)]) == 4 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + } + } + CALL [5] { + function: _>_ + args: { + IDENT [6] { + name: @c0:0 + } + CONSTANT [7] { value: 0 } + } + } + CALL [8] { + function: _||_ + args: { + IDENT [9] { + name: @x0:0 + } + IDENT [10] { + name: @index1 + } + } + } + COMPREHENSION [11] { + iter_var: @c0:0 + iter_range: { + IDENT [12] { + name: @index0 + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [13] { value: false } + } + loop_condition: { + CALL [14] { + function: @not_strictly_false + args: { + CALL [15] { + function: !_ + args: { + IDENT [16] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + IDENT [17] { + name: @index2 + } + } + result: { + IDENT [18] { + name: @x0:0 + } + } + } + CREATE_LIST [19] { + elements: { + IDENT [20] { + name: @index3 + } + } + } + CALL [21] { + function: size + args: { + IDENT [22] { + name: @index4 + } + } + } + CREATE_LIST [23] { + elements: { + CONSTANT [24] { value: 2 } + } + } + CALL [25] { + function: _>_ + args: { + IDENT [26] { + name: @c0:0 + } + CONSTANT [27] { value: 1 } + } + } + CALL [28] { + function: _||_ + args: { + IDENT [29] { + name: @x0:0 + } + IDENT [30] { + name: @index7 + } + } + } + COMPREHENSION [31] { + iter_var: @c0:0 + iter_range: { + IDENT [32] { + name: @index6 + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [33] { value: false } + } + loop_condition: { + CALL [34] { + function: @not_strictly_false + args: { + CALL [35] { + function: !_ + args: { + IDENT [36] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + IDENT [37] { + name: @index8 + } + } + result: { + IDENT [38] { + name: @x0:0 + } + } + } + CREATE_LIST [39] { + elements: { + IDENT [40] { + name: @index9 + } + } + } + CALL [41] { + function: size + args: { + IDENT [42] { + name: @index10 + } + } + } + CALL [43] { + function: _+_ + args: { + CALL [44] { + function: _+_ + args: { + CALL [45] { + function: _+_ + args: { + IDENT [46] { + name: @index5 + } + IDENT [47] { + name: @index5 + } + } + } + IDENT [48] { + name: @index11 + } + } + } + IDENT [49] { + name: @index11 + } + } + } + } + } + CALL [50] { + function: _==_ + args: { + IDENT [51] { + name: @index12 + } + CONSTANT [52] { value: 4 } + } + } + } +} +Test case: MULTIPLE_MACROS_2 +Source: [[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == 'a')] + [['a'].exists(l, l == 'a')] == [true, true, true, true] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + } + } + CALL [5] { + function: _>_ + args: { + IDENT [6] { + name: @c0:0 + } + CONSTANT [7] { value: 0 } + } + } + CALL [8] { + function: _||_ + args: { + IDENT [9] { + name: @x0:0 + } + IDENT [10] { + name: @index1 + } + } + } + COMPREHENSION [11] { + iter_var: @c0:0 + iter_range: { + IDENT [12] { + name: @index0 + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [13] { value: false } + } + loop_condition: { + CALL [14] { + function: @not_strictly_false + args: { + CALL [15] { + function: !_ + args: { + IDENT [16] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + IDENT [17] { + name: @index2 + } + } + result: { + IDENT [18] { + name: @x0:0 + } + } + } + CREATE_LIST [19] { + elements: { + IDENT [20] { + name: @index3 + } + } + } + CREATE_LIST [21] { + elements: { + CONSTANT [22] { value: "a" } + } + } + CALL [23] { + function: _==_ + args: { + IDENT [24] { + name: @c0:1 + } + CONSTANT [25] { value: "a" } + } + } + CALL [26] { + function: _||_ + args: { + IDENT [27] { + name: @x0:1 + } + IDENT [28] { + name: @index6 + } + } + } + COMPREHENSION [29] { + iter_var: @c0:1 + iter_range: { + IDENT [30] { + name: @index5 + } + } + accu_var: @x0:1 + accu_init: { + CONSTANT [31] { value: false } + } + loop_condition: { + CALL [32] { + function: @not_strictly_false + args: { + CALL [33] { + function: !_ + args: { + IDENT [34] { + name: @x0:1 + } + } + } + } + } + } + loop_step: { + IDENT [35] { + name: @index7 + } + } + result: { + IDENT [36] { + name: @x0:1 + } + } + } + CREATE_LIST [37] { + elements: { + IDENT [38] { + name: @index8 + } + } + } + CREATE_LIST [39] { + elements: { + CONSTANT [40] { value: true } + CONSTANT [41] { value: true } + CONSTANT [42] { value: true } + CONSTANT [43] { value: true } + } + } + CALL [44] { + function: _+_ + args: { + CALL [45] { + function: _+_ + args: { + CALL [46] { + function: _+_ + args: { + IDENT [47] { + name: @index4 + } + IDENT [48] { + name: @index4 + } + } + } + IDENT [49] { + name: @index9 + } + } + } + IDENT [50] { + name: @index9 + } + } + } + } + } + CALL [51] { + function: _==_ + args: { + IDENT [52] { + name: @index11 + } + IDENT [53] { + name: @index10 + } + } + } + } +} +Test case: NESTED_MACROS +Source: [1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [[2, 3, 4], [2, 3, 4], [2, 3, 4]] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + CONSTANT [6] { value: 3 } + } + } + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 2 } + CONSTANT [9] { value: 3 } + CONSTANT [10] { value: 4 } + } + } + CREATE_LIST [11] { + elements: { + IDENT [12] { + name: @index1 + } + IDENT [13] { + name: @index1 + } + IDENT [14] { + name: @index1 + } + } + } + COMPREHENSION [15] { + iter_var: @c0:0 + iter_range: { + IDENT [16] { + name: @index0 + } + } + accu_var: @x0:0 + accu_init: { + CREATE_LIST [17] { + elements: { + } + } + } + loop_condition: { + CONSTANT [18] { value: true } + } + loop_step: { + CALL [19] { + function: _+_ + args: { + IDENT [20] { + name: @x0:0 + } + CREATE_LIST [21] { + elements: { + COMPREHENSION [22] { + iter_var: @c1:0 + iter_range: { + IDENT [23] { + name: @index0 + } + } + accu_var: @x1:0 + accu_init: { + CREATE_LIST [24] { + elements: { + } + } + } + loop_condition: { + CONSTANT [25] { value: true } + } + loop_step: { + CALL [26] { + function: _+_ + args: { + IDENT [27] { + name: @x1:0 + } + CREATE_LIST [28] { + elements: { + CALL [29] { + function: _+_ + args: { + IDENT [30] { + name: @c1:0 + } + CONSTANT [31] { value: 1 } + } + } + } + } + } + } + } + result: { + IDENT [32] { + name: @x1:0 + } + } + } + } + } + } + } + } + result: { + IDENT [33] { + name: @x0:0 + } + } + } + } + } + CALL [34] { + function: _==_ + args: { + IDENT [35] { + name: @index3 + } + IDENT [36] { + name: @index2 + } + } + } + } +} +Test case: NESTED_MACROS_2 +Source: [1, 2].map(y, [1, 2, 3].filter(x, x == y)) == [[1], [2]] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CREATE_LIST [4] { + elements: { + CONSTANT [5] { value: 1 } + } + } + CREATE_LIST [6] { + elements: { + CONSTANT [7] { value: 2 } + } + } + } + } + COMPREHENSION [8] { + iter_var: @c0:0 + iter_range: { + CREATE_LIST [9] { + elements: { + CONSTANT [10] { value: 1 } + CONSTANT [11] { value: 2 } + } + } + } + accu_var: @x0:0 + accu_init: { + CREATE_LIST [12] { + elements: { + } + } + } + loop_condition: { + CONSTANT [13] { value: true } + } + loop_step: { + CALL [14] { + function: _+_ + args: { + IDENT [15] { + name: @x0:0 + } + CREATE_LIST [16] { + elements: { + COMPREHENSION [17] { + iter_var: @c1:0 + iter_range: { + CREATE_LIST [18] { + elements: { + CONSTANT [19] { value: 1 } + CONSTANT [20] { value: 2 } + CONSTANT [21] { value: 3 } + } + } + } + accu_var: @x1:0 + accu_init: { + CREATE_LIST [22] { + elements: { + } + } + } + loop_condition: { + CONSTANT [23] { value: true } + } + loop_step: { + CALL [24] { + function: _?_:_ + args: { + CALL [25] { + function: _==_ + args: { + IDENT [26] { + name: @c1:0 + } + IDENT [27] { + name: @c0:0 + } + } + } + CALL [28] { + function: _+_ + args: { + IDENT [29] { + name: @x1:0 + } + CREATE_LIST [30] { + elements: { + IDENT [31] { + name: @c1:0 + } + } + } + } + } + IDENT [32] { + name: @x1:0 + } + } + } + } + result: { + IDENT [33] { + name: @x1:0 + } + } + } + } + } + } + } + } + result: { + IDENT [34] { + name: @x0:0 + } + } + } + } + } + CALL [35] { + function: _==_ + args: { + IDENT [36] { + name: @index1 + } + IDENT [37] { + name: @index0 + } + } + } + } +} +Test case: INCLUSION_LIST +Source: 1 in [1,2,3] && 2 in [1,2,3] && 3 in [3, [1,2,3]] && 1 in [1,2,3] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + CONSTANT [6] { value: 3 } + } + } + CALL [7] { + function: @in + args: { + CONSTANT [8] { value: 1 } + IDENT [9] { + name: @index0 + } + } + } + CALL [10] { + function: _&&_ + args: { + CALL [11] { + function: @in + args: { + CONSTANT [12] { value: 3 } + CREATE_LIST [13] { + elements: { + CONSTANT [14] { value: 3 } + IDENT [15] { + name: @index0 + } + } + } + } + } + IDENT [16] { + name: @index1 + } + } + } + CALL [17] { + function: _&&_ + args: { + IDENT [18] { + name: @index1 + } + CALL [19] { + function: @in + args: { + CONSTANT [20] { value: 2 } + IDENT [21] { + name: @index0 + } + } + } + } + } + } + } + CALL [22] { + function: _&&_ + args: { + IDENT [23] { + name: @index3 + } + IDENT [24] { + name: @index2 + } + } + } + } +} +Test case: INCLUSION_MAP +Source: 2 in {'a': 1, 2: {true: false}, 3: {true: false}} +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: true } + } + value: { + CONSTANT [6] { value: false } + } + } + } + CREATE_MAP [7] { + MAP_ENTRY [8] { + key: { + CONSTANT [9] { value: "a" } + } + value: { + CONSTANT [10] { value: 1 } + } + } + MAP_ENTRY [11] { + key: { + CONSTANT [12] { value: 2 } + } + value: { + IDENT [13] { + name: @index0 + } + } + } + MAP_ENTRY [14] { + key: { + CONSTANT [15] { value: 3 } + } + value: { + IDENT [16] { + name: @index0 + } + } + } + } + } + } + CALL [17] { + function: @in + args: { + CONSTANT [18] { value: 2 } + IDENT [19] { + name: @index1 + } + } + } + } +} +Test case: MACRO_ITER_VAR_NOT_REFERENCED +Source: [1,2].map(i, [1, 2].map(i, [3,4])) == [[[3, 4], [3, 4]], [[3, 4], [3, 4]]] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + } + } + CREATE_LIST [6] { + elements: { + CONSTANT [7] { value: 3 } + CONSTANT [8] { value: 4 } + } + } + CREATE_LIST [9] { + elements: { + IDENT [10] { + name: @index1 + } + IDENT [11] { + name: @index1 + } + } + } + CREATE_LIST [12] { + elements: { + IDENT [13] { + name: @index2 + } + IDENT [14] { + name: @index2 + } + } + } + COMPREHENSION [15] { + iter_var: @c0:0 + iter_range: { + IDENT [16] { + name: @index0 + } + } + accu_var: @x0:0 + accu_init: { + CREATE_LIST [17] { + elements: { + } + } + } + loop_condition: { + CONSTANT [18] { value: true } + } + loop_step: { + CALL [19] { + function: _+_ + args: { + IDENT [20] { + name: @x0:0 + } + CREATE_LIST [21] { + elements: { + COMPREHENSION [22] { + iter_var: @c1:0 + iter_range: { + IDENT [23] { + name: @index0 + } + } + accu_var: @x1:0 + accu_init: { + CREATE_LIST [24] { + elements: { + } + } + } + loop_condition: { + CONSTANT [25] { value: true } + } + loop_step: { + CALL [26] { + function: _+_ + args: { + IDENT [27] { + name: @x1:0 + } + CREATE_LIST [28] { + elements: { + IDENT [29] { + name: @index1 + } + } + } + } + } + } + result: { + IDENT [30] { + name: @x1:0 + } + } + } + } + } + } + } + } + result: { + IDENT [31] { + name: @x0:0 + } + } + } + } + } + CALL [32] { + function: _==_ + args: { + IDENT [33] { + name: @index4 + } + IDENT [34] { + name: @index3 + } + } + } + } +} +Test case: MACRO_SHADOWED_VARIABLE +Source: [x - 1 > 3 ? x - 1 : 5].exists(x, x - 1 > 3) || x - 1 > 3 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _-_ + args: { + IDENT [4] { + name: x + } + CONSTANT [5] { value: 1 } + } + } + CALL [6] { + function: _>_ + args: { + IDENT [7] { + name: @index0 + } + CONSTANT [8] { value: 3 } + } + } + COMPREHENSION [9] { + iter_var: @c0:0 + iter_range: { + CREATE_LIST [10] { + elements: { + CALL [11] { + function: _?_:_ + args: { + IDENT [12] { + name: @index1 + } + IDENT [13] { + name: @index0 + } + CONSTANT [14] { value: 5 } + } + } + } + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [15] { value: false } + } + loop_condition: { + CALL [16] { + function: @not_strictly_false + args: { + CALL [17] { + function: !_ + args: { + IDENT [18] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + CALL [19] { + function: _||_ + args: { + IDENT [20] { + name: @x0:0 + } + CALL [21] { + function: _>_ + args: { + CALL [22] { + function: _-_ + args: { + IDENT [23] { + name: @c0:0 + } + CONSTANT [24] { value: 1 } + } + } + CONSTANT [25] { value: 3 } + } + } + } + } + } + result: { + IDENT [26] { + name: @x0:0 + } + } + } + } + } + CALL [27] { + function: _||_ + args: { + IDENT [28] { + name: @index2 + } + IDENT [29] { + name: @index1 + } + } + } + } +} +Test case: MACRO_SHADOWED_VARIABLE_2 +Source: ["foo", "bar"].map(x, [x + x, x + x]).map(x, [x + x, x + x]) +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _+_ + args: { + IDENT [4] { + name: @c1:0 + } + IDENT [5] { + name: @c1:0 + } + } + } + CALL [6] { + function: _+_ + args: { + IDENT [7] { + name: @c0:0 + } + IDENT [8] { + name: @c0:0 + } + } + } + CALL [9] { + function: _+_ + args: { + IDENT [10] { + name: @x0:0 + } + CREATE_LIST [11] { + elements: { + CREATE_LIST [12] { + elements: { + IDENT [13] { + name: @index1 + } + IDENT [14] { + name: @index1 + } + } + } + } + } + } + } + COMPREHENSION [15] { + iter_var: @c1:0 + iter_range: { + CREATE_LIST [16] { + elements: { + CONSTANT [17] { value: "foo" } + CONSTANT [18] { value: "bar" } + } + } + } + accu_var: @x1:0 + accu_init: { + CREATE_LIST [19] { + elements: { + } + } + } + loop_condition: { + CONSTANT [20] { value: true } + } + loop_step: { + CALL [21] { + function: _+_ + args: { + IDENT [22] { + name: @x1:0 + } + CREATE_LIST [23] { + elements: { + CREATE_LIST [24] { + elements: { + IDENT [25] { + name: @index0 + } + IDENT [26] { + name: @index0 + } + } + } + } + } + } + } + } + result: { + IDENT [27] { + name: @x1:0 + } + } + } + } + } + COMPREHENSION [28] { + iter_var: @c0:0 + iter_range: { + IDENT [29] { + name: @index3 + } + } + accu_var: @x0:0 + accu_init: { + CREATE_LIST [30] { + elements: { + } + } + } + loop_condition: { + CONSTANT [31] { value: true } + } + loop_step: { + IDENT [32] { + name: @index2 + } + } + result: { + IDENT [33] { + name: @x0:0 + } + } + } + } +} +Test case: PRESENCE_TEST +Source: has({'a': true}.a) && {'a':true}['a'] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: "a" } + } + value: { + CONSTANT [6] { value: true } + } + } + } + CALL [7] { + function: _[_] + args: { + IDENT [8] { + name: @index0 + } + CONSTANT [9] { value: "a" } + } + } + } + } + CALL [10] { + function: _&&_ + args: { + SELECT [11] { + IDENT [12] { + name: @index0 + }.a~presence_test + } + IDENT [13] { + name: @index1 + } + } + } + } +} +Test case: PRESENCE_TEST_WITH_TERNARY +Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : 0) == 10 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + CALL [5] { + function: _?_:_ + args: { + SELECT [6] { + IDENT [7] { + name: @index0 + }.payload~presence_test + } + SELECT [8] { + SELECT [9] { + IDENT [10] { + name: @index0 + }.payload + }.single_int64 + } + CONSTANT [11] { value: 0 } + } + } + } + } + CALL [12] { + function: _==_ + args: { + IDENT [13] { + name: @index1 + } + CONSTANT [14] { value: 10 } + } + } + } +} +Test case: PRESENCE_TEST_WITH_TERNARY_2 +Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : msg.oneof_type.payload.single_int64 * 0) == 10 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.single_int64 + } + CALL [9] { + function: _?_:_ + args: { + SELECT [10] { + IDENT [11] { + name: @index0 + }.payload~presence_test + } + IDENT [12] { + name: @index2 + } + CALL [13] { + function: _*_ + args: { + IDENT [14] { + name: @index2 + } + CONSTANT [15] { value: 0 } + } + } + } + } + } + } + CALL [16] { + function: _==_ + args: { + IDENT [17] { + name: @index3 + } + CONSTANT [18] { value: 10 } + } + } + } +} +Test case: PRESENCE_TEST_WITH_TERNARY_3 +Source: (has(msg.oneof_type.payload.single_int64) ? msg.oneof_type.payload.single_int64 : msg.oneof_type.payload.single_int64 * 0) == 10 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.single_int64 + } + CALL [9] { + function: _?_:_ + args: { + SELECT [10] { + IDENT [11] { + name: @index1 + }.single_int64~presence_test + } + IDENT [12] { + name: @index2 + } + CALL [13] { + function: _*_ + args: { + IDENT [14] { + name: @index2 + } + CONSTANT [15] { value: 0 } + } + } + } + } + } + } + CALL [16] { + function: _==_ + args: { + IDENT [17] { + name: @index3 + } + CONSTANT [18] { value: 10 } + } + } + } +} +Test case: PRESENCE_TEST_WITH_TERNARY_NESTED +Source: (has(msg.oneof_type) && has(msg.oneof_type.payload) && has(msg.oneof_type.payload.single_int64)) ? ((has(msg.oneof_type.payload.map_string_string) && has(msg.oneof_type.payload.map_string_string.key)) ? msg.oneof_type.payload.map_string_string.key == 'A' : false) : false +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.map_string_string + } + CALL [9] { + function: _?_:_ + args: { + CALL [10] { + function: _&&_ + args: { + SELECT [11] { + IDENT [12] { + name: @index1 + }.map_string_string~presence_test + } + SELECT [13] { + IDENT [14] { + name: @index2 + }.key~presence_test + } + } + } + CALL [15] { + function: _==_ + args: { + SELECT [16] { + IDENT [17] { + name: @index2 + }.key + } + CONSTANT [18] { value: "A" } + } + } + CONSTANT [19] { value: false } + } + } + CALL [20] { + function: _&&_ + args: { + CALL [21] { + function: _&&_ + args: { + SELECT [22] { + IDENT [23] { + name: msg + }.oneof_type~presence_test + } + SELECT [24] { + IDENT [25] { + name: @index0 + }.payload~presence_test + } + } + } + SELECT [26] { + IDENT [27] { + name: @index1 + }.single_int64~presence_test + } + } + } + } + } + CALL [28] { + function: _?_:_ + args: { + IDENT [29] { + name: @index4 + } + IDENT [30] { + name: @index3 + } + CONSTANT [31] { value: false } + } + } + } +} +Test case: OPTIONAL_LIST +Source: [10, ?optional.none(), [?optional.none(), ?opt_x], [?optional.none(), ?opt_x]] == [10, [5], [5]] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: optional.none + args: { + } + } + CREATE_LIST [4] { + elements: { + IDENT [5] { + name: @index0 + } + IDENT [6] { + name: opt_x + } + } + optional_indices: [0, 1] + } + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 5 } + } + } + CREATE_LIST [9] { + elements: { + CONSTANT [10] { value: 10 } + IDENT [11] { + name: @index2 + } + IDENT [12] { + name: @index2 + } + } + } + CREATE_LIST [13] { + elements: { + CONSTANT [14] { value: 10 } + IDENT [15] { + name: @index0 + } + IDENT [16] { + name: @index1 + } + IDENT [17] { + name: @index1 + } + } + optional_indices: [0] + } + } + } + CALL [18] { + function: _==_ + args: { + IDENT [19] { + name: @index4 + } + IDENT [20] { + name: @index3 + } + } + } + } +} +Test case: OPTIONAL_MAP +Source: {?'hello': optional.of('hello')}['hello'] + {?'hello': optional.of('hello')}['hello'] == 'hellohello' +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: optional.of + args: { + CONSTANT [4] { value: "hello" } + } + } + CREATE_MAP [5] { + MAP_ENTRY [6] { + key: { + CONSTANT [7] { value: "hello" } + } + optional_entry: true + value: { + IDENT [8] { + name: @index0 + } + } + } + } + CALL [9] { + function: _[_] + args: { + IDENT [10] { + name: @index1 + } + CONSTANT [11] { value: "hello" } + } + } + CALL [12] { + function: _+_ + args: { + IDENT [13] { + name: @index2 + } + IDENT [14] { + name: @index2 + } + } + } + } + } + CALL [15] { + function: _==_ + args: { + IDENT [16] { + name: @index3 + } + CONSTANT [17] { value: "hellohello" } + } + } + } +} +Test case: OPTIONAL_MAP_CHAINED +Source: {?'key': optional.of('test')}[?'bogus'].or({'key': 'test'}[?'bogus']).orValue({'key': 'test'}['key']) == 'test' +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: "key" } + } + value: { + CONSTANT [6] { value: "test" } + } + } + } + CALL [7] { + function: orValue + target: { + CALL [8] { + function: or + target: { + CALL [9] { + function: _[?_] + args: { + CREATE_MAP [10] { + MAP_ENTRY [11] { + key: { + CONSTANT [12] { value: "key" } + } + optional_entry: true + value: { + CALL [13] { + function: optional.of + args: { + CONSTANT [14] { value: "test" } + } + } + } + } + } + CONSTANT [15] { value: "bogus" } + } + } + } + args: { + CALL [16] { + function: _[?_] + args: { + IDENT [17] { + name: @index0 + } + CONSTANT [18] { value: "bogus" } + } + } + } + } + } + args: { + CALL [19] { + function: _[_] + args: { + IDENT [20] { + name: @index0 + } + CONSTANT [21] { value: "key" } + } + } + } + } + } + } + CALL [22] { + function: _==_ + args: { + IDENT [23] { + name: @index1 + } + CONSTANT [24] { value: "test" } + } + } + } +} +Test case: OPTIONAL_MESSAGE +Source: TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}.single_int32 + TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}.single_int64 == 5 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: optional.ofNonZeroValue + args: { + CONSTANT [4] { value: 1 } + } + } + CALL [5] { + function: optional.of + args: { + CONSTANT [6] { value: 4 } + } + } + CREATE_STRUCT [7] { + name: TestAllTypes + entries: { + ENTRY [8] { + field_key: single_int64 + optional_entry: true + value: { + IDENT [9] { + name: @index0 + } + } + } + ENTRY [10] { + field_key: single_int32 + optional_entry: true + value: { + IDENT [11] { + name: @index1 + } + } + } + } + } + CALL [12] { + function: _+_ + args: { + SELECT [13] { + IDENT [14] { + name: @index2 + }.single_int32 + } + SELECT [15] { + IDENT [16] { + name: @index2 + }.single_int64 + } + } + } + } + } + CALL [17] { + function: _==_ + args: { + IDENT [18] { + name: @index3 + } + CONSTANT [19] { value: 5 } + } + } + } +} +Test case: CALL +Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('h' + 'e' + 'l' + 'l' + 'o') +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _+_ + args: { + CONSTANT [4] { value: "h" } + CONSTANT [5] { value: "e" } + } + } + CALL [6] { + function: _+_ + args: { + IDENT [7] { + name: @index0 + } + CONSTANT [8] { value: "l" } + } + } + CALL [9] { + function: _+_ + args: { + IDENT [10] { + name: @index1 + } + CONSTANT [11] { value: "l" } + } + } + CALL [12] { + function: _+_ + args: { + IDENT [13] { + name: @index2 + } + CONSTANT [14] { value: "o" } + } + } + CALL [15] { + function: _+_ + args: { + IDENT [16] { + name: @index3 + } + CONSTANT [17] { value: " world" } + } + } + } + } + CALL [18] { + function: matches + target: { + IDENT [19] { + name: @index4 + } + } + args: { + IDENT [20] { + name: @index3 + } + } + } + } +} +Test case: CALL_ARGUMENT_NESTED_NO_COMMON_SUBEXPR +Source: 'hello world'.matches('h' + 'e' + 'l' + 'l' + 'o') +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _+_ + args: { + CALL [4] { + function: _+_ + args: { + CALL [5] { + function: _+_ + args: { + CALL [6] { + function: _+_ + args: { + CONSTANT [7] { value: "h" } + CONSTANT [8] { value: "e" } + } + } + CONSTANT [9] { value: "l" } + } + } + CONSTANT [10] { value: "l" } + } + } + CONSTANT [11] { value: "o" } + } + } + } + } + CALL [12] { + function: matches + target: { + CONSTANT [13] { value: "hello world" } + } + args: { + IDENT [14] { + name: @index0 + } + } + } + } +} +Test case: CALL_TARGET_NESTED_NO_COMMON_SUBEXPR +Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('hello') +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _+_ + args: { + CALL [4] { + function: _+_ + args: { + CALL [5] { + function: _+_ + args: { + CALL [6] { + function: _+_ + args: { + CALL [7] { + function: _+_ + args: { + CONSTANT [8] { value: "h" } + CONSTANT [9] { value: "e" } + } + } + CONSTANT [10] { value: "l" } + } + } + CONSTANT [11] { value: "l" } + } + } + CONSTANT [12] { value: "o" } + } + } + CONSTANT [13] { value: " world" } + } + } + } + } + CALL [14] { + function: matches + target: { + IDENT [15] { + name: @index0 + } + } + args: { + CONSTANT [16] { value: "hello" } + } + } + } +} +Test case: CALL_BOTH_ARGUMENT_TARGET_NESTED_NO_COMMON_SUBEXPR +Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('w' + 'o' + 'r' + 'l' + 'd') +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _+_ + args: { + CALL [4] { + function: _+_ + args: { + CALL [5] { + function: _+_ + args: { + CALL [6] { + function: _+_ + args: { + CONSTANT [7] { value: "w" } + CONSTANT [8] { value: "o" } + } + } + CONSTANT [9] { value: "r" } + } + } + CONSTANT [10] { value: "l" } + } + } + CONSTANT [11] { value: "d" } + } + } + CALL [12] { + function: _+_ + args: { + CALL [13] { + function: _+_ + args: { + CALL [14] { + function: _+_ + args: { + CALL [15] { + function: _+_ + args: { + CALL [16] { + function: _+_ + args: { + CONSTANT [17] { value: "h" } + CONSTANT [18] { value: "e" } + } + } + CONSTANT [19] { value: "l" } + } + } + CONSTANT [20] { value: "l" } + } + } + CONSTANT [21] { value: "o" } + } + } + CONSTANT [22] { value: " world" } + } + } + } + } + CALL [23] { + function: matches + target: { + IDENT [24] { + name: @index1 + } + } + args: { + IDENT [25] { + name: @index0 + } + } + } + } +} diff --git a/optimizer/src/test/resources/subexpression_ast_cascaded_binds.baseline b/optimizer/src/test/resources/subexpression_ast_cascaded_binds.baseline new file mode 100644 index 000000000..0dd7c6734 --- /dev/null +++ b/optimizer/src/test/resources/subexpression_ast_cascaded_binds.baseline @@ -0,0 +1,3894 @@ +Test case: SIZE_1 +Source: size([1,2]) + size([1,2]) + 1 == 5 +=====> +CALL [1] { + function: _==_ + args: { + CALL [2] { + function: _+_ + args: { + COMPREHENSION [3] { + iter_var: #unused + iter_range: { + CREATE_LIST [4] { + elements: { + } + } + } + accu_var: @r0 + accu_init: { + CALL [5] { + function: size + args: { + CREATE_LIST [6] { + elements: { + CONSTANT [7] { value: 1 } + CONSTANT [8] { value: 2 } + } + } + } + } + } + loop_condition: { + CONSTANT [9] { value: false } + } + loop_step: { + IDENT [10] { + name: @r0 + } + } + result: { + CALL [11] { + function: _+_ + args: { + IDENT [12] { + name: @r0 + } + IDENT [13] { + name: @r0 + } + } + } + } + } + CONSTANT [14] { value: 1 } + } + } + CONSTANT [15] { value: 5 } + } +} +Test case: SIZE_2 +Source: 2 + size([1,2]) + size([1,2]) + 1 == 7 +=====> +CALL [1] { + function: _==_ + args: { + CALL [2] { + function: _+_ + args: { + COMPREHENSION [3] { + iter_var: #unused + iter_range: { + CREATE_LIST [4] { + elements: { + } + } + } + accu_var: @r0 + accu_init: { + CALL [5] { + function: size + args: { + CREATE_LIST [6] { + elements: { + CONSTANT [7] { value: 1 } + CONSTANT [8] { value: 2 } + } + } + } + } + } + loop_condition: { + CONSTANT [9] { value: false } + } + loop_step: { + IDENT [10] { + name: @r0 + } + } + result: { + CALL [11] { + function: _+_ + args: { + CALL [12] { + function: _+_ + args: { + CONSTANT [13] { value: 2 } + IDENT [14] { + name: @r0 + } + } + } + IDENT [15] { + name: @r0 + } + } + } + } + } + CONSTANT [16] { value: 1 } + } + } + CONSTANT [17] { value: 7 } + } +} +Test case: SIZE_3 +Source: size([0]) + size([0]) + size([1,2]) + size([1,2]) == 6 +=====> +CALL [1] { + function: _==_ + args: { + COMPREHENSION [2] { + iter_var: #unused + iter_range: { + CREATE_LIST [3] { + elements: { + } + } + } + accu_var: @r1 + accu_init: { + CALL [4] { + function: size + args: { + CREATE_LIST [5] { + elements: { + CONSTANT [6] { value: 1 } + CONSTANT [7] { value: 2 } + } + } + } + } + } + loop_condition: { + CONSTANT [8] { value: false } + } + loop_step: { + IDENT [9] { + name: @r1 + } + } + result: { + CALL [10] { + function: _+_ + args: { + CALL [11] { + function: _+_ + args: { + COMPREHENSION [12] { + iter_var: #unused + iter_range: { + CREATE_LIST [13] { + elements: { + } + } + } + accu_var: @r0 + accu_init: { + CALL [14] { + function: size + args: { + CREATE_LIST [15] { + elements: { + CONSTANT [16] { value: 0 } + } + } + } + } + } + loop_condition: { + CONSTANT [17] { value: false } + } + loop_step: { + IDENT [18] { + name: @r0 + } + } + result: { + CALL [19] { + function: _+_ + args: { + IDENT [20] { + name: @r0 + } + IDENT [21] { + name: @r0 + } + } + } + } + } + IDENT [22] { + name: @r1 + } + } + } + IDENT [23] { + name: @r1 + } + } + } + } + } + CONSTANT [24] { value: 6 } + } +} +Test case: SIZE_4 +Source: 5 + size([0]) + size([0]) + size([1,2]) + size([1,2]) + size([1,2,3]) + size([1,2,3]) == 17 +=====> +CALL [1] { + function: _==_ + args: { + COMPREHENSION [2] { + iter_var: #unused + iter_range: { + CREATE_LIST [3] { + elements: { + } + } + } + accu_var: @r2 + accu_init: { + CALL [4] { + function: size + args: { + CREATE_LIST [5] { + elements: { + CONSTANT [6] { value: 1 } + CONSTANT [7] { value: 2 } + CONSTANT [8] { value: 3 } + } + } + } + } + } + loop_condition: { + CONSTANT [9] { value: false } + } + loop_step: { + IDENT [10] { + name: @r2 + } + } + result: { + CALL [11] { + function: _+_ + args: { + CALL [12] { + function: _+_ + args: { + COMPREHENSION [13] { + iter_var: #unused + iter_range: { + CREATE_LIST [14] { + elements: { + } + } + } + accu_var: @r1 + accu_init: { + CALL [15] { + function: size + args: { + CREATE_LIST [16] { + elements: { + CONSTANT [17] { value: 1 } + CONSTANT [18] { value: 2 } + } + } + } + } + } + loop_condition: { + CONSTANT [19] { value: false } + } + loop_step: { + IDENT [20] { + name: @r1 + } + } + result: { + CALL [21] { + function: _+_ + args: { + CALL [22] { + function: _+_ + args: { + COMPREHENSION [23] { + iter_var: #unused + iter_range: { + CREATE_LIST [24] { + elements: { + } + } + } + accu_var: @r0 + accu_init: { + CALL [25] { + function: size + args: { + CREATE_LIST [26] { + elements: { + CONSTANT [27] { value: 0 } + } + } + } + } + } + loop_condition: { + CONSTANT [28] { value: false } + } + loop_step: { + IDENT [29] { + name: @r0 + } + } + result: { + CALL [30] { + function: _+_ + args: { + CALL [31] { + function: _+_ + args: { + CONSTANT [32] { value: 5 } + IDENT [33] { + name: @r0 + } + } + } + IDENT [34] { + name: @r0 + } + } + } + } + } + IDENT [35] { + name: @r1 + } + } + } + IDENT [36] { + name: @r1 + } + } + } + } + } + IDENT [37] { + name: @r2 + } + } + } + IDENT [38] { + name: @r2 + } + } + } + } + } + CONSTANT [39] { value: 17 } + } +} +Test case: TIMESTAMP +Source: timestamp(int(timestamp(1000000000))).getFullYear() + timestamp(int(timestamp(75))).getFullYear() + timestamp(int(timestamp(50))).getFullYear() + timestamp(int(timestamp(1000000000))).getFullYear() + timestamp(int(timestamp(50))).getSeconds() + timestamp(int(timestamp(200))).getFullYear() + timestamp(int(timestamp(200))).getFullYear() + timestamp(int(timestamp(75))).getMinutes() + timestamp(int(timestamp(1000000000))).getFullYear() == 13934 +=====> +CALL [1] { + function: _==_ + args: { + COMPREHENSION [2] { + iter_var: #unused + iter_range: { + CREATE_LIST [3] { + elements: { + } + } + } + accu_var: @r0 + accu_init: { + CALL [4] { + function: getFullYear + target: { + CALL [5] { + function: timestamp + args: { + CALL [6] { + function: int + args: { + CALL [7] { + function: timestamp + args: { + CONSTANT [8] { value: 1000000000 } + } + } + } + } + } + } + } + args: { + } + } + } + loop_condition: { + CONSTANT [9] { value: false } + } + loop_step: { + IDENT [10] { + name: @r0 + } + } + result: { + CALL [11] { + function: _+_ + args: { + COMPREHENSION [12] { + iter_var: #unused + iter_range: { + CREATE_LIST [13] { + elements: { + } + } + } + accu_var: @r3 + accu_init: { + CALL [14] { + function: timestamp + args: { + CALL [15] { + function: int + args: { + CALL [16] { + function: timestamp + args: { + CONSTANT [17] { value: 75 } + } + } + } + } + } + } + } + loop_condition: { + CONSTANT [18] { value: false } + } + loop_step: { + IDENT [19] { + name: @r3 + } + } + result: { + CALL [20] { + function: _+_ + args: { + COMPREHENSION [21] { + iter_var: #unused + iter_range: { + CREATE_LIST [22] { + elements: { + } + } + } + accu_var: @r2 + accu_init: { + CALL [23] { + function: getFullYear + target: { + CALL [24] { + function: timestamp + args: { + CALL [25] { + function: int + args: { + CALL [26] { + function: timestamp + args: { + CONSTANT [27] { value: 200 } + } + } + } + } + } + } + } + args: { + } + } + } + loop_condition: { + CONSTANT [28] { value: false } + } + loop_step: { + IDENT [29] { + name: @r2 + } + } + result: { + CALL [30] { + function: _+_ + args: { + CALL [31] { + function: _+_ + args: { + COMPREHENSION [32] { + iter_var: #unused + iter_range: { + CREATE_LIST [33] { + elements: { + } + } + } + accu_var: @r1 + accu_init: { + CALL [34] { + function: timestamp + args: { + CALL [35] { + function: int + args: { + CALL [36] { + function: timestamp + args: { + CONSTANT [37] { value: 50 } + } + } + } + } + } + } + } + loop_condition: { + CONSTANT [38] { value: false } + } + loop_step: { + IDENT [39] { + name: @r1 + } + } + result: { + CALL [40] { + function: _+_ + args: { + CALL [41] { + function: _+_ + args: { + CALL [42] { + function: _+_ + args: { + CALL [43] { + function: _+_ + args: { + IDENT [44] { + name: @r0 + } + CALL [45] { + function: getFullYear + target: { + IDENT [46] { + name: @r3 + } + } + args: { + } + } + } + } + CALL [47] { + function: getFullYear + target: { + IDENT [48] { + name: @r1 + } + } + args: { + } + } + } + } + IDENT [49] { + name: @r0 + } + } + } + CALL [50] { + function: getSeconds + target: { + IDENT [51] { + name: @r1 + } + } + args: { + } + } + } + } + } + } + IDENT [52] { + name: @r2 + } + } + } + IDENT [53] { + name: @r2 + } + } + } + } + } + CALL [54] { + function: getMinutes + target: { + IDENT [55] { + name: @r3 + } + } + args: { + } + } + } + } + } + } + IDENT [56] { + name: @r0 + } + } + } + } + } + CONSTANT [57] { value: 13934 } + } +} +Test case: MAP_INDEX +Source: {"a": 2}["a"] + {"a": 2}["a"] * {"a": 2}["a"] == 6 +=====> +CALL [1] { + function: _==_ + args: { + COMPREHENSION [2] { + iter_var: #unused + iter_range: { + CREATE_LIST [3] { + elements: { + } + } + } + accu_var: @r0 + accu_init: { + CALL [4] { + function: _[_] + args: { + CREATE_MAP [5] { + MAP_ENTRY [6] { + key: { + CONSTANT [7] { value: "a" } + } + value: { + CONSTANT [8] { value: 2 } + } + } + } + CONSTANT [9] { value: "a" } + } + } + } + loop_condition: { + CONSTANT [10] { value: false } + } + loop_step: { + IDENT [11] { + name: @r0 + } + } + result: { + CALL [12] { + function: _+_ + args: { + IDENT [13] { + name: @r0 + } + CALL [14] { + function: _*_ + args: { + IDENT [15] { + name: @r0 + } + IDENT [16] { + name: @r0 + } + } + } + } + } + } + } + CONSTANT [17] { value: 6 } + } +} +Test case: NESTED_MAP_CONSTRUCTION +Source: {'a': {'b': 1}, 'c': {'b': 1}, 'd': {'e': {'b': 1}}, 'e': {'e': {'b': 1}}} +=====> +COMPREHENSION [1] { + iter_var: #unused + iter_range: { + CREATE_LIST [2] { + elements: { + } + } + } + accu_var: @r0 + accu_init: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: "b" } + } + value: { + CONSTANT [6] { value: 1 } + } + } + } + } + loop_condition: { + CONSTANT [7] { value: false } + } + loop_step: { + IDENT [8] { + name: @r0 + } + } + result: { + COMPREHENSION [9] { + iter_var: #unused + iter_range: { + CREATE_LIST [10] { + elements: { + } + } + } + accu_var: @r1 + accu_init: { + CREATE_MAP [11] { + MAP_ENTRY [12] { + key: { + CONSTANT [13] { value: "e" } + } + value: { + IDENT [14] { + name: @r0 + } + } + } + } + } + loop_condition: { + CONSTANT [15] { value: false } + } + loop_step: { + IDENT [16] { + name: @r1 + } + } + result: { + CREATE_MAP [17] { + MAP_ENTRY [18] { + key: { + CONSTANT [19] { value: "a" } + } + value: { + IDENT [20] { + name: @r0 + } + } + } + MAP_ENTRY [21] { + key: { + CONSTANT [22] { value: "c" } + } + value: { + IDENT [23] { + name: @r0 + } + } + } + MAP_ENTRY [24] { + key: { + CONSTANT [25] { value: "d" } + } + value: { + IDENT [26] { + name: @r1 + } + } + } + MAP_ENTRY [27] { + key: { + CONSTANT [28] { value: "e" } + } + value: { + IDENT [29] { + name: @r1 + } + } + } + } + } + } + } +} +Test case: NESTED_LIST_CONSTRUCTION +Source: [1, [1,2,3,4], 2, [1,2,3,4], 5, [1,2,3,4], 7, [[1,2], [1,2,3,4]], [1,2]] +=====> +COMPREHENSION [1] { + iter_var: #unused + iter_range: { + CREATE_LIST [2] { + elements: { + } + } + } + accu_var: @r0 + accu_init: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + CONSTANT [6] { value: 3 } + CONSTANT [7] { value: 4 } + } + } + } + loop_condition: { + CONSTANT [8] { value: false } + } + loop_step: { + IDENT [9] { + name: @r0 + } + } + result: { + COMPREHENSION [10] { + iter_var: #unused + iter_range: { + CREATE_LIST [11] { + elements: { + } + } + } + accu_var: @r1 + accu_init: { + CREATE_LIST [12] { + elements: { + CONSTANT [13] { value: 1 } + CONSTANT [14] { value: 2 } + } + } + } + loop_condition: { + CONSTANT [15] { value: false } + } + loop_step: { + IDENT [16] { + name: @r1 + } + } + result: { + CREATE_LIST [17] { + elements: { + CONSTANT [18] { value: 1 } + IDENT [19] { + name: @r0 + } + CONSTANT [20] { value: 2 } + IDENT [21] { + name: @r0 + } + CONSTANT [22] { value: 5 } + IDENT [23] { + name: @r0 + } + CONSTANT [24] { value: 7 } + CREATE_LIST [25] { + elements: { + IDENT [26] { + name: @r1 + } + IDENT [27] { + name: @r0 + } + } + } + IDENT [28] { + name: @r1 + } + } + } + } + } + } +} +Test case: SELECT +Source: msg.single_int64 + msg.single_int64 == 6 +=====> +CALL [1] { + function: _==_ + args: { + COMPREHENSION [2] { + iter_var: #unused + iter_range: { + CREATE_LIST [3] { + elements: { + } + } + } + accu_var: @r0 + accu_init: { + SELECT [4] { + IDENT [5] { + name: msg + }.single_int64 + } + } + loop_condition: { + CONSTANT [6] { value: false } + } + loop_step: { + IDENT [7] { + name: @r0 + } + } + result: { + CALL [8] { + function: _+_ + args: { + IDENT [9] { + name: @r0 + } + IDENT [10] { + name: @r0 + } + } + } + } + } + CONSTANT [11] { value: 6 } + } +} +Test case: SELECT_NESTED_1 +Source: msg.oneof_type.payload.single_int64 + msg.oneof_type.payload.single_int32 + msg.oneof_type.payload.single_int64 + msg.single_int64 + msg.oneof_type.payload.oneof_type.payload.single_int64 == 31 +=====> +CALL [1] { + function: _==_ + args: { + COMPREHENSION [2] { + iter_var: #unused + iter_range: { + CREATE_LIST [3] { + elements: { + } + } + } + accu_var: @r0 + accu_init: { + SELECT [4] { + SELECT [5] { + IDENT [6] { + name: msg + }.oneof_type + }.payload + } + } + loop_condition: { + CONSTANT [7] { value: false } + } + loop_step: { + IDENT [8] { + name: @r0 + } + } + result: { + CALL [9] { + function: _+_ + args: { + CALL [10] { + function: _+_ + args: { + COMPREHENSION [11] { + iter_var: #unused + iter_range: { + CREATE_LIST [12] { + elements: { + } + } + } + accu_var: @r1 + accu_init: { + SELECT [13] { + IDENT [14] { + name: @r0 + }.single_int64 + } + } + loop_condition: { + CONSTANT [15] { value: false } + } + loop_step: { + IDENT [16] { + name: @r1 + } + } + result: { + CALL [17] { + function: _+_ + args: { + CALL [18] { + function: _+_ + args: { + IDENT [19] { + name: @r1 + } + SELECT [20] { + IDENT [21] { + name: @r0 + }.single_int32 + } + } + } + IDENT [22] { + name: @r1 + } + } + } + } + } + SELECT [23] { + IDENT [24] { + name: msg + }.single_int64 + } + } + } + SELECT [25] { + SELECT [26] { + SELECT [27] { + IDENT [28] { + name: @r0 + }.oneof_type + }.payload + }.single_int64 + } + } + } + } + } + CONSTANT [29] { value: 31 } + } +} +Test case: SELECT_NESTED_2 +Source: true || msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload.single_bool || msg.oneof_type.payload.oneof_type.payload.oneof_type.child.child.payload.single_bool +=====> +COMPREHENSION [1] { + iter_var: #unused + iter_range: { + CREATE_LIST [2] { + elements: { + } + } + } + accu_var: @r0 + accu_init: { + SELECT [3] { + SELECT [4] { + SELECT [5] { + SELECT [6] { + SELECT [7] { + IDENT [8] { + name: msg + }.oneof_type + }.payload + }.oneof_type + }.payload + }.oneof_type + } + } + loop_condition: { + CONSTANT [9] { value: false } + } + loop_step: { + IDENT [10] { + name: @r0 + } + } + result: { + CALL [11] { + function: _||_ + args: { + CALL [12] { + function: _||_ + args: { + CONSTANT [13] { value: true } + SELECT [14] { + SELECT [15] { + SELECT [16] { + SELECT [17] { + IDENT [18] { + name: @r0 + }.payload + }.oneof_type + }.payload + }.single_bool + } + } + } + SELECT [19] { + SELECT [20] { + SELECT [21] { + SELECT [22] { + IDENT [23] { + name: @r0 + }.child + }.child + }.payload + }.single_bool + } + } + } + } +} +Test case: SELECT_NESTED_MESSAGE_MAP_INDEX_1 +Source: msg.oneof_type.payload.map_int32_int64[1] + msg.oneof_type.payload.map_int32_int64[1] + msg.oneof_type.payload.map_int32_int64[1] == 15 +=====> +CALL [1] { + function: _==_ + args: { + COMPREHENSION [2] { + iter_var: #unused + iter_range: { + CREATE_LIST [3] { + elements: { + } + } + } + accu_var: @r0 + accu_init: { + CALL [4] { + function: _[_] + args: { + SELECT [5] { + SELECT [6] { + SELECT [7] { + IDENT [8] { + name: msg + }.oneof_type + }.payload + }.map_int32_int64 + } + CONSTANT [9] { value: 1 } + } + } + } + loop_condition: { + CONSTANT [10] { value: false } + } + loop_step: { + IDENT [11] { + name: @r0 + } + } + result: { + CALL [12] { + function: _+_ + args: { + CALL [13] { + function: _+_ + args: { + IDENT [14] { + name: @r0 + } + IDENT [15] { + name: @r0 + } + } + } + IDENT [16] { + name: @r0 + } + } + } + } + } + CONSTANT [17] { value: 15 } + } +} +Test case: SELECT_NESTED_MESSAGE_MAP_INDEX_2 +Source: msg.oneof_type.payload.map_int32_int64[0] + msg.oneof_type.payload.map_int32_int64[1] + msg.oneof_type.payload.map_int32_int64[2] == 8 +=====> +CALL [1] { + function: _==_ + args: { + COMPREHENSION [2] { + iter_var: #unused + iter_range: { + CREATE_LIST [3] { + elements: { + } + } + } + accu_var: @r0 + accu_init: { + SELECT [4] { + SELECT [5] { + SELECT [6] { + IDENT [7] { + name: msg + }.oneof_type + }.payload + }.map_int32_int64 + } + } + loop_condition: { + CONSTANT [8] { value: false } + } + loop_step: { + IDENT [9] { + name: @r0 + } + } + result: { + CALL [10] { + function: _+_ + args: { + CALL [11] { + function: _+_ + args: { + CALL [12] { + function: _[_] + args: { + IDENT [13] { + name: @r0 + } + CONSTANT [14] { value: 0 } + } + } + CALL [15] { + function: _[_] + args: { + IDENT [16] { + name: @r0 + } + CONSTANT [17] { value: 1 } + } + } + } + } + CALL [18] { + function: _[_] + args: { + IDENT [19] { + name: @r0 + } + CONSTANT [20] { value: 2 } + } + } + } + } + } + } + CONSTANT [21] { value: 8 } + } +} +Test case: SELECT_NESTED_NO_COMMON_SUBEXPR +Source: msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload.single_int64 +=====> +SELECT [10] { + SELECT [9] { + SELECT [8] { + SELECT [7] { + SELECT [6] { + SELECT [5] { + SELECT [4] { + SELECT [3] { + SELECT [2] { + IDENT [1] { + name: msg + }.oneof_type + }.payload + }.oneof_type + }.payload + }.oneof_type + }.payload + }.oneof_type + }.payload + }.single_int64 +} +Test case: TERNARY +Source: (msg.single_int64 > 0 ? msg.single_int64 : 0) == 3 +=====> +CALL [1] { + function: _==_ + args: { + COMPREHENSION [2] { + iter_var: #unused + iter_range: { + CREATE_LIST [3] { + elements: { + } + } + } + accu_var: @r0 + accu_init: { + SELECT [4] { + IDENT [5] { + name: msg + }.single_int64 + } + } + loop_condition: { + CONSTANT [6] { value: false } + } + loop_step: { + IDENT [7] { + name: @r0 + } + } + result: { + CALL [8] { + function: _?_:_ + args: { + CALL [9] { + function: _>_ + args: { + IDENT [10] { + name: @r0 + } + CONSTANT [11] { value: 0 } + } + } + IDENT [12] { + name: @r0 + } + CONSTANT [13] { value: 0 } + } + } + } + } + CONSTANT [14] { value: 3 } + } +} +Test case: TERNARY_BIND_RHS_ONLY +Source: false ? false : (msg.single_int64) + ((msg.single_int64 + 1) * 2) == 11 +=====> +CALL [1] { + function: _?_:_ + args: { + CONSTANT [2] { value: false } + CONSTANT [3] { value: false } + CALL [4] { + function: _==_ + args: { + COMPREHENSION [5] { + iter_var: #unused + iter_range: { + CREATE_LIST [6] { + elements: { + } + } + } + accu_var: @r0 + accu_init: { + SELECT [7] { + IDENT [8] { + name: msg + }.single_int64 + } + } + loop_condition: { + CONSTANT [9] { value: false } + } + loop_step: { + IDENT [10] { + name: @r0 + } + } + result: { + CALL [11] { + function: _+_ + args: { + IDENT [12] { + name: @r0 + } + CALL [13] { + function: _*_ + args: { + CALL [14] { + function: _+_ + args: { + IDENT [15] { + name: @r0 + } + CONSTANT [16] { value: 1 } + } + } + CONSTANT [17] { value: 2 } + } + } + } + } + } + } + CONSTANT [18] { value: 11 } + } + } + } +} +Test case: NESTED_TERNARY +Source: (msg.single_int64 > 0 ? (msg.single_int32 > 0 ? msg.single_int64 + msg.single_int32 : 0) : 0) == 8 +=====> +CALL [1] { + function: _==_ + args: { + COMPREHENSION [2] { + iter_var: #unused + iter_range: { + CREATE_LIST [3] { + elements: { + } + } + } + accu_var: @r0 + accu_init: { + SELECT [4] { + IDENT [5] { + name: msg + }.single_int64 + } + } + loop_condition: { + CONSTANT [6] { value: false } + } + loop_step: { + IDENT [7] { + name: @r0 + } + } + result: { + CALL [8] { + function: _?_:_ + args: { + CALL [9] { + function: _>_ + args: { + IDENT [10] { + name: @r0 + } + CONSTANT [11] { value: 0 } + } + } + COMPREHENSION [12] { + iter_var: #unused + iter_range: { + CREATE_LIST [13] { + elements: { + } + } + } + accu_var: @r1 + accu_init: { + SELECT [14] { + IDENT [15] { + name: msg + }.single_int32 + } + } + loop_condition: { + CONSTANT [16] { value: false } + } + loop_step: { + IDENT [17] { + name: @r1 + } + } + result: { + CALL [18] { + function: _?_:_ + args: { + CALL [19] { + function: _>_ + args: { + IDENT [20] { + name: @r1 + } + CONSTANT [21] { value: 0 } + } + } + CALL [22] { + function: _+_ + args: { + IDENT [23] { + name: @r0 + } + IDENT [24] { + name: @r1 + } + } + } + CONSTANT [25] { value: 0 } + } + } + } + } + CONSTANT [26] { value: 0 } + } + } + } + } + CONSTANT [27] { value: 8 } + } +} +Test case: MULTIPLE_MACROS_1 +Source: size([[1].exists(i, i > 0)]) + size([[1].exists(j, j > 0)]) + size([[2].exists(k, k > 1)]) + size([[2].exists(l, l > 1)]) == 4 +=====> +CALL [1] { + function: _==_ + args: { + COMPREHENSION [2] { + iter_var: #unused + iter_range: { + CREATE_LIST [3] { + elements: { + } + } + } + accu_var: @r1 + accu_init: { + CALL [4] { + function: size + args: { + CREATE_LIST [5] { + elements: { + COMPREHENSION [6] { + iter_var: @c0:0 + iter_range: { + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 2 } + } + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [9] { value: false } + } + loop_condition: { + CALL [10] { + function: @not_strictly_false + args: { + CALL [11] { + function: !_ + args: { + IDENT [12] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + CALL [13] { + function: _||_ + args: { + IDENT [14] { + name: @x0:0 + } + CALL [15] { + function: _>_ + args: { + IDENT [16] { + name: @c0:0 + } + CONSTANT [17] { value: 1 } + } + } + } + } + } + result: { + IDENT [18] { + name: @x0:0 + } + } + } + } + } + } + } + } + loop_condition: { + CONSTANT [19] { value: false } + } + loop_step: { + IDENT [20] { + name: @r1 + } + } + result: { + CALL [21] { + function: _+_ + args: { + CALL [22] { + function: _+_ + args: { + COMPREHENSION [23] { + iter_var: #unused + iter_range: { + CREATE_LIST [24] { + elements: { + } + } + } + accu_var: @r0 + accu_init: { + CALL [25] { + function: size + args: { + CREATE_LIST [26] { + elements: { + COMPREHENSION [27] { + iter_var: @c0:0 + iter_range: { + CREATE_LIST [28] { + elements: { + CONSTANT [29] { value: 1 } + } + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [30] { value: false } + } + loop_condition: { + CALL [31] { + function: @not_strictly_false + args: { + CALL [32] { + function: !_ + args: { + IDENT [33] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + CALL [34] { + function: _||_ + args: { + IDENT [35] { + name: @x0:0 + } + CALL [36] { + function: _>_ + args: { + IDENT [37] { + name: @c0:0 + } + CONSTANT [38] { value: 0 } + } + } + } + } + } + result: { + IDENT [39] { + name: @x0:0 + } + } + } + } + } + } + } + } + loop_condition: { + CONSTANT [40] { value: false } + } + loop_step: { + IDENT [41] { + name: @r0 + } + } + result: { + CALL [42] { + function: _+_ + args: { + IDENT [43] { + name: @r0 + } + IDENT [44] { + name: @r0 + } + } + } + } + } + IDENT [45] { + name: @r1 + } + } + } + IDENT [46] { + name: @r1 + } + } + } + } + } + CONSTANT [47] { value: 4 } + } +} +Test case: MULTIPLE_MACROS_2 +Source: [[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == 'a')] + [['a'].exists(l, l == 'a')] == [true, true, true, true] +=====> +CALL [1] { + function: _==_ + args: { + COMPREHENSION [2] { + iter_var: #unused + iter_range: { + CREATE_LIST [3] { + elements: { + } + } + } + accu_var: @r1 + accu_init: { + CREATE_LIST [4] { + elements: { + COMPREHENSION [5] { + iter_var: @c0:1 + iter_range: { + CREATE_LIST [6] { + elements: { + CONSTANT [7] { value: "a" } + } + } + } + accu_var: @x0:1 + accu_init: { + CONSTANT [8] { value: false } + } + loop_condition: { + CALL [9] { + function: @not_strictly_false + args: { + CALL [10] { + function: !_ + args: { + IDENT [11] { + name: @x0:1 + } + } + } + } + } + } + loop_step: { + CALL [12] { + function: _||_ + args: { + IDENT [13] { + name: @x0:1 + } + CALL [14] { + function: _==_ + args: { + IDENT [15] { + name: @c0:1 + } + CONSTANT [16] { value: "a" } + } + } + } + } + } + result: { + IDENT [17] { + name: @x0:1 + } + } + } + } + } + } + loop_condition: { + CONSTANT [18] { value: false } + } + loop_step: { + IDENT [19] { + name: @r1 + } + } + result: { + CALL [20] { + function: _+_ + args: { + CALL [21] { + function: _+_ + args: { + COMPREHENSION [22] { + iter_var: #unused + iter_range: { + CREATE_LIST [23] { + elements: { + } + } + } + accu_var: @r0 + accu_init: { + CREATE_LIST [24] { + elements: { + COMPREHENSION [25] { + iter_var: @c0:0 + iter_range: { + CREATE_LIST [26] { + elements: { + CONSTANT [27] { value: 1 } + } + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [28] { value: false } + } + loop_condition: { + CALL [29] { + function: @not_strictly_false + args: { + CALL [30] { + function: !_ + args: { + IDENT [31] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + CALL [32] { + function: _||_ + args: { + IDENT [33] { + name: @x0:0 + } + CALL [34] { + function: _>_ + args: { + IDENT [35] { + name: @c0:0 + } + CONSTANT [36] { value: 0 } + } + } + } + } + } + result: { + IDENT [37] { + name: @x0:0 + } + } + } + } + } + } + loop_condition: { + CONSTANT [38] { value: false } + } + loop_step: { + IDENT [39] { + name: @r0 + } + } + result: { + CALL [40] { + function: _+_ + args: { + IDENT [41] { + name: @r0 + } + IDENT [42] { + name: @r0 + } + } + } + } + } + IDENT [43] { + name: @r1 + } + } + } + IDENT [44] { + name: @r1 + } + } + } + } + } + CREATE_LIST [45] { + elements: { + CONSTANT [46] { value: true } + CONSTANT [47] { value: true } + CONSTANT [48] { value: true } + CONSTANT [49] { value: true } + } + } + } +} +Test case: NESTED_MACROS +Source: [1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [[2, 3, 4], [2, 3, 4], [2, 3, 4]] +=====> +CALL [1] { + function: _==_ + args: { + COMPREHENSION [2] { + iter_var: #unused + iter_range: { + CREATE_LIST [3] { + elements: { + } + } + } + accu_var: @r0 + accu_init: { + CREATE_LIST [4] { + elements: { + CONSTANT [5] { value: 1 } + CONSTANT [6] { value: 2 } + CONSTANT [7] { value: 3 } + } + } + } + loop_condition: { + CONSTANT [8] { value: false } + } + loop_step: { + IDENT [9] { + name: @r0 + } + } + result: { + COMPREHENSION [10] { + iter_var: @c0:0 + iter_range: { + IDENT [11] { + name: @r0 + } + } + accu_var: @x0:0 + accu_init: { + CREATE_LIST [12] { + elements: { + } + } + } + loop_condition: { + CONSTANT [13] { value: true } + } + loop_step: { + CALL [14] { + function: _+_ + args: { + IDENT [15] { + name: @x0:0 + } + CREATE_LIST [16] { + elements: { + COMPREHENSION [17] { + iter_var: @c1:0 + iter_range: { + IDENT [18] { + name: @r0 + } + } + accu_var: @x1:0 + accu_init: { + CREATE_LIST [19] { + elements: { + } + } + } + loop_condition: { + CONSTANT [20] { value: true } + } + loop_step: { + CALL [21] { + function: _+_ + args: { + IDENT [22] { + name: @x1:0 + } + CREATE_LIST [23] { + elements: { + CALL [24] { + function: _+_ + args: { + IDENT [25] { + name: @c1:0 + } + CONSTANT [26] { value: 1 } + } + } + } + } + } + } + } + result: { + IDENT [27] { + name: @x1:0 + } + } + } + } + } + } + } + } + result: { + IDENT [28] { + name: @x0:0 + } + } + } + } + } + COMPREHENSION [29] { + iter_var: #unused + iter_range: { + CREATE_LIST [30] { + elements: { + } + } + } + accu_var: @r1 + accu_init: { + CREATE_LIST [31] { + elements: { + CONSTANT [32] { value: 2 } + CONSTANT [33] { value: 3 } + CONSTANT [34] { value: 4 } + } + } + } + loop_condition: { + CONSTANT [35] { value: false } + } + loop_step: { + IDENT [36] { + name: @r1 + } + } + result: { + CREATE_LIST [37] { + elements: { + IDENT [38] { + name: @r1 + } + IDENT [39] { + name: @r1 + } + IDENT [40] { + name: @r1 + } + } + } + } + } + } +} +Test case: NESTED_MACROS_2 +Source: [1, 2].map(y, [1, 2, 3].filter(x, x == y)) == [[1], [2]] +=====> +CALL [31] { + function: _==_ + args: { + COMPREHENSION [30] { + iter_var: @c0:0 + iter_range: { + CREATE_LIST [1] { + elements: { + CONSTANT [2] { value: 1 } + CONSTANT [3] { value: 2 } + } + } + } + accu_var: @x0:0 + accu_init: { + CREATE_LIST [24] { + elements: { + } + } + } + loop_condition: { + CONSTANT [25] { value: true } + } + loop_step: { + CALL [28] { + function: _+_ + args: { + IDENT [26] { + name: @x0:0 + } + CREATE_LIST [27] { + elements: { + COMPREHENSION [23] { + iter_var: @c1:0 + iter_range: { + CREATE_LIST [6] { + elements: { + CONSTANT [7] { value: 1 } + CONSTANT [8] { value: 2 } + CONSTANT [9] { value: 3 } + } + } + } + accu_var: @x1:0 + accu_init: { + CREATE_LIST [15] { + elements: { + } + } + } + loop_condition: { + CONSTANT [16] { value: true } + } + loop_step: { + CALL [21] { + function: _?_:_ + args: { + CALL [13] { + function: _==_ + args: { + IDENT [12] { + name: @c1:0 + } + IDENT [14] { + name: @c0:0 + } + } + } + CALL [19] { + function: _+_ + args: { + IDENT [17] { + name: @x1:0 + } + CREATE_LIST [18] { + elements: { + IDENT [11] { + name: @c1:0 + } + } + } + } + } + IDENT [20] { + name: @x1:0 + } + } + } + } + result: { + IDENT [22] { + name: @x1:0 + } + } + } + } + } + } + } + } + result: { + IDENT [29] { + name: @x0:0 + } + } + } + CREATE_LIST [32] { + elements: { + CREATE_LIST [33] { + elements: { + CONSTANT [34] { value: 1 } + } + } + CREATE_LIST [35] { + elements: { + CONSTANT [36] { value: 2 } + } + } + } + } + } +} +Test case: INCLUSION_LIST +Source: 1 in [1,2,3] && 2 in [1,2,3] && 3 in [3, [1,2,3]] && 1 in [1,2,3] +=====> +COMPREHENSION [1] { + iter_var: #unused + iter_range: { + CREATE_LIST [2] { + elements: { + } + } + } + accu_var: @r0 + accu_init: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + CONSTANT [6] { value: 3 } + } + } + } + loop_condition: { + CONSTANT [7] { value: false } + } + loop_step: { + IDENT [8] { + name: @r0 + } + } + result: { + COMPREHENSION [9] { + iter_var: #unused + iter_range: { + CREATE_LIST [10] { + elements: { + } + } + } + accu_var: @r1 + accu_init: { + CALL [11] { + function: @in + args: { + CONSTANT [12] { value: 1 } + IDENT [13] { + name: @r0 + } + } + } + } + loop_condition: { + CONSTANT [14] { value: false } + } + loop_step: { + IDENT [15] { + name: @r1 + } + } + result: { + CALL [16] { + function: _&&_ + args: { + CALL [17] { + function: _&&_ + args: { + IDENT [18] { + name: @r1 + } + CALL [19] { + function: @in + args: { + CONSTANT [20] { value: 2 } + IDENT [21] { + name: @r0 + } + } + } + } + } + CALL [22] { + function: _&&_ + args: { + CALL [23] { + function: @in + args: { + CONSTANT [24] { value: 3 } + CREATE_LIST [25] { + elements: { + CONSTANT [26] { value: 3 } + IDENT [27] { + name: @r0 + } + } + } + } + } + IDENT [28] { + name: @r1 + } + } + } + } + } + } + } + } +} +Test case: INCLUSION_MAP +Source: 2 in {'a': 1, 2: {true: false}, 3: {true: false}} +=====> +CALL [1] { + function: @in + args: { + CONSTANT [2] { value: 2 } + COMPREHENSION [3] { + iter_var: #unused + iter_range: { + CREATE_LIST [4] { + elements: { + } + } + } + accu_var: @r0 + accu_init: { + CREATE_MAP [5] { + MAP_ENTRY [6] { + key: { + CONSTANT [7] { value: true } + } + value: { + CONSTANT [8] { value: false } + } + } + } + } + loop_condition: { + CONSTANT [9] { value: false } + } + loop_step: { + IDENT [10] { + name: @r0 + } + } + result: { + CREATE_MAP [11] { + MAP_ENTRY [12] { + key: { + CONSTANT [13] { value: "a" } + } + value: { + CONSTANT [14] { value: 1 } + } + } + MAP_ENTRY [15] { + key: { + CONSTANT [16] { value: 2 } + } + value: { + IDENT [17] { + name: @r0 + } + } + } + MAP_ENTRY [18] { + key: { + CONSTANT [19] { value: 3 } + } + value: { + IDENT [20] { + name: @r0 + } + } + } + } + } + } + } +} +Test case: MACRO_ITER_VAR_NOT_REFERENCED +Source: [1,2].map(i, [1, 2].map(i, [3,4])) == [[[3, 4], [3, 4]], [[3, 4], [3, 4]]] +=====> +COMPREHENSION [1] { + iter_var: #unused + iter_range: { + CREATE_LIST [2] { + elements: { + } + } + } + accu_var: @r1 + accu_init: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: 3 } + CONSTANT [5] { value: 4 } + } + } + } + loop_condition: { + CONSTANT [6] { value: false } + } + loop_step: { + IDENT [7] { + name: @r1 + } + } + result: { + CALL [8] { + function: _==_ + args: { + COMPREHENSION [9] { + iter_var: #unused + iter_range: { + CREATE_LIST [10] { + elements: { + } + } + } + accu_var: @r0 + accu_init: { + CREATE_LIST [11] { + elements: { + CONSTANT [12] { value: 1 } + CONSTANT [13] { value: 2 } + } + } + } + loop_condition: { + CONSTANT [14] { value: false } + } + loop_step: { + IDENT [15] { + name: @r0 + } + } + result: { + COMPREHENSION [16] { + iter_var: @c0:0 + iter_range: { + IDENT [17] { + name: @r0 + } + } + accu_var: @x0:0 + accu_init: { + CREATE_LIST [18] { + elements: { + } + } + } + loop_condition: { + CONSTANT [19] { value: true } + } + loop_step: { + CALL [20] { + function: _+_ + args: { + IDENT [21] { + name: @x0:0 + } + CREATE_LIST [22] { + elements: { + COMPREHENSION [23] { + iter_var: @c1:0 + iter_range: { + IDENT [24] { + name: @r0 + } + } + accu_var: @x1:0 + accu_init: { + CREATE_LIST [25] { + elements: { + } + } + } + loop_condition: { + CONSTANT [26] { value: true } + } + loop_step: { + CALL [27] { + function: _+_ + args: { + IDENT [28] { + name: @x1:0 + } + CREATE_LIST [29] { + elements: { + IDENT [30] { + name: @r1 + } + } + } + } + } + } + result: { + IDENT [31] { + name: @x1:0 + } + } + } + } + } + } + } + } + result: { + IDENT [32] { + name: @x0:0 + } + } + } + } + } + COMPREHENSION [33] { + iter_var: #unused + iter_range: { + CREATE_LIST [34] { + elements: { + } + } + } + accu_var: @r2 + accu_init: { + CREATE_LIST [35] { + elements: { + IDENT [36] { + name: @r1 + } + IDENT [37] { + name: @r1 + } + } + } + } + loop_condition: { + CONSTANT [38] { value: false } + } + loop_step: { + IDENT [39] { + name: @r2 + } + } + result: { + CREATE_LIST [40] { + elements: { + IDENT [41] { + name: @r2 + } + IDENT [42] { + name: @r2 + } + } + } + } + } + } + } + } +} +Test case: MACRO_SHADOWED_VARIABLE +Source: [x - 1 > 3 ? x - 1 : 5].exists(x, x - 1 > 3) || x - 1 > 3 +=====> +COMPREHENSION [1] { + iter_var: #unused + iter_range: { + CREATE_LIST [2] { + elements: { + } + } + } + accu_var: @r0 + accu_init: { + CALL [3] { + function: _-_ + args: { + IDENT [4] { + name: x + } + CONSTANT [5] { value: 1 } + } + } + } + loop_condition: { + CONSTANT [6] { value: false } + } + loop_step: { + IDENT [7] { + name: @r0 + } + } + result: { + COMPREHENSION [8] { + iter_var: #unused + iter_range: { + CREATE_LIST [9] { + elements: { + } + } + } + accu_var: @r1 + accu_init: { + CALL [10] { + function: _>_ + args: { + IDENT [11] { + name: @r0 + } + CONSTANT [12] { value: 3 } + } + } + } + loop_condition: { + CONSTANT [13] { value: false } + } + loop_step: { + IDENT [14] { + name: @r1 + } + } + result: { + CALL [15] { + function: _||_ + args: { + COMPREHENSION [16] { + iter_var: @c0:0 + iter_range: { + CREATE_LIST [17] { + elements: { + CALL [18] { + function: _?_:_ + args: { + IDENT [19] { + name: @r1 + } + IDENT [20] { + name: @r0 + } + CONSTANT [21] { value: 5 } + } + } + } + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [22] { value: false } + } + loop_condition: { + CALL [23] { + function: @not_strictly_false + args: { + CALL [24] { + function: !_ + args: { + IDENT [25] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + CALL [26] { + function: _||_ + args: { + IDENT [27] { + name: @x0:0 + } + CALL [28] { + function: _>_ + args: { + CALL [29] { + function: _-_ + args: { + IDENT [30] { + name: @c0:0 + } + CONSTANT [31] { value: 1 } + } + } + CONSTANT [32] { value: 3 } + } + } + } + } + } + result: { + IDENT [33] { + name: @x0:0 + } + } + } + IDENT [34] { + name: @r1 + } + } + } + } + } + } +} +Test case: MACRO_SHADOWED_VARIABLE_2 +Source: ["foo", "bar"].map(x, [x + x, x + x]).map(x, [x + x, x + x]) +=====> +COMPREHENSION [1] { + iter_var: @c0:0 + iter_range: { + COMPREHENSION [2] { + iter_var: @c1:0 + iter_range: { + CREATE_LIST [3] { + elements: { + CONSTANT [4] { value: "foo" } + CONSTANT [5] { value: "bar" } + } + } + } + accu_var: @x1:0 + accu_init: { + CREATE_LIST [6] { + elements: { + } + } + } + loop_condition: { + CONSTANT [7] { value: true } + } + loop_step: { + CALL [8] { + function: _+_ + args: { + IDENT [9] { + name: @x1:0 + } + CREATE_LIST [10] { + elements: { + COMPREHENSION [11] { + iter_var: #unused + iter_range: { + CREATE_LIST [12] { + elements: { + } + } + } + accu_var: @r0 + accu_init: { + CALL [13] { + function: _+_ + args: { + IDENT [14] { + name: @c1:0 + } + IDENT [15] { + name: @c1:0 + } + } + } + } + loop_condition: { + CONSTANT [16] { value: false } + } + loop_step: { + IDENT [17] { + name: @r0 + } + } + result: { + CREATE_LIST [18] { + elements: { + IDENT [19] { + name: @r0 + } + IDENT [20] { + name: @r0 + } + } + } + } + } + } + } + } + } + } + result: { + IDENT [21] { + name: @x1:0 + } + } + } + } + accu_var: @x0:0 + accu_init: { + CREATE_LIST [22] { + elements: { + } + } + } + loop_condition: { + CONSTANT [23] { value: true } + } + loop_step: { + CALL [24] { + function: _+_ + args: { + IDENT [25] { + name: @x0:0 + } + CREATE_LIST [26] { + elements: { + COMPREHENSION [27] { + iter_var: #unused + iter_range: { + CREATE_LIST [28] { + elements: { + } + } + } + accu_var: @r1 + accu_init: { + CALL [29] { + function: _+_ + args: { + IDENT [30] { + name: @c0:0 + } + IDENT [31] { + name: @c0:0 + } + } + } + } + loop_condition: { + CONSTANT [32] { value: false } + } + loop_step: { + IDENT [33] { + name: @r1 + } + } + result: { + CREATE_LIST [34] { + elements: { + IDENT [35] { + name: @r1 + } + IDENT [36] { + name: @r1 + } + } + } + } + } + } + } + } + } + } + result: { + IDENT [37] { + name: @x0:0 + } + } +} +Test case: PRESENCE_TEST +Source: has({'a': true}.a) && {'a':true}['a'] +=====> +COMPREHENSION [1] { + iter_var: #unused + iter_range: { + CREATE_LIST [2] { + elements: { + } + } + } + accu_var: @r0 + accu_init: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: "a" } + } + value: { + CONSTANT [6] { value: true } + } + } + } + } + loop_condition: { + CONSTANT [7] { value: false } + } + loop_step: { + IDENT [8] { + name: @r0 + } + } + result: { + CALL [9] { + function: _&&_ + args: { + SELECT [10] { + IDENT [11] { + name: @r0 + }.a~presence_test + } + CALL [12] { + function: _[_] + args: { + IDENT [13] { + name: @r0 + } + CONSTANT [14] { value: "a" } + } + } + } + } + } +} +Test case: PRESENCE_TEST_WITH_TERNARY +Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : 0) == 10 +=====> +CALL [1] { + function: _==_ + args: { + COMPREHENSION [2] { + iter_var: #unused + iter_range: { + CREATE_LIST [3] { + elements: { + } + } + } + accu_var: @r0 + accu_init: { + SELECT [4] { + IDENT [5] { + name: msg + }.oneof_type + } + } + loop_condition: { + CONSTANT [6] { value: false } + } + loop_step: { + IDENT [7] { + name: @r0 + } + } + result: { + CALL [8] { + function: _?_:_ + args: { + SELECT [9] { + IDENT [10] { + name: @r0 + }.payload~presence_test + } + SELECT [11] { + SELECT [12] { + IDENT [13] { + name: @r0 + }.payload + }.single_int64 + } + CONSTANT [14] { value: 0 } + } + } + } + } + CONSTANT [15] { value: 10 } + } +} +Test case: PRESENCE_TEST_WITH_TERNARY_2 +Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : msg.oneof_type.payload.single_int64 * 0) == 10 +=====> +CALL [1] { + function: _==_ + args: { + COMPREHENSION [2] { + iter_var: #unused + iter_range: { + CREATE_LIST [3] { + elements: { + } + } + } + accu_var: @r0 + accu_init: { + SELECT [4] { + IDENT [5] { + name: msg + }.oneof_type + } + } + loop_condition: { + CONSTANT [6] { value: false } + } + loop_step: { + IDENT [7] { + name: @r0 + } + } + result: { + COMPREHENSION [8] { + iter_var: #unused + iter_range: { + CREATE_LIST [9] { + elements: { + } + } + } + accu_var: @r1 + accu_init: { + SELECT [10] { + SELECT [11] { + IDENT [12] { + name: @r0 + }.payload + }.single_int64 + } + } + loop_condition: { + CONSTANT [13] { value: false } + } + loop_step: { + IDENT [14] { + name: @r1 + } + } + result: { + CALL [15] { + function: _?_:_ + args: { + SELECT [16] { + IDENT [17] { + name: @r0 + }.payload~presence_test + } + IDENT [18] { + name: @r1 + } + CALL [19] { + function: _*_ + args: { + IDENT [20] { + name: @r1 + } + CONSTANT [21] { value: 0 } + } + } + } + } + } + } + } + } + CONSTANT [22] { value: 10 } + } +} +Test case: PRESENCE_TEST_WITH_TERNARY_3 +Source: (has(msg.oneof_type.payload.single_int64) ? msg.oneof_type.payload.single_int64 : msg.oneof_type.payload.single_int64 * 0) == 10 +=====> +CALL [1] { + function: _==_ + args: { + COMPREHENSION [2] { + iter_var: #unused + iter_range: { + CREATE_LIST [3] { + elements: { + } + } + } + accu_var: @r0 + accu_init: { + SELECT [4] { + SELECT [5] { + IDENT [6] { + name: msg + }.oneof_type + }.payload + } + } + loop_condition: { + CONSTANT [7] { value: false } + } + loop_step: { + IDENT [8] { + name: @r0 + } + } + result: { + COMPREHENSION [9] { + iter_var: #unused + iter_range: { + CREATE_LIST [10] { + elements: { + } + } + } + accu_var: @r1 + accu_init: { + SELECT [11] { + IDENT [12] { + name: @r0 + }.single_int64 + } + } + loop_condition: { + CONSTANT [13] { value: false } + } + loop_step: { + IDENT [14] { + name: @r1 + } + } + result: { + CALL [15] { + function: _?_:_ + args: { + SELECT [16] { + IDENT [17] { + name: @r0 + }.single_int64~presence_test + } + IDENT [18] { + name: @r1 + } + CALL [19] { + function: _*_ + args: { + IDENT [20] { + name: @r1 + } + CONSTANT [21] { value: 0 } + } + } + } + } + } + } + } + } + CONSTANT [22] { value: 10 } + } +} +Test case: PRESENCE_TEST_WITH_TERNARY_NESTED +Source: (has(msg.oneof_type) && has(msg.oneof_type.payload) && has(msg.oneof_type.payload.single_int64)) ? ((has(msg.oneof_type.payload.map_string_string) && has(msg.oneof_type.payload.map_string_string.key)) ? msg.oneof_type.payload.map_string_string.key == 'A' : false) : false +=====> +COMPREHENSION [1] { + iter_var: #unused + iter_range: { + CREATE_LIST [2] { + elements: { + } + } + } + accu_var: @r0 + accu_init: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + } + loop_condition: { + CONSTANT [5] { value: false } + } + loop_step: { + IDENT [6] { + name: @r0 + } + } + result: { + COMPREHENSION [7] { + iter_var: #unused + iter_range: { + CREATE_LIST [8] { + elements: { + } + } + } + accu_var: @r1 + accu_init: { + SELECT [9] { + IDENT [10] { + name: @r0 + }.payload + } + } + loop_condition: { + CONSTANT [11] { value: false } + } + loop_step: { + IDENT [12] { + name: @r1 + } + } + result: { + CALL [13] { + function: _?_:_ + args: { + CALL [14] { + function: _&&_ + args: { + CALL [15] { + function: _&&_ + args: { + SELECT [16] { + IDENT [17] { + name: msg + }.oneof_type~presence_test + } + SELECT [18] { + IDENT [19] { + name: @r0 + }.payload~presence_test + } + } + } + SELECT [20] { + IDENT [21] { + name: @r1 + }.single_int64~presence_test + } + } + } + COMPREHENSION [22] { + iter_var: #unused + iter_range: { + CREATE_LIST [23] { + elements: { + } + } + } + accu_var: @r2 + accu_init: { + SELECT [24] { + IDENT [25] { + name: @r1 + }.map_string_string + } + } + loop_condition: { + CONSTANT [26] { value: false } + } + loop_step: { + IDENT [27] { + name: @r2 + } + } + result: { + CALL [28] { + function: _?_:_ + args: { + CALL [29] { + function: _&&_ + args: { + SELECT [30] { + IDENT [31] { + name: @r1 + }.map_string_string~presence_test + } + SELECT [32] { + IDENT [33] { + name: @r2 + }.key~presence_test + } + } + } + CALL [34] { + function: _==_ + args: { + SELECT [35] { + IDENT [36] { + name: @r2 + }.key + } + CONSTANT [37] { value: "A" } + } + } + CONSTANT [38] { value: false } + } + } + } + } + CONSTANT [39] { value: false } + } + } + } + } + } +} +Test case: OPTIONAL_LIST +Source: [10, ?optional.none(), [?optional.none(), ?opt_x], [?optional.none(), ?opt_x]] == [10, [5], [5]] +=====> +CALL [1] { + function: _==_ + args: { + COMPREHENSION [2] { + iter_var: #unused + iter_range: { + CREATE_LIST [3] { + elements: { + } + } + } + accu_var: @r0 + accu_init: { + CALL [4] { + function: optional.none + args: { + } + } + } + loop_condition: { + CONSTANT [5] { value: false } + } + loop_step: { + IDENT [6] { + name: @r0 + } + } + result: { + COMPREHENSION [7] { + iter_var: #unused + iter_range: { + CREATE_LIST [8] { + elements: { + } + } + } + accu_var: @r1 + accu_init: { + CREATE_LIST [9] { + elements: { + IDENT [10] { + name: @r0 + } + IDENT [11] { + name: opt_x + } + } + optional_indices: [0, 1] + } + } + loop_condition: { + CONSTANT [12] { value: false } + } + loop_step: { + IDENT [13] { + name: @r1 + } + } + result: { + CREATE_LIST [14] { + elements: { + CONSTANT [15] { value: 10 } + IDENT [16] { + name: @r0 + } + IDENT [17] { + name: @r1 + } + IDENT [18] { + name: @r1 + } + } + optional_indices: [0] + } + } + } + } + } + COMPREHENSION [19] { + iter_var: #unused + iter_range: { + CREATE_LIST [20] { + elements: { + } + } + } + accu_var: @r2 + accu_init: { + CREATE_LIST [21] { + elements: { + CONSTANT [22] { value: 5 } + } + } + } + loop_condition: { + CONSTANT [23] { value: false } + } + loop_step: { + IDENT [24] { + name: @r2 + } + } + result: { + CREATE_LIST [25] { + elements: { + CONSTANT [26] { value: 10 } + IDENT [27] { + name: @r2 + } + IDENT [28] { + name: @r2 + } + } + } + } + } + } +} +Test case: OPTIONAL_MAP +Source: {?'hello': optional.of('hello')}['hello'] + {?'hello': optional.of('hello')}['hello'] == 'hellohello' +=====> +CALL [1] { + function: _==_ + args: { + COMPREHENSION [2] { + iter_var: #unused + iter_range: { + CREATE_LIST [3] { + elements: { + } + } + } + accu_var: @r0 + accu_init: { + CALL [4] { + function: _[_] + args: { + CREATE_MAP [5] { + MAP_ENTRY [6] { + key: { + CONSTANT [7] { value: "hello" } + } + optional_entry: true + value: { + CALL [8] { + function: optional.of + args: { + CONSTANT [9] { value: "hello" } + } + } + } + } + } + CONSTANT [10] { value: "hello" } + } + } + } + loop_condition: { + CONSTANT [11] { value: false } + } + loop_step: { + IDENT [12] { + name: @r0 + } + } + result: { + CALL [13] { + function: _+_ + args: { + IDENT [14] { + name: @r0 + } + IDENT [15] { + name: @r0 + } + } + } + } + } + CONSTANT [16] { value: "hellohello" } + } +} +Test case: OPTIONAL_MAP_CHAINED +Source: {?'key': optional.of('test')}[?'bogus'].or({'key': 'test'}[?'bogus']).orValue({'key': 'test'}['key']) == 'test' +=====> +CALL [1] { + function: _==_ + args: { + COMPREHENSION [2] { + iter_var: #unused + iter_range: { + CREATE_LIST [3] { + elements: { + } + } + } + accu_var: @r0 + accu_init: { + CREATE_MAP [4] { + MAP_ENTRY [5] { + key: { + CONSTANT [6] { value: "key" } + } + value: { + CONSTANT [7] { value: "test" } + } + } + } + } + loop_condition: { + CONSTANT [8] { value: false } + } + loop_step: { + IDENT [9] { + name: @r0 + } + } + result: { + CALL [10] { + function: orValue + target: { + CALL [11] { + function: or + target: { + CALL [12] { + function: _[?_] + args: { + CREATE_MAP [13] { + MAP_ENTRY [14] { + key: { + CONSTANT [15] { value: "key" } + } + optional_entry: true + value: { + CALL [16] { + function: optional.of + args: { + CONSTANT [17] { value: "test" } + } + } + } + } + } + CONSTANT [18] { value: "bogus" } + } + } + } + args: { + CALL [19] { + function: _[?_] + args: { + IDENT [20] { + name: @r0 + } + CONSTANT [21] { value: "bogus" } + } + } + } + } + } + args: { + CALL [22] { + function: _[_] + args: { + IDENT [23] { + name: @r0 + } + CONSTANT [24] { value: "key" } + } + } + } + } + } + } + CONSTANT [25] { value: "test" } + } +} +Test case: OPTIONAL_MESSAGE +Source: TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}.single_int32 + TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}.single_int64 == 5 +=====> +CALL [1] { + function: _==_ + args: { + COMPREHENSION [2] { + iter_var: #unused + iter_range: { + CREATE_LIST [3] { + elements: { + } + } + } + accu_var: @r0 + accu_init: { + CREATE_STRUCT [4] { + name: TestAllTypes + entries: { + ENTRY [5] { + field_key: single_int64 + optional_entry: true + value: { + CALL [6] { + function: optional.ofNonZeroValue + args: { + CONSTANT [7] { value: 1 } + } + } + } + } + ENTRY [8] { + field_key: single_int32 + optional_entry: true + value: { + CALL [9] { + function: optional.of + args: { + CONSTANT [10] { value: 4 } + } + } + } + } + } + } + } + loop_condition: { + CONSTANT [11] { value: false } + } + loop_step: { + IDENT [12] { + name: @r0 + } + } + result: { + CALL [13] { + function: _+_ + args: { + SELECT [14] { + IDENT [15] { + name: @r0 + }.single_int32 + } + SELECT [16] { + IDENT [17] { + name: @r0 + }.single_int64 + } + } + } + } + } + CONSTANT [18] { value: 5 } + } +} +Test case: CALL +Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('h' + 'e' + 'l' + 'l' + 'o') +=====> +COMPREHENSION [1] { + iter_var: #unused + iter_range: { + CREATE_LIST [2] { + elements: { + } + } + } + accu_var: @r0 + accu_init: { + CALL [3] { + function: _+_ + args: { + CALL [4] { + function: _+_ + args: { + CALL [5] { + function: _+_ + args: { + CALL [6] { + function: _+_ + args: { + CONSTANT [7] { value: "h" } + CONSTANT [8] { value: "e" } + } + } + CONSTANT [9] { value: "l" } + } + } + CONSTANT [10] { value: "l" } + } + } + CONSTANT [11] { value: "o" } + } + } + } + loop_condition: { + CONSTANT [12] { value: false } + } + loop_step: { + IDENT [13] { + name: @r0 + } + } + result: { + CALL [14] { + function: matches + target: { + CALL [15] { + function: _+_ + args: { + IDENT [16] { + name: @r0 + } + CONSTANT [17] { value: " world" } + } + } + } + args: { + IDENT [18] { + name: @r0 + } + } + } + } +} +Test case: CALL_ARGUMENT_NESTED_NO_COMMON_SUBEXPR +Source: 'hello world'.matches('h' + 'e' + 'l' + 'l' + 'o') +=====> +CALL [2] { + function: matches + target: { + CONSTANT [1] { value: "hello world" } + } + args: { + CALL [10] { + function: _+_ + args: { + CALL [8] { + function: _+_ + args: { + CALL [6] { + function: _+_ + args: { + CALL [4] { + function: _+_ + args: { + CONSTANT [3] { value: "h" } + CONSTANT [5] { value: "e" } + } + } + CONSTANT [7] { value: "l" } + } + } + CONSTANT [9] { value: "l" } + } + } + CONSTANT [11] { value: "o" } + } + } + } +} +Test case: CALL_TARGET_NESTED_NO_COMMON_SUBEXPR +Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('hello') +=====> +CALL [12] { + function: matches + target: { + CALL [10] { + function: _+_ + args: { + CALL [8] { + function: _+_ + args: { + CALL [6] { + function: _+_ + args: { + CALL [4] { + function: _+_ + args: { + CALL [2] { + function: _+_ + args: { + CONSTANT [1] { value: "h" } + CONSTANT [3] { value: "e" } + } + } + CONSTANT [5] { value: "l" } + } + } + CONSTANT [7] { value: "l" } + } + } + CONSTANT [9] { value: "o" } + } + } + CONSTANT [11] { value: " world" } + } + } + } + args: { + CONSTANT [13] { value: "hello" } + } +} +Test case: CALL_BOTH_ARGUMENT_TARGET_NESTED_NO_COMMON_SUBEXPR +Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('w' + 'o' + 'r' + 'l' + 'd') +=====> +CALL [12] { + function: matches + target: { + CALL [10] { + function: _+_ + args: { + CALL [8] { + function: _+_ + args: { + CALL [6] { + function: _+_ + args: { + CALL [4] { + function: _+_ + args: { + CALL [2] { + function: _+_ + args: { + CONSTANT [1] { value: "h" } + CONSTANT [3] { value: "e" } + } + } + CONSTANT [5] { value: "l" } + } + } + CONSTANT [7] { value: "l" } + } + } + CONSTANT [9] { value: "o" } + } + } + CONSTANT [11] { value: " world" } + } + } + } + args: { + CALL [20] { + function: _+_ + args: { + CALL [18] { + function: _+_ + args: { + CALL [16] { + function: _+_ + args: { + CALL [14] { + function: _+_ + args: { + CONSTANT [13] { value: "w" } + CONSTANT [15] { value: "o" } + } + } + CONSTANT [17] { value: "r" } + } + } + CONSTANT [19] { value: "l" } + } + } + CONSTANT [21] { value: "d" } + } + } + } +} diff --git a/optimizer/src/test/resources/subexpression_unparsed.baseline b/optimizer/src/test/resources/subexpression_unparsed.baseline new file mode 100644 index 000000000..73e3507fc --- /dev/null +++ b/optimizer/src/test/resources/subexpression_unparsed.baseline @@ -0,0 +1,623 @@ +Test case: SIZE_1 +Source: size([1,2]) + size([1,2]) + 1 == 5 +=====> +Result: true +[CASCADED_BINDS]: cel.bind(@r0, size([1, 2]), @r0 + @r0) + 1 == 5 +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([size([1, 2])], @index0 + @index0 + 1 == 5) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([[1, 2], size(@index0), @index1 + @index1, @index2 + 1], @index3 == 5) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([[1, 2], size(@index0), @index1 + @index1 + 1], @index2 == 5) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([[1, 2], size(@index0), @index1 + @index1 + 1], @index2 == 5) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([[1, 2], size(@index0), @index1 + @index1 + 1], @index2 == 5) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([[1, 2], size(@index0), @index1 + @index1 + 1], @index2 == 5) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([[1, 2], size(@index0), @index1 + @index1 + 1], @index2 == 5) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([[1, 2], size(@index0), @index1 + @index1 + 1], @index2 == 5) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([[1, 2], size(@index0), @index1 + @index1 + 1], @index2 == 5) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([[1, 2], size(@index0), @index1 + @index1 + 1], @index2 == 5) + +Test case: SIZE_2 +Source: 2 + size([1,2]) + size([1,2]) + 1 == 7 +=====> +Result: true +[CASCADED_BINDS]: cel.bind(@r0, size([1, 2]), 2 + @r0 + @r0) + 1 == 7 +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([size([1, 2])], 2 + @index0 + @index0 + 1 == 7) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([[1, 2], size(@index0), 2 + @index1, @index2 + @index1, @index3 + 1], @index4 == 7) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([[1, 2], size(@index0), 2 + @index1 + @index1, @index2 + 1], @index3 == 7) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([[1, 2], size(@index0), 2 + @index1 + @index1 + 1], @index2 == 7) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([[1, 2], size(@index0), 2 + @index1 + @index1 + 1], @index2 == 7) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([[1, 2], size(@index0), 2 + @index1 + @index1 + 1], @index2 == 7) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([[1, 2], size(@index0), 2 + @index1 + @index1 + 1], @index2 == 7) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([[1, 2], size(@index0), 2 + @index1 + @index1 + 1], @index2 == 7) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([[1, 2], size(@index0), 2 + @index1 + @index1 + 1], @index2 == 7) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([[1, 2], size(@index0), 2 + @index1 + @index1 + 1], @index2 == 7) + +Test case: SIZE_3 +Source: size([0]) + size([0]) + size([1,2]) + size([1,2]) == 6 +=====> +Result: true +[CASCADED_BINDS]: cel.bind(@r1, size([1, 2]), cel.bind(@r0, size([0]), @r0 + @r0) + @r1 + @r1) == 6 +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([size([0]), size([1, 2])], @index0 + @index0 + @index1 + @index1 == 6) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([[0], size(@index0), [1, 2], size(@index2), @index1 + @index1, @index4 + @index3, @index5 + @index3], @index6 == 6) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([[0], size(@index0), [1, 2], size(@index2), @index1 + @index1 + @index3, @index4 + @index3], @index5 == 6) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([[0], size(@index0), [1, 2], size(@index2), @index1 + @index1 + @index3 + @index3], @index4 == 6) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([[0], size(@index0), [1, 2], size(@index2), @index1 + @index1 + @index3 + @index3], @index4 == 6) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([[0], size(@index0), [1, 2], size(@index2), @index1 + @index1 + @index3 + @index3], @index4 == 6) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([[0], size(@index0), [1, 2], size(@index2), @index1 + @index1 + @index3 + @index3], @index4 == 6) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([[0], size(@index0), [1, 2], size(@index2), @index1 + @index1 + @index3 + @index3], @index4 == 6) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([[0], size(@index0), [1, 2], size(@index2), @index1 + @index1 + @index3 + @index3], @index4 == 6) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([[0], size(@index0), [1, 2], size(@index2), @index1 + @index1 + @index3 + @index3], @index4 == 6) + +Test case: SIZE_4 +Source: 5 + size([0]) + size([0]) + size([1,2]) + size([1,2]) + size([1,2,3]) + size([1,2,3]) == 17 +=====> +Result: true +[CASCADED_BINDS]: cel.bind(@r2, size([1, 2, 3]), cel.bind(@r1, size([1, 2]), cel.bind(@r0, size([0]), 5 + @r0 + @r0) + @r1 + @r1) + @r2 + @r2) == 17 +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([size([0]), size([1, 2]), size([1, 2, 3])], 5 + @index0 + @index0 + @index1 + @index1 + @index2 + @index2 == 17) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([[0], size(@index0), [1, 2], size(@index2), [1, 2, 3], size(@index4), 5 + @index1, @index6 + @index1, @index7 + @index3, @index8 + @index3, @index9 + @index5, @index10 + @index5], @index11 == 17) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([[0], size(@index0), [1, 2], size(@index2), [1, 2, 3], size(@index4), 5 + @index1 + @index1, @index6 + @index3 + @index3, @index7 + @index5 + @index5], @index8 == 17) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([[0], size(@index0), [1, 2], size(@index2), [1, 2, 3], size(@index4), 5 + @index1 + @index1 + @index3, @index6 + @index3 + @index5 + @index5], @index7 == 17) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([[0], size(@index0), [1, 2], size(@index2), [1, 2, 3], size(@index4), 5 + @index1 + @index1 + @index3 + @index3, @index6 + @index5 + @index5], @index7 == 17) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([[0], size(@index0), [1, 2], size(@index2), [1, 2, 3], size(@index4), 5 + @index1 + @index1 + @index3 + @index3 + @index5, @index6 + @index5], @index7 == 17) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([[0], size(@index0), [1, 2], size(@index2), [1, 2, 3], size(@index4), 5 + @index1 + @index1 + @index3 + @index3 + @index5 + @index5], @index6 == 17) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([[0], size(@index0), [1, 2], size(@index2), [1, 2, 3], size(@index4), 5 + @index1 + @index1 + @index3 + @index3 + @index5 + @index5], @index6 == 17) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([[0], size(@index0), [1, 2], size(@index2), [1, 2, 3], size(@index4), 5 + @index1 + @index1 + @index3 + @index3 + @index5 + @index5], @index6 == 17) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([[0], size(@index0), [1, 2], size(@index2), [1, 2, 3], size(@index4), 5 + @index1 + @index1 + @index3 + @index3 + @index5 + @index5], @index6 == 17) + +Test case: TIMESTAMP +Source: timestamp(int(timestamp(1000000000))).getFullYear() + timestamp(int(timestamp(75))).getFullYear() + timestamp(int(timestamp(50))).getFullYear() + timestamp(int(timestamp(1000000000))).getFullYear() + timestamp(int(timestamp(50))).getSeconds() + timestamp(int(timestamp(200))).getFullYear() + timestamp(int(timestamp(200))).getFullYear() + timestamp(int(timestamp(75))).getMinutes() + timestamp(int(timestamp(1000000000))).getFullYear() == 13934 +=====> +Result: true +[CASCADED_BINDS]: cel.bind(@r0, timestamp(int(timestamp(1000000000))).getFullYear(), cel.bind(@r3, timestamp(int(timestamp(75))), cel.bind(@r2, timestamp(int(timestamp(200))).getFullYear(), cel.bind(@r1, timestamp(int(timestamp(50))), @r0 + @r3.getFullYear() + @r1.getFullYear() + @r0 + @r1.getSeconds()) + @r2 + @r2) + @r3.getMinutes()) + @r0) == 13934 +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([timestamp(int(timestamp(1000000000))).getFullYear(), timestamp(int(timestamp(50))), timestamp(int(timestamp(200))).getFullYear(), timestamp(int(timestamp(75)))], @index0 + @index3.getFullYear() + @index1.getFullYear() + @index0 + @index1.getSeconds() + @index2 + @index2 + @index3.getMinutes() + @index0 == 13934) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([timestamp(1000000000), int(@index0), timestamp(@index1), @index2.getFullYear(), timestamp(50), int(@index4), timestamp(@index5), timestamp(200), int(@index7), timestamp(@index8), @index9.getFullYear(), timestamp(75), int(@index11), timestamp(@index12), @index13.getMinutes(), @index6.getSeconds(), @index6.getFullYear(), @index13.getFullYear(), @index3 + @index17, @index18 + @index16, @index19 + @index3, @index20 + @index15, @index21 + @index10, @index22 + @index10, @index23 + @index14, @index24 + @index3], @index25 == 13934) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([timestamp(1000000000), int(@index0), timestamp(@index1), @index2.getFullYear(), timestamp(50), int(@index4), timestamp(@index5), timestamp(200), int(@index7), timestamp(@index8), @index9.getFullYear(), timestamp(75), int(@index11), timestamp(@index12), @index13.getMinutes(), @index6.getSeconds(), @index6.getFullYear(), @index3 + @index13.getFullYear(), @index17 + @index16 + @index3, @index18 + @index15 + @index10, @index19 + @index10 + @index14, @index20 + @index3], @index21 == 13934) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([timestamp(1000000000), int(@index0), timestamp(@index1), @index2.getFullYear(), timestamp(50), int(@index4), timestamp(@index5), timestamp(200), int(@index7), timestamp(@index8), @index9.getFullYear(), timestamp(75), int(@index11), timestamp(@index12), @index13.getMinutes(), @index6.getSeconds(), @index3 + @index13.getFullYear() + @index6.getFullYear(), @index16 + @index3 + @index15 + @index10, @index17 + @index10 + @index14 + @index3], @index18 == 13934) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([timestamp(1000000000), int(@index0), timestamp(@index1), @index2.getFullYear(), timestamp(50), int(@index4), timestamp(@index5), timestamp(200), int(@index7), timestamp(@index8), @index9.getFullYear(), timestamp(75), int(@index11), timestamp(@index12), @index13.getMinutes(), @index6.getSeconds(), @index3 + @index13.getFullYear() + @index6.getFullYear() + @index3, @index16 + @index15 + @index10 + @index10 + @index14, @index17 + @index3], @index18 == 13934) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([timestamp(1000000000), int(@index0), timestamp(@index1), @index2.getFullYear(), timestamp(50), int(@index4), timestamp(@index5), timestamp(200), int(@index7), timestamp(@index8), @index9.getFullYear(), timestamp(75), int(@index11), timestamp(@index12), @index13.getMinutes(), @index3 + @index13.getFullYear() + @index6.getFullYear() + @index3 + @index6.getSeconds(), @index15 + @index10 + @index10 + @index14 + @index3], @index16 == 13934) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([timestamp(1000000000), int(@index0), timestamp(@index1), @index2.getFullYear(), timestamp(50), int(@index4), timestamp(@index5), timestamp(200), int(@index7), timestamp(@index8), @index9.getFullYear(), timestamp(75), int(@index11), timestamp(@index12), @index13.getMinutes(), @index3 + @index13.getFullYear() + @index6.getFullYear() + @index3 + @index6.getSeconds() + @index10, @index15 + @index10 + @index14 + @index3], @index16 == 13934) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([timestamp(1000000000), int(@index0), timestamp(@index1), @index2.getFullYear(), timestamp(50), int(@index4), timestamp(@index5), timestamp(200), int(@index7), timestamp(@index8), @index9.getFullYear(), timestamp(75), int(@index11), timestamp(@index12), @index13.getMinutes(), @index3 + @index13.getFullYear() + @index6.getFullYear() + @index3 + @index6.getSeconds() + @index10 + @index10, @index15 + @index14 + @index3], @index16 == 13934) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([timestamp(1000000000), int(@index0), timestamp(@index1), @index2.getFullYear(), timestamp(50), int(@index4), timestamp(@index5), timestamp(200), int(@index7), timestamp(@index8), @index9.getFullYear(), timestamp(75), int(@index11), timestamp(@index12), @index3 + @index13.getFullYear() + @index6.getFullYear() + @index3 + @index6.getSeconds() + @index10 + @index10 + @index13.getMinutes(), @index14 + @index3], @index15 == 13934) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([timestamp(1000000000), int(@index0), timestamp(@index1), @index2.getFullYear(), timestamp(50), int(@index4), timestamp(@index5), timestamp(200), int(@index7), timestamp(@index8), @index9.getFullYear(), timestamp(75), int(@index11), timestamp(@index12), @index3 + @index13.getFullYear() + @index6.getFullYear() + @index3 + @index6.getSeconds() + @index10 + @index10 + @index13.getMinutes() + @index3], @index14 == 13934) + +Test case: MAP_INDEX +Source: {"a": 2}["a"] + {"a": 2}["a"] * {"a": 2}["a"] == 6 +=====> +Result: true +[CASCADED_BINDS]: cel.bind(@r0, {"a": 2}["a"], @r0 + @r0 * @r0) == 6 +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([{"a": 2}["a"]], @index0 + @index0 * @index0 == 6) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([{"a": 2}, @index0["a"], @index1 * @index1, @index1 + @index2], @index3 == 6) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([{"a": 2}, @index0["a"], @index1 + @index1 * @index1], @index2 == 6) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([{"a": 2}, @index0["a"], @index1 + @index1 * @index1], @index2 == 6) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([{"a": 2}, @index0["a"], @index1 + @index1 * @index1], @index2 == 6) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([{"a": 2}, @index0["a"], @index1 + @index1 * @index1], @index2 == 6) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([{"a": 2}, @index0["a"], @index1 + @index1 * @index1], @index2 == 6) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([{"a": 2}, @index0["a"], @index1 + @index1 * @index1], @index2 == 6) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([{"a": 2}, @index0["a"], @index1 + @index1 * @index1], @index2 == 6) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([{"a": 2}, @index0["a"], @index1 + @index1 * @index1], @index2 == 6) + +Test case: NESTED_MAP_CONSTRUCTION +Source: {'a': {'b': 1}, 'c': {'b': 1}, 'd': {'e': {'b': 1}}, 'e': {'e': {'b': 1}}} +=====> +Result: {a={b=1}, c={b=1}, d={e={b=1}}, e={e={b=1}}} +[CASCADED_BINDS]: cel.bind(@r0, {"b": 1}, cel.bind(@r1, {"e": @r0}, {"a": @r0, "c": @r0, "d": @r1, "e": @r1})) +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([{"b": 1}, {"e": @index0}], {"a": @index0, "c": @index0, "d": @index1, "e": @index1}) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([{"b": 1}, {"e": @index0}], {"a": @index0, "c": @index0, "d": @index1, "e": @index1}) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([{"b": 1}, {"e": @index0}], {"a": @index0, "c": @index0, "d": @index1, "e": @index1}) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([{"b": 1}, {"e": @index0}], {"a": @index0, "c": @index0, "d": @index1, "e": @index1}) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([{"b": 1}, {"e": @index0}], {"a": @index0, "c": @index0, "d": @index1, "e": @index1}) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([{"b": 1}, {"e": @index0}], {"a": @index0, "c": @index0, "d": @index1, "e": @index1}) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([{"b": 1}, {"e": @index0}], {"a": @index0, "c": @index0, "d": @index1, "e": @index1}) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([{"b": 1}, {"e": @index0}], {"a": @index0, "c": @index0, "d": @index1, "e": @index1}) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([{"b": 1}, {"e": @index0}], {"a": @index0, "c": @index0, "d": @index1, "e": @index1}) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([{"b": 1}, {"e": @index0}], {"a": @index0, "c": @index0, "d": @index1, "e": @index1}) + +Test case: NESTED_LIST_CONSTRUCTION +Source: [1, [1,2,3,4], 2, [1,2,3,4], 5, [1,2,3,4], 7, [[1,2], [1,2,3,4]], [1,2]] +=====> +Result: [1, [1, 2, 3, 4], 2, [1, 2, 3, 4], 5, [1, 2, 3, 4], 7, [[1, 2], [1, 2, 3, 4]], [1, 2]] +[CASCADED_BINDS]: cel.bind(@r0, [1, 2, 3, 4], cel.bind(@r1, [1, 2], [1, @r0, 2, @r0, 5, @r0, 7, [@r1, @r0], @r1])) +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([[1, 2, 3, 4], [1, 2]], [1, @index0, 2, @index0, 5, @index0, 7, [@index1, @index0], @index1]) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([[1, 2, 3, 4], [1, 2], [@index1, @index0]], [1, @index0, 2, @index0, 5, @index0, 7, @index2, @index1]) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([[1, 2, 3, 4], [1, 2], [@index1, @index0]], [1, @index0, 2, @index0, 5, @index0, 7, @index2, @index1]) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([[1, 2, 3, 4], [1, 2], [@index1, @index0]], [1, @index0, 2, @index0, 5, @index0, 7, @index2, @index1]) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([[1, 2, 3, 4], [1, 2], [@index1, @index0]], [1, @index0, 2, @index0, 5, @index0, 7, @index2, @index1]) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([[1, 2, 3, 4], [1, 2], [@index1, @index0]], [1, @index0, 2, @index0, 5, @index0, 7, @index2, @index1]) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([[1, 2, 3, 4], [1, 2], [@index1, @index0]], [1, @index0, 2, @index0, 5, @index0, 7, @index2, @index1]) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([[1, 2, 3, 4], [1, 2], [@index1, @index0]], [1, @index0, 2, @index0, 5, @index0, 7, @index2, @index1]) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([[1, 2, 3, 4], [1, 2], [@index1, @index0]], [1, @index0, 2, @index0, 5, @index0, 7, @index2, @index1]) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([[1, 2, 3, 4], [1, 2], [@index1, @index0]], [1, @index0, 2, @index0, 5, @index0, 7, @index2, @index1]) + +Test case: SELECT +Source: msg.single_int64 + msg.single_int64 == 6 +=====> +Result: true +[CASCADED_BINDS]: cel.bind(@r0, msg.single_int64, @r0 + @r0) == 6 +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.single_int64], @index0 + @index0 == 6) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.single_int64, @index0 + @index0], @index1 == 6) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.single_int64, @index0 + @index0], @index1 == 6) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.single_int64, @index0 + @index0], @index1 == 6) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.single_int64, @index0 + @index0], @index1 == 6) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.single_int64, @index0 + @index0], @index1 == 6) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.single_int64, @index0 + @index0], @index1 == 6) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([msg.single_int64, @index0 + @index0], @index1 == 6) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([msg.single_int64, @index0 + @index0], @index1 == 6) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([msg.single_int64, @index0 + @index0], @index1 == 6) + +Test case: SELECT_NESTED_1 +Source: msg.oneof_type.payload.single_int64 + msg.oneof_type.payload.single_int32 + msg.oneof_type.payload.single_int64 + msg.single_int64 + msg.oneof_type.payload.oneof_type.payload.single_int64 == 31 +=====> +Result: true +[CASCADED_BINDS]: cel.bind(@r0, msg.oneof_type.payload, cel.bind(@r1, @r0.single_int64, @r1 + @r0.single_int32 + @r1) + msg.single_int64 + @r0.oneof_type.payload.single_int64) == 31 +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.oneof_type.payload, @index0.single_int64], @index1 + @index0.single_int32 + @index1 + msg.single_int64 + @index0.oneof_type.payload.single_int64 == 31) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, @index1.oneof_type, @index3.payload, @index4.single_int64, msg.single_int64, @index1.single_int32, @index2 + @index7, @index8 + @index2, @index9 + @index6, @index10 + @index5], @index11 == 31) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, @index1.oneof_type.payload, @index3.single_int64, msg.single_int64, @index2 + @index1.single_int32, @index6 + @index2 + @index5, @index7 + @index4], @index8 == 31) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, @index1.oneof_type.payload.single_int64, msg.single_int64, @index2 + @index1.single_int32 + @index2, @index5 + @index4 + @index3], @index6 == 31) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, @index1.oneof_type.payload.single_int64, @index2 + @index1.single_int32 + @index2 + msg.single_int64, @index4 + @index3], @index5 == 31) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, @index2 + @index1.single_int32 + @index2 + msg.single_int64 + @index1.oneof_type.payload.single_int64], @index3 == 31) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, @index2 + @index1.single_int32 + @index2 + msg.single_int64 + @index1.oneof_type.payload.single_int64], @index3 == 31) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, @index2 + @index1.single_int32 + @index2 + msg.single_int64 + @index1.oneof_type.payload.single_int64], @index3 == 31) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, @index2 + @index1.single_int32 + @index2 + msg.single_int64 + @index1.oneof_type.payload.single_int64], @index3 == 31) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, @index2 + @index1.single_int32 + @index2 + msg.single_int64 + @index1.oneof_type.payload.single_int64], @index3 == 31) + +Test case: SELECT_NESTED_2 +Source: true || msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload.single_bool || msg.oneof_type.payload.oneof_type.payload.oneof_type.child.child.payload.single_bool +=====> +Result: true +[CASCADED_BINDS]: cel.bind(@r0, msg.oneof_type.payload.oneof_type.payload.oneof_type, true || @r0.payload.oneof_type.payload.single_bool || @r0.child.child.payload.single_bool) +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.oneof_type.payload.oneof_type.payload.oneof_type], true || @index0.payload.oneof_type.payload.single_bool || @index0.child.child.payload.single_bool) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.oneof_type, @index2.payload, @index3.oneof_type, @index4.child, @index5.child, @index6.payload, @index7.single_bool, @index4.payload, @index9.oneof_type, @index10.payload, @index11.single_bool, true || @index12], @index13 || @index8) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type, @index0.payload, @index1.oneof_type, @index2.payload, @index3.oneof_type, @index4.child.child, @index5.payload.single_bool, @index4.payload.oneof_type, @index7.payload.single_bool, true || @index8], @index9 || @index6) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type, @index0.payload, @index1.oneof_type, @index2.payload, @index3.oneof_type, @index4.child.child.payload, @index5.single_bool, @index4.payload.oneof_type.payload, true || @index7.single_bool], @index8 || @index6) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.oneof_type, @index0.payload, @index1.oneof_type, @index2.payload, @index3.oneof_type, @index4.child.child.payload.single_bool, @index4.payload.oneof_type.payload.single_bool, true || @index6], @index7 || @index5) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.oneof_type, @index0.payload, @index1.oneof_type, @index2.payload, @index3.oneof_type, @index4.child.child.payload.single_bool, true || @index4.payload.oneof_type.payload.single_bool], @index6 || @index5) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.oneof_type, @index0.payload, @index1.oneof_type, @index2.payload, @index3.oneof_type, @index4.child.child.payload.single_bool, true || @index4.payload.oneof_type.payload.single_bool], @index6 || @index5) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([msg.oneof_type, @index0.payload, @index1.oneof_type, @index2.payload, @index3.oneof_type, @index4.child.child.payload.single_bool, true || @index4.payload.oneof_type.payload.single_bool], @index6 || @index5) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([msg.oneof_type, @index0.payload, @index1.oneof_type, @index2.payload, @index3.oneof_type, @index4.child.child.payload.single_bool, true || @index4.payload.oneof_type.payload.single_bool], @index6 || @index5) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([msg.oneof_type, @index0.payload, @index1.oneof_type, @index2.payload, @index3.oneof_type, @index4.child.child.payload.single_bool, true || @index4.payload.oneof_type.payload.single_bool], @index6 || @index5) + +Test case: SELECT_NESTED_MESSAGE_MAP_INDEX_1 +Source: msg.oneof_type.payload.map_int32_int64[1] + msg.oneof_type.payload.map_int32_int64[1] + msg.oneof_type.payload.map_int32_int64[1] == 15 +=====> +Result: true +[CASCADED_BINDS]: cel.bind(@r0, msg.oneof_type.payload.map_int32_int64[1], @r0 + @r0 + @r0) == 15 +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.oneof_type.payload.map_int32_int64[1]], @index0 + @index0 + @index0 == 15) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_int32_int64, @index2[1], @index3 + @index3, @index4 + @index3], @index5 == 15) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_int32_int64, @index2[1], @index3 + @index3 + @index3], @index4 == 15) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_int32_int64, @index2[1], @index3 + @index3 + @index3], @index4 == 15) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_int32_int64, @index2[1], @index3 + @index3 + @index3], @index4 == 15) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_int32_int64, @index2[1], @index3 + @index3 + @index3], @index4 == 15) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_int32_int64, @index2[1], @index3 + @index3 + @index3], @index4 == 15) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_int32_int64, @index2[1], @index3 + @index3 + @index3], @index4 == 15) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_int32_int64, @index2[1], @index3 + @index3 + @index3], @index4 == 15) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_int32_int64, @index2[1], @index3 + @index3 + @index3], @index4 == 15) + +Test case: SELECT_NESTED_MESSAGE_MAP_INDEX_2 +Source: msg.oneof_type.payload.map_int32_int64[0] + msg.oneof_type.payload.map_int32_int64[1] + msg.oneof_type.payload.map_int32_int64[2] == 8 +=====> +Result: true +[CASCADED_BINDS]: cel.bind(@r0, msg.oneof_type.payload.map_int32_int64, @r0[0] + @r0[1] + @r0[2]) == 8 +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.oneof_type.payload.map_int32_int64], @index0[0] + @index0[1] + @index0[2] == 8) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_int32_int64, @index2[2], @index2[1], @index2[0], @index5 + @index4, @index6 + @index3], @index7 == 8) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_int32_int64, @index2[2], @index2[0] + @index2[1], @index4 + @index3], @index5 == 8) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_int32_int64, @index2[0] + @index2[1] + @index2[2]], @index3 == 8) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_int32_int64, @index2[0] + @index2[1] + @index2[2]], @index3 == 8) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_int32_int64, @index2[0] + @index2[1] + @index2[2]], @index3 == 8) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_int32_int64, @index2[0] + @index2[1] + @index2[2]], @index3 == 8) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_int32_int64, @index2[0] + @index2[1] + @index2[2]], @index3 == 8) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_int32_int64, @index2[0] + @index2[1] + @index2[2]], @index3 == 8) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_int32_int64, @index2[0] + @index2[1] + @index2[2]], @index3 == 8) + +Test case: SELECT_NESTED_NO_COMMON_SUBEXPR +Source: msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload.single_int64 +=====> +Result: 0 +[CASCADED_BINDS]: msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload.single_int64 +[BLOCK_COMMON_SUBEXPR_ONLY]: msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload.single_int64 +[BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.oneof_type, @index2.payload, @index3.oneof_type, @index4.payload, @index5.oneof_type, @index6.payload], @index7.single_int64) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type.payload, @index0.oneof_type.payload, @index1.oneof_type.payload, @index2.oneof_type.payload], @index3.single_int64) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type.payload.oneof_type, @index0.payload.oneof_type.payload, @index1.oneof_type.payload], @index2.single_int64) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.oneof_type.payload.oneof_type.payload, @index0.oneof_type.payload.oneof_type.payload], @index1.single_int64) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.oneof_type.payload.oneof_type.payload.oneof_type, @index0.payload.oneof_type.payload], @index1.single_int64) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.oneof_type.payload.oneof_type.payload.oneof_type.payload, @index0.oneof_type.payload], @index1.single_int64) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type, @index0.payload], @index1.single_int64) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload], @index0.single_int64) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload], @index0.single_int64) + +Test case: TERNARY +Source: (msg.single_int64 > 0 ? msg.single_int64 : 0) == 3 +=====> +Result: true +[CASCADED_BINDS]: cel.bind(@r0, msg.single_int64, (@r0 > 0) ? @r0 : 0) == 3 +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.single_int64], ((@index0 > 0) ? @index0 : 0) == 3) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.single_int64, @index0 > 0, @index1 ? @index0 : 0], @index2 == 3) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.single_int64, (@index0 > 0) ? @index0 : 0], @index1 == 3) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.single_int64, (@index0 > 0) ? @index0 : 0], @index1 == 3) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.single_int64, (@index0 > 0) ? @index0 : 0], @index1 == 3) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.single_int64, (@index0 > 0) ? @index0 : 0], @index1 == 3) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.single_int64, (@index0 > 0) ? @index0 : 0], @index1 == 3) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([msg.single_int64, (@index0 > 0) ? @index0 : 0], @index1 == 3) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([msg.single_int64, (@index0 > 0) ? @index0 : 0], @index1 == 3) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([msg.single_int64, (@index0 > 0) ? @index0 : 0], @index1 == 3) + +Test case: TERNARY_BIND_RHS_ONLY +Source: false ? false : (msg.single_int64) + ((msg.single_int64 + 1) * 2) == 11 +=====> +Result: true +[CASCADED_BINDS]: false ? false : (cel.bind(@r0, msg.single_int64, @r0 + (@r0 + 1) * 2) == 11) +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.single_int64], false ? false : (@index0 + (@index0 + 1) * 2 == 11)) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.single_int64, @index0 + 1, @index1 * 2, @index0 + @index2, @index3 == 11], false ? false : @index4) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.single_int64, (@index0 + 1) * 2, @index0 + @index1 == 11], false ? false : @index2) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.single_int64, @index0 + (@index0 + 1) * 2, @index1 == 11], false ? false : @index2) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.single_int64, @index0 + (@index0 + 1) * 2 == 11], false ? false : @index1) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.single_int64, @index0 + (@index0 + 1) * 2 == 11], false ? false : @index1) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.single_int64, @index0 + (@index0 + 1) * 2 == 11], false ? false : @index1) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([msg.single_int64, @index0 + (@index0 + 1) * 2 == 11], false ? false : @index1) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([msg.single_int64, @index0 + (@index0 + 1) * 2 == 11], false ? false : @index1) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([msg.single_int64, @index0 + (@index0 + 1) * 2 == 11], false ? false : @index1) + +Test case: NESTED_TERNARY +Source: (msg.single_int64 > 0 ? (msg.single_int32 > 0 ? msg.single_int64 + msg.single_int32 : 0) : 0) == 8 +=====> +Result: true +[CASCADED_BINDS]: cel.bind(@r0, msg.single_int64, (@r0 > 0) ? cel.bind(@r1, msg.single_int32, (@r1 > 0) ? (@r0 + @r1) : 0) : 0) == 8 +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.single_int64, msg.single_int32], ((@index0 > 0) ? ((@index1 > 0) ? (@index0 + @index1) : 0) : 0) == 8) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.single_int64, msg.single_int32, @index0 + @index1, @index1 > 0, @index3 ? @index2 : 0, @index0 > 0, @index5 ? @index4 : 0], @index6 == 8) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.single_int64, msg.single_int32, (@index1 > 0) ? (@index0 + @index1) : 0, (@index0 > 0) ? @index2 : 0], @index3 == 8) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.single_int64, msg.single_int32, (@index0 > 0) ? ((@index1 > 0) ? (@index0 + @index1) : 0) : 0], @index2 == 8) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.single_int64, msg.single_int32, (@index0 > 0) ? ((@index1 > 0) ? (@index0 + @index1) : 0) : 0], @index2 == 8) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.single_int64, msg.single_int32, (@index0 > 0) ? ((@index1 > 0) ? (@index0 + @index1) : 0) : 0], @index2 == 8) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.single_int64, msg.single_int32, (@index0 > 0) ? ((@index1 > 0) ? (@index0 + @index1) : 0) : 0], @index2 == 8) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([msg.single_int64, msg.single_int32, (@index0 > 0) ? ((@index1 > 0) ? (@index0 + @index1) : 0) : 0], @index2 == 8) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([msg.single_int64, msg.single_int32, (@index0 > 0) ? ((@index1 > 0) ? (@index0 + @index1) : 0) : 0], @index2 == 8) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([msg.single_int64, msg.single_int32, (@index0 > 0) ? ((@index1 > 0) ? (@index0 + @index1) : 0) : 0], @index2 == 8) + +Test case: MULTIPLE_MACROS_1 +Source: size([[1].exists(i, i > 0)]) + size([[1].exists(j, j > 0)]) + size([[2].exists(k, k > 1)]) + size([[2].exists(l, l > 1)]) == 4 +=====> +Result: true +[CASCADED_BINDS]: cel.bind(@r1, size([[2].exists(@c0:0, @c0:0 > 1)]), cel.bind(@r0, size([[1].exists(@c0:0, @c0:0 > 0)]), @r0 + @r0) + @r1 + @r1) == 4 +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([size([[1].exists(@c0:0, @c0:0 > 0)]), size([[2].exists(@c0:0, @c0:0 > 1)])], @index0 + @index0 + @index1 + @index1 == 4) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([[1], @c0:0 > 0, @x0:0 || @index1, [2], @c0:0 > 1, @x0:0 || @index4], size([@index0.exists(@c0:0, @index1)]) + size([@index0.exists(@c0:0, @index1)]) + size([@index3.exists(@c0:0, @index4)]) + size([@index3.exists(@c0:0, @index4)]) == 4) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([[1], @c0:0 > 0, @x0:0 || @index1, [2], @c0:0 > 1, @x0:0 || @index4], size([@index0.exists(@c0:0, @index1)]) + size([@index0.exists(@c0:0, @index1)]) + size([@index3.exists(@c0:0, @index4)]) + size([@index3.exists(@c0:0, @index4)]) == 4) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([[1], @c0:0 > 0, @x0:0 || @index1, @index0.exists(@c0:0, @index1), [@index3], size(@index4), [2], @c0:0 > 1, @x0:0 || @index7, @index6.exists(@c0:0, @index7), [@index9], size(@index10), @index5 + @index5 + @index11 + @index11], @index12 == 4) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([[1], @c0:0 > 0, @x0:0 || @index1, @index0.exists(@c0:0, @index1), [@index3], size(@index4), [2], @c0:0 > 1, @x0:0 || @index7, @index6.exists(@c0:0, @index7), [@index9], size(@index10), @index5 + @index5 + @index11 + @index11], @index12 == 4) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([[1], @c0:0 > 0, @x0:0 || @index1, @index0.exists(@c0:0, @index1), [@index3], size(@index4), [2], @c0:0 > 1, @x0:0 || @index7, @index6.exists(@c0:0, @index7), [@index9], size(@index10), @index5 + @index5 + @index11 + @index11], @index12 == 4) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([[1], @c0:0 > 0, @x0:0 || @index1, @index0.exists(@c0:0, @index1), [@index3], size(@index4), [2], @c0:0 > 1, @x0:0 || @index7, @index6.exists(@c0:0, @index7), [@index9], size(@index10), @index5 + @index5 + @index11 + @index11], @index12 == 4) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([[1], @c0:0 > 0, @x0:0 || @index1, @index0.exists(@c0:0, @index1), [@index3], size(@index4), [2], @c0:0 > 1, @x0:0 || @index7, @index6.exists(@c0:0, @index7), [@index9], size(@index10), @index5 + @index5 + @index11 + @index11], @index12 == 4) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([[1], @c0:0 > 0, @x0:0 || @index1, @index0.exists(@c0:0, @index1), [@index3], size(@index4), [2], @c0:0 > 1, @x0:0 || @index7, @index6.exists(@c0:0, @index7), [@index9], size(@index10), @index5 + @index5 + @index11 + @index11], @index12 == 4) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([[1], @c0:0 > 0, @x0:0 || @index1, @index0.exists(@c0:0, @index1), [@index3], size(@index4), [2], @c0:0 > 1, @x0:0 || @index7, @index6.exists(@c0:0, @index7), [@index9], size(@index10), @index5 + @index5 + @index11 + @index11], @index12 == 4) + +Test case: MULTIPLE_MACROS_2 +Source: [[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == 'a')] + [['a'].exists(l, l == 'a')] == [true, true, true, true] +=====> +Result: true +[CASCADED_BINDS]: cel.bind(@r1, [["a"].exists(@c0:1, @c0:1 == "a")], cel.bind(@r0, [[1].exists(@c0:0, @c0:0 > 0)], @r0 + @r0) + @r1 + @r1) == [true, true, true, true] +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([[[1].exists(@c0:0, @c0:0 > 0)], [["a"].exists(@c0:1, @c0:1 == "a")]], @index0 + @index0 + @index1 + @index1 == [true, true, true, true]) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([[1], @c0:0 > 0, @x0:0 || @index1, ["a"], @c0:1 == "a", @x0:1 || @index4, [true, true, true, true]], [@index0.exists(@c0:0, @index1)] + [@index0.exists(@c0:0, @index1)] + [@index3.exists(@c0:1, @index4)] + [@index3.exists(@c0:1, @index4)] == @index6) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([[1], @c0:0 > 0, @x0:0 || @index1, ["a"], @c0:1 == "a", @x0:1 || @index4, [true, true, true, true]], [@index0.exists(@c0:0, @index1)] + [@index0.exists(@c0:0, @index1)] + [@index3.exists(@c0:1, @index4)] + [@index3.exists(@c0:1, @index4)] == @index6) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([[1], @c0:0 > 0, @x0:0 || @index1, @index0.exists(@c0:0, @index1), [@index3], ["a"], @c0:1 == "a", @x0:1 || @index6, @index5.exists(@c0:1, @index6), [@index8], [true, true, true, true], @index4 + @index4 + @index9 + @index9], @index11 == @index10) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([[1], @c0:0 > 0, @x0:0 || @index1, @index0.exists(@c0:0, @index1), [@index3], ["a"], @c0:1 == "a", @x0:1 || @index6, @index5.exists(@c0:1, @index6), [@index8], [true, true, true, true], @index4 + @index4 + @index9 + @index9], @index11 == @index10) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([[1], @c0:0 > 0, @x0:0 || @index1, @index0.exists(@c0:0, @index1), [@index3], ["a"], @c0:1 == "a", @x0:1 || @index6, @index5.exists(@c0:1, @index6), [@index8], [true, true, true, true], @index4 + @index4 + @index9 + @index9], @index11 == @index10) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([[1], @c0:0 > 0, @x0:0 || @index1, @index0.exists(@c0:0, @index1), [@index3], ["a"], @c0:1 == "a", @x0:1 || @index6, @index5.exists(@c0:1, @index6), [@index8], [true, true, true, true], @index4 + @index4 + @index9 + @index9], @index11 == @index10) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([[1], @c0:0 > 0, @x0:0 || @index1, @index0.exists(@c0:0, @index1), [@index3], ["a"], @c0:1 == "a", @x0:1 || @index6, @index5.exists(@c0:1, @index6), [@index8], [true, true, true, true], @index4 + @index4 + @index9 + @index9], @index11 == @index10) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([[1], @c0:0 > 0, @x0:0 || @index1, @index0.exists(@c0:0, @index1), [@index3], ["a"], @c0:1 == "a", @x0:1 || @index6, @index5.exists(@c0:1, @index6), [@index8], [true, true, true, true], @index4 + @index4 + @index9 + @index9], @index11 == @index10) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([[1], @c0:0 > 0, @x0:0 || @index1, @index0.exists(@c0:0, @index1), [@index3], ["a"], @c0:1 == "a", @x0:1 || @index6, @index5.exists(@c0:1, @index6), [@index8], [true, true, true, true], @index4 + @index4 + @index9 + @index9], @index11 == @index10) + +Test case: NESTED_MACROS +Source: [1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [[2, 3, 4], [2, 3, 4], [2, 3, 4]] +=====> +Result: true +[CASCADED_BINDS]: cel.bind(@r0, [1, 2, 3], @r0.map(@c0:0, @r0.map(@c1:0, @c1:0 + 1))) == cel.bind(@r1, [2, 3, 4], [@r1, @r1, @r1]) +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([[1, 2, 3], [2, 3, 4]], @index0.map(@c0:0, @index0.map(@c1:0, @c1:0 + 1)) == [@index1, @index1, @index1]) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([[1, 2, 3], [2, 3, 4], [@index1, @index1, @index1], @c1:0 + 1, [@index3], @x1:0 + @index4], @index0.map(@c0:0, @index0.map(@c1:0, @index3)) == @index2) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([[1, 2, 3], [2, 3, 4], [@index1, @index1, @index1], [@c1:0 + 1], @index0.map(@c1:0, @c1:0 + 1), @x0:0 + [@index4], @index0.map(@c0:0, @index4)], @index6 == @index2) +[BLOCK_RECURSION_DEPTH_3]: Unparse Error: java.lang.IllegalArgumentException: unexpected expr kind: NOT_SET +[BLOCK_RECURSION_DEPTH_4]: cel.@block([[1, 2, 3], [2, 3, 4], [@index1, @index1, @index1], @index0.map(@c1:0, @c1:0 + 1), @index0.map(@c0:0, @index3)], @index4 == @index2) +[BLOCK_RECURSION_DEPTH_5]: Unparse Error: java.lang.IllegalArgumentException: unexpected expr kind: NOT_SET +[BLOCK_RECURSION_DEPTH_6]: Unparse Error: java.lang.IllegalArgumentException: unexpected expr kind: NOT_SET +[BLOCK_RECURSION_DEPTH_7]: cel.@block([[1, 2, 3], [2, 3, 4], [@index1, @index1, @index1], @index0.map(@c0:0, @index0.map(@c1:0, @c1:0 + 1))], @index3 == @index2) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([[1, 2, 3], [2, 3, 4], [@index1, @index1, @index1], @index0.map(@c0:0, @index0.map(@c1:0, @c1:0 + 1))], @index3 == @index2) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([[1, 2, 3], [2, 3, 4], [@index1, @index1, @index1], @index0.map(@c0:0, @index0.map(@c1:0, @c1:0 + 1))], @index3 == @index2) + +Test case: NESTED_MACROS_2 +Source: [1, 2].map(y, [1, 2, 3].filter(x, x == y)) == [[1], [2]] +=====> +Result: true +[CASCADED_BINDS]: [1, 2].map(@c0:0, [1, 2, 3].filter(@c1:0, @c1:0 == @c0:0)) == [[1], [2]] +[BLOCK_COMMON_SUBEXPR_ONLY]: [1, 2].map(@c0:0, [1, 2, 3].filter(@c1:0, @c1:0 == @c0:0)) == [[1], [2]] +[BLOCK_RECURSION_DEPTH_1]: cel.@block([[2], [1], [@index1, @index0], [@c1:0], @x1:0 + @index3, @c1:0 == @c0:0, @index5 ? @index4 : @x1:0, [1, 2, 3], [1, 2]], @index8.map(@c0:0, @index7.filter(@c1:0, @index5)) == @index2) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([[[1], [2]], @x1:0 + [@c1:0], (@c1:0 == @c0:0) ? @index1 : @x1:0, [1, 2, 3].filter(@c1:0, @c1:0 == @c0:0), @x0:0 + [@index3], [1, 2].map(@c0:0, @index3)], @index5 == @index0) +[BLOCK_RECURSION_DEPTH_3]: Unparse Error: java.lang.IllegalArgumentException: unexpected expr kind: NOT_SET +[BLOCK_RECURSION_DEPTH_4]: cel.@block([[[1], [2]], [1, 2, 3].filter(@c1:0, @c1:0 == @c0:0), [1, 2].map(@c0:0, @index1)], @index2 == @index0) +[BLOCK_RECURSION_DEPTH_5]: Unparse Error: java.lang.IllegalArgumentException: unexpected expr kind: NOT_SET +[BLOCK_RECURSION_DEPTH_6]: Unparse Error: java.lang.IllegalArgumentException: unexpected expr kind: NOT_SET +[BLOCK_RECURSION_DEPTH_7]: cel.@block([[[1], [2]], [1, 2].map(@c0:0, [1, 2, 3].filter(@c1:0, @c1:0 == @c0:0))], @index1 == @index0) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([[[1], [2]], [1, 2].map(@c0:0, [1, 2, 3].filter(@c1:0, @c1:0 == @c0:0))], @index1 == @index0) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([[[1], [2]], [1, 2].map(@c0:0, [1, 2, 3].filter(@c1:0, @c1:0 == @c0:0))], @index1 == @index0) + +Test case: INCLUSION_LIST +Source: 1 in [1,2,3] && 2 in [1,2,3] && 3 in [3, [1,2,3]] && 1 in [1,2,3] +=====> +Result: true +[CASCADED_BINDS]: cel.bind(@r0, [1, 2, 3], cel.bind(@r1, 1 in @r0, @r1 && 2 in @r0 && 3 in [3, @r0] && @r1)) +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([[1, 2, 3], 1 in @index0], @index1 && 2 in @index0 && 3 in [3, @index0] && @index1) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([[1, 2, 3], 1 in @index0, [3, @index0], 3 in @index2, @index3 && @index1, 2 in @index0, @index1 && @index5], @index6 && @index4) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([[1, 2, 3], 1 in @index0, 3 in [3, @index0], @index2 && @index1, @index1 && 2 in @index0], @index4 && @index3) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([[1, 2, 3], 1 in @index0, 3 in [3, @index0] && @index1, @index1 && 2 in @index0], @index3 && @index2) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([[1, 2, 3], 1 in @index0, 3 in [3, @index0] && @index1, @index1 && 2 in @index0], @index3 && @index2) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([[1, 2, 3], 1 in @index0, 3 in [3, @index0] && @index1, @index1 && 2 in @index0], @index3 && @index2) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([[1, 2, 3], 1 in @index0, 3 in [3, @index0] && @index1, @index1 && 2 in @index0], @index3 && @index2) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([[1, 2, 3], 1 in @index0, 3 in [3, @index0] && @index1, @index1 && 2 in @index0], @index3 && @index2) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([[1, 2, 3], 1 in @index0, 3 in [3, @index0] && @index1, @index1 && 2 in @index0], @index3 && @index2) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([[1, 2, 3], 1 in @index0, 3 in [3, @index0] && @index1, @index1 && 2 in @index0], @index3 && @index2) + +Test case: INCLUSION_MAP +Source: 2 in {'a': 1, 2: {true: false}, 3: {true: false}} +=====> +Result: true +[CASCADED_BINDS]: 2 in cel.bind(@r0, {true: false}, {"a": 1, 2: @r0, 3: @r0}) +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([{true: false}], 2 in {"a": 1, 2: @index0, 3: @index0}) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([{true: false}, {"a": 1, 2: @index0, 3: @index0}], 2 in @index1) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([{true: false}, {"a": 1, 2: @index0, 3: @index0}], 2 in @index1) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([{true: false}, {"a": 1, 2: @index0, 3: @index0}], 2 in @index1) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([{true: false}, {"a": 1, 2: @index0, 3: @index0}], 2 in @index1) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([{true: false}, {"a": 1, 2: @index0, 3: @index0}], 2 in @index1) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([{true: false}, {"a": 1, 2: @index0, 3: @index0}], 2 in @index1) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([{true: false}, {"a": 1, 2: @index0, 3: @index0}], 2 in @index1) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([{true: false}, {"a": 1, 2: @index0, 3: @index0}], 2 in @index1) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([{true: false}, {"a": 1, 2: @index0, 3: @index0}], 2 in @index1) + +Test case: MACRO_ITER_VAR_NOT_REFERENCED +Source: [1,2].map(i, [1, 2].map(i, [3,4])) == [[[3, 4], [3, 4]], [[3, 4], [3, 4]]] +=====> +Result: true +[CASCADED_BINDS]: cel.bind(@r1, [3, 4], cel.bind(@r0, [1, 2], @r0.map(@c0:0, @r0.map(@c1:0, @r1))) == cel.bind(@r2, [@r1, @r1], [@r2, @r2])) +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([[1, 2], [3, 4], [@index1, @index1]], @index0.map(@c0:0, @index0.map(@c1:0, @index1)) == [@index2, @index2]) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([[1, 2], [3, 4], [@index1, @index1], [@index2, @index2], [@index1], @x1:0 + @index4], @index0.map(@c0:0, @index0.map(@c1:0, @index1)) == @index3) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([[1, 2], [3, 4], [@index1, @index1], [@index2, @index2], @x1:0 + [@index1], @index0.map(@c1:0, @index1), @x0:0 + [@index5], @index0.map(@c0:0, @index5)], @index7 == @index3) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([[1, 2], [3, 4], [@index1, @index1], [@index2, @index2], @index0.map(@c1:0, @index1), @index0.map(@c0:0, @index4)], @index5 == @index3) +[BLOCK_RECURSION_DEPTH_4]: Unparse Error: java.lang.IllegalArgumentException: unexpected expr kind: NOT_SET +[BLOCK_RECURSION_DEPTH_5]: Unparse Error: java.lang.IllegalArgumentException: unexpected expr kind: NOT_SET +[BLOCK_RECURSION_DEPTH_6]: cel.@block([[1, 2], [3, 4], [@index1, @index1], [@index2, @index2], @index0.map(@c0:0, @index0.map(@c1:0, @index1))], @index4 == @index3) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([[1, 2], [3, 4], [@index1, @index1], [@index2, @index2], @index0.map(@c0:0, @index0.map(@c1:0, @index1))], @index4 == @index3) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([[1, 2], [3, 4], [@index1, @index1], [@index2, @index2], @index0.map(@c0:0, @index0.map(@c1:0, @index1))], @index4 == @index3) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([[1, 2], [3, 4], [@index1, @index1], [@index2, @index2], @index0.map(@c0:0, @index0.map(@c1:0, @index1))], @index4 == @index3) + +Test case: MACRO_SHADOWED_VARIABLE +Source: [x - 1 > 3 ? x - 1 : 5].exists(x, x - 1 > 3) || x - 1 > 3 +=====> +Result: true +[CASCADED_BINDS]: cel.bind(@r0, x - 1, cel.bind(@r1, @r0 > 3, [@r1 ? @r0 : 5].exists(@c0:0, @c0:0 - 1 > 3) || @r1)) +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([x - 1, @index0 > 3], [@index1 ? @index0 : 5].exists(@c0:0, @c0:0 - 1 > 3) || @index1) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([x - 1, @index0 > 3, @c0:0 - 1, @index2 > 3, @x0:0 || @index3, @index1 ? @index0 : 5, [@index5]], @index6.exists(@c0:0, @index3) || @index1) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([x - 1, @index0 > 3, @c0:0 - 1 > 3, @x0:0 || @index2, [@index1 ? @index0 : 5]], @index4.exists(@c0:0, @index2) || @index1) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([x - 1, @index0 > 3, @x0:0 || @c0:0 - 1 > 3, [@index1 ? @index0 : 5].exists(@c0:0, @c0:0 - 1 > 3)], @index3 || @index1) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([x - 1, @index0 > 3, [@index1 ? @index0 : 5].exists(@c0:0, @c0:0 - 1 > 3)], @index2 || @index1) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([x - 1, @index0 > 3, [@index1 ? @index0 : 5].exists(@c0:0, @c0:0 - 1 > 3)], @index2 || @index1) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([x - 1, @index0 > 3, [@index1 ? @index0 : 5].exists(@c0:0, @c0:0 - 1 > 3)], @index2 || @index1) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([x - 1, @index0 > 3, [@index1 ? @index0 : 5].exists(@c0:0, @c0:0 - 1 > 3)], @index2 || @index1) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([x - 1, @index0 > 3, [@index1 ? @index0 : 5].exists(@c0:0, @c0:0 - 1 > 3)], @index2 || @index1) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([x - 1, @index0 > 3, [@index1 ? @index0 : 5].exists(@c0:0, @c0:0 - 1 > 3)], @index2 || @index1) + +Test case: MACRO_SHADOWED_VARIABLE_2 +Source: ["foo", "bar"].map(x, [x + x, x + x]).map(x, [x + x, x + x]) +=====> +Result: [[[foofoo, foofoo, foofoo, foofoo], [foofoo, foofoo, foofoo, foofoo]], [[barbar, barbar, barbar, barbar], [barbar, barbar, barbar, barbar]]] +[CASCADED_BINDS]: ["foo", "bar"].map(@c1:0, cel.bind(@r0, @c1:0 + @c1:0, [@r0, @r0])).map(@c0:0, cel.bind(@r1, @c0:0 + @c0:0, [@r1, @r1])) +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([@c1:0 + @c1:0, @c0:0 + @c0:0], ["foo", "bar"].map(@c1:0, [@index0, @index0]).map(@c0:0, [@index1, @index1])) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([@c1:0 + @c1:0, @c0:0 + @c0:0, [@index1, @index1], [@index2], @x0:0 + @index3, [@index0, @index0], [@index5], @x1:0 + @index6, ["foo", "bar"]], @index8.map(@c1:0, @index5).map(@c0:0, @index2)) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([@c1:0 + @c1:0, @c0:0 + @c0:0, [[@index1, @index1]], @x0:0 + @index2, [[@index0, @index0]], ["foo", "bar"].map(@c1:0, [@index0, @index0])], @index5.map(@c0:0, [@index1, @index1])) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([@c1:0 + @c1:0, @c0:0 + @c0:0, @x0:0 + [[@index1, @index1]], @x1:0 + [[@index0, @index0]], ["foo", "bar"].map(@c1:0, [@index0, @index0])], @index4.map(@c0:0, [@index1, @index1])) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([@c1:0 + @c1:0, @c0:0 + @c0:0, @x0:0 + [[@index1, @index1]], ["foo", "bar"].map(@c1:0, [@index0, @index0])], @index3.map(@c0:0, [@index1, @index1])) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([@c1:0 + @c1:0, @c0:0 + @c0:0, @x0:0 + [[@index1, @index1]], ["foo", "bar"].map(@c1:0, [@index0, @index0])], @index3.map(@c0:0, [@index1, @index1])) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([@c1:0 + @c1:0, @c0:0 + @c0:0, @x0:0 + [[@index1, @index1]], ["foo", "bar"].map(@c1:0, [@index0, @index0])], @index3.map(@c0:0, [@index1, @index1])) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([@c1:0 + @c1:0, @c0:0 + @c0:0, @x0:0 + [[@index1, @index1]], ["foo", "bar"].map(@c1:0, [@index0, @index0])], @index3.map(@c0:0, [@index1, @index1])) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([@c1:0 + @c1:0, @c0:0 + @c0:0, @x0:0 + [[@index1, @index1]], ["foo", "bar"].map(@c1:0, [@index0, @index0])], @index3.map(@c0:0, [@index1, @index1])) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([@c1:0 + @c1:0, @c0:0 + @c0:0, @x0:0 + [[@index1, @index1]], ["foo", "bar"].map(@c1:0, [@index0, @index0])], @index3.map(@c0:0, [@index1, @index1])) + +Test case: PRESENCE_TEST +Source: has({'a': true}.a) && {'a':true}['a'] +=====> +Result: true +[CASCADED_BINDS]: cel.bind(@r0, {"a": true}, has(@r0.a) && @r0["a"]) +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([{"a": true}], has(@index0.a) && @index0["a"]) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([{"a": true}, @index0["a"]], has(@index0.a) && @index1) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([{"a": true}, @index0["a"]], has(@index0.a) && @index1) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([{"a": true}, @index0["a"]], has(@index0.a) && @index1) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([{"a": true}, @index0["a"]], has(@index0.a) && @index1) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([{"a": true}, @index0["a"]], has(@index0.a) && @index1) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([{"a": true}, @index0["a"]], has(@index0.a) && @index1) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([{"a": true}, @index0["a"]], has(@index0.a) && @index1) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([{"a": true}, @index0["a"]], has(@index0.a) && @index1) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([{"a": true}, @index0["a"]], has(@index0.a) && @index1) + +Test case: PRESENCE_TEST_WITH_TERNARY +Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : 0) == 10 +=====> +Result: true +[CASCADED_BINDS]: cel.bind(@r0, msg.oneof_type, has(@r0.payload) ? @r0.payload.single_int64 : 0) == 10 +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.oneof_type], (has(@index0.payload) ? @index0.payload.single_int64 : 0) == 10) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64], (has(@index0.payload) ? @index2 : 0) == 10) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type, @index0.payload.single_int64, has(@index0.payload) ? @index1 : 0], @index2 == 10) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type, has(@index0.payload) ? @index0.payload.single_int64 : 0], @index1 == 10) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.oneof_type, has(@index0.payload) ? @index0.payload.single_int64 : 0], @index1 == 10) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.oneof_type, has(@index0.payload) ? @index0.payload.single_int64 : 0], @index1 == 10) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.oneof_type, has(@index0.payload) ? @index0.payload.single_int64 : 0], @index1 == 10) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([msg.oneof_type, has(@index0.payload) ? @index0.payload.single_int64 : 0], @index1 == 10) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([msg.oneof_type, has(@index0.payload) ? @index0.payload.single_int64 : 0], @index1 == 10) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([msg.oneof_type, has(@index0.payload) ? @index0.payload.single_int64 : 0], @index1 == 10) + +Test case: PRESENCE_TEST_WITH_TERNARY_2 +Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : msg.oneof_type.payload.single_int64 * 0) == 10 +=====> +Result: true +[CASCADED_BINDS]: cel.bind(@r0, msg.oneof_type, cel.bind(@r1, @r0.payload.single_int64, has(@r0.payload) ? @r1 : (@r1 * 0))) == 10 +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.oneof_type, @index0.payload.single_int64], (has(@index0.payload) ? @index1 : (@index1 * 0)) == 10) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, @index2 * 0], (has(@index0.payload) ? @index2 : @index3) == 10) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, has(@index0.payload) ? @index2 : (@index2 * 0)], @index3 == 10) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, has(@index0.payload) ? @index2 : (@index2 * 0)], @index3 == 10) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, has(@index0.payload) ? @index2 : (@index2 * 0)], @index3 == 10) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, has(@index0.payload) ? @index2 : (@index2 * 0)], @index3 == 10) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, has(@index0.payload) ? @index2 : (@index2 * 0)], @index3 == 10) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, has(@index0.payload) ? @index2 : (@index2 * 0)], @index3 == 10) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, has(@index0.payload) ? @index2 : (@index2 * 0)], @index3 == 10) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, has(@index0.payload) ? @index2 : (@index2 * 0)], @index3 == 10) + +Test case: PRESENCE_TEST_WITH_TERNARY_3 +Source: (has(msg.oneof_type.payload.single_int64) ? msg.oneof_type.payload.single_int64 : msg.oneof_type.payload.single_int64 * 0) == 10 +=====> +Result: true +[CASCADED_BINDS]: cel.bind(@r0, msg.oneof_type.payload, cel.bind(@r1, @r0.single_int64, has(@r0.single_int64) ? @r1 : (@r1 * 0))) == 10 +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.oneof_type.payload, @index0.single_int64], (has(@index0.single_int64) ? @index1 : (@index1 * 0)) == 10) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, @index2 * 0], (has(@index1.single_int64) ? @index2 : @index3) == 10) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, has(@index1.single_int64) ? @index2 : (@index2 * 0)], @index3 == 10) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, has(@index1.single_int64) ? @index2 : (@index2 * 0)], @index3 == 10) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, has(@index1.single_int64) ? @index2 : (@index2 * 0)], @index3 == 10) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, has(@index1.single_int64) ? @index2 : (@index2 * 0)], @index3 == 10) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, has(@index1.single_int64) ? @index2 : (@index2 * 0)], @index3 == 10) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, has(@index1.single_int64) ? @index2 : (@index2 * 0)], @index3 == 10) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, has(@index1.single_int64) ? @index2 : (@index2 * 0)], @index3 == 10) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, has(@index1.single_int64) ? @index2 : (@index2 * 0)], @index3 == 10) + +Test case: PRESENCE_TEST_WITH_TERNARY_NESTED +Source: (has(msg.oneof_type) && has(msg.oneof_type.payload) && has(msg.oneof_type.payload.single_int64)) ? ((has(msg.oneof_type.payload.map_string_string) && has(msg.oneof_type.payload.map_string_string.key)) ? msg.oneof_type.payload.map_string_string.key == 'A' : false) : false +=====> +Result: true +[CASCADED_BINDS]: cel.bind(@r0, msg.oneof_type, cel.bind(@r1, @r0.payload, (has(msg.oneof_type) && has(@r0.payload) && has(@r1.single_int64)) ? cel.bind(@r2, @r1.map_string_string, (has(@r1.map_string_string) && has(@r2.key)) ? (@r2.key == "A") : false) : false)) +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_string_string], (has(msg.oneof_type) && has(@index0.payload) && has(@index1.single_int64)) ? ((has(@index1.map_string_string) && has(@index2.key)) ? (@index2.key == "A") : false) : false) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_string_string, @index2.key, @index3 == "A"], (has(msg.oneof_type) && has(@index0.payload) && has(@index1.single_int64)) ? ((has(@index1.map_string_string) && has(@index2.key)) ? @index4 : false) : false) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_string_string, @index2.key == "A", has(@index1.map_string_string) && has(@index2.key), @index4 ? @index3 : false, has(msg.oneof_type) && has(@index0.payload), @index6 && has(@index1.single_int64)], @index7 ? @index5 : false) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_string_string, (has(@index1.map_string_string) && has(@index2.key)) ? (@index2.key == "A") : false, has(msg.oneof_type) && has(@index0.payload) && has(@index1.single_int64)], @index4 ? @index3 : false) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_string_string, (has(@index1.map_string_string) && has(@index2.key)) ? (@index2.key == "A") : false, has(msg.oneof_type) && has(@index0.payload) && has(@index1.single_int64)], @index4 ? @index3 : false) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_string_string, (has(@index1.map_string_string) && has(@index2.key)) ? (@index2.key == "A") : false, has(msg.oneof_type) && has(@index0.payload) && has(@index1.single_int64)], @index4 ? @index3 : false) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_string_string, (has(@index1.map_string_string) && has(@index2.key)) ? (@index2.key == "A") : false, has(msg.oneof_type) && has(@index0.payload) && has(@index1.single_int64)], @index4 ? @index3 : false) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_string_string, (has(@index1.map_string_string) && has(@index2.key)) ? (@index2.key == "A") : false, has(msg.oneof_type) && has(@index0.payload) && has(@index1.single_int64)], @index4 ? @index3 : false) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_string_string, (has(@index1.map_string_string) && has(@index2.key)) ? (@index2.key == "A") : false, has(msg.oneof_type) && has(@index0.payload) && has(@index1.single_int64)], @index4 ? @index3 : false) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_string_string, (has(@index1.map_string_string) && has(@index2.key)) ? (@index2.key == "A") : false, has(msg.oneof_type) && has(@index0.payload) && has(@index1.single_int64)], @index4 ? @index3 : false) + +Test case: OPTIONAL_LIST +Source: [10, ?optional.none(), [?optional.none(), ?opt_x], [?optional.none(), ?opt_x]] == [10, [5], [5]] +=====> +Result: true +[CASCADED_BINDS]: cel.bind(@r0, optional.none(), cel.bind(@r1, [?@r0, ?opt_x], [10, ?@r0, @r1, @r1])) == cel.bind(@r2, [5], [10, @r2, @r2]) +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([optional.none(), [?@index0, ?opt_x], [5]], [10, ?@index0, @index1, @index1] == [10, @index2, @index2]) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([optional.none(), [?@index0, ?opt_x], [5], [10, @index2, @index2], [10, ?@index0, @index1, @index1]], @index4 == @index3) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([optional.none(), [?@index0, ?opt_x], [5], [10, @index2, @index2], [10, ?@index0, @index1, @index1]], @index4 == @index3) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([optional.none(), [?@index0, ?opt_x], [5], [10, @index2, @index2], [10, ?@index0, @index1, @index1]], @index4 == @index3) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([optional.none(), [?@index0, ?opt_x], [5], [10, @index2, @index2], [10, ?@index0, @index1, @index1]], @index4 == @index3) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([optional.none(), [?@index0, ?opt_x], [5], [10, @index2, @index2], [10, ?@index0, @index1, @index1]], @index4 == @index3) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([optional.none(), [?@index0, ?opt_x], [5], [10, @index2, @index2], [10, ?@index0, @index1, @index1]], @index4 == @index3) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([optional.none(), [?@index0, ?opt_x], [5], [10, @index2, @index2], [10, ?@index0, @index1, @index1]], @index4 == @index3) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([optional.none(), [?@index0, ?opt_x], [5], [10, @index2, @index2], [10, ?@index0, @index1, @index1]], @index4 == @index3) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([optional.none(), [?@index0, ?opt_x], [5], [10, @index2, @index2], [10, ?@index0, @index1, @index1]], @index4 == @index3) + +Test case: OPTIONAL_MAP +Source: {?'hello': optional.of('hello')}['hello'] + {?'hello': optional.of('hello')}['hello'] == 'hellohello' +=====> +Result: true +[CASCADED_BINDS]: cel.bind(@r0, {?"hello": optional.of("hello")}["hello"], @r0 + @r0) == "hellohello" +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([{?"hello": optional.of("hello")}["hello"]], @index0 + @index0 == "hellohello") +[BLOCK_RECURSION_DEPTH_1]: cel.@block([optional.of("hello"), {?"hello": @index0}, @index1["hello"], @index2 + @index2], @index3 == "hellohello") +[BLOCK_RECURSION_DEPTH_2]: cel.@block([optional.of("hello"), {?"hello": @index0}, @index1["hello"], @index2 + @index2], @index3 == "hellohello") +[BLOCK_RECURSION_DEPTH_3]: cel.@block([optional.of("hello"), {?"hello": @index0}, @index1["hello"], @index2 + @index2], @index3 == "hellohello") +[BLOCK_RECURSION_DEPTH_4]: cel.@block([optional.of("hello"), {?"hello": @index0}, @index1["hello"], @index2 + @index2], @index3 == "hellohello") +[BLOCK_RECURSION_DEPTH_5]: cel.@block([optional.of("hello"), {?"hello": @index0}, @index1["hello"], @index2 + @index2], @index3 == "hellohello") +[BLOCK_RECURSION_DEPTH_6]: cel.@block([optional.of("hello"), {?"hello": @index0}, @index1["hello"], @index2 + @index2], @index3 == "hellohello") +[BLOCK_RECURSION_DEPTH_7]: cel.@block([optional.of("hello"), {?"hello": @index0}, @index1["hello"], @index2 + @index2], @index3 == "hellohello") +[BLOCK_RECURSION_DEPTH_8]: cel.@block([optional.of("hello"), {?"hello": @index0}, @index1["hello"], @index2 + @index2], @index3 == "hellohello") +[BLOCK_RECURSION_DEPTH_9]: cel.@block([optional.of("hello"), {?"hello": @index0}, @index1["hello"], @index2 + @index2], @index3 == "hellohello") + +Test case: OPTIONAL_MAP_CHAINED +Source: {?'key': optional.of('test')}[?'bogus'].or({'key': 'test'}[?'bogus']).orValue({'key': 'test'}['key']) == 'test' +=====> +Result: true +[CASCADED_BINDS]: cel.bind(@r0, {"key": "test"}, {?"key": optional.of("test")}[?"bogus"].or(@r0[?"bogus"]).orValue(@r0["key"])) == "test" +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([{"key": "test"}], {?"key": optional.of("test")}[?"bogus"].or(@index0[?"bogus"]).orValue(@index0["key"]) == "test") +[BLOCK_RECURSION_DEPTH_1]: cel.@block([{"key": "test"}, @index0["key"], @index0[?"bogus"], optional.of("test"), {?"key": @index3}, @index4[?"bogus"], @index5.or(@index2), @index6.orValue(@index1)], @index7 == "test") +[BLOCK_RECURSION_DEPTH_2]: cel.@block([{"key": "test"}, @index0["key"], @index0[?"bogus"], {?"key": optional.of("test")}, @index3[?"bogus"].or(@index2), @index4.orValue(@index1)], @index5 == "test") +[BLOCK_RECURSION_DEPTH_3]: cel.@block([{"key": "test"}, @index0["key"], @index0[?"bogus"], {?"key": optional.of("test")}[?"bogus"], @index3.or(@index2).orValue(@index1)], @index4 == "test") +[BLOCK_RECURSION_DEPTH_4]: cel.@block([{"key": "test"}, @index0["key"], {?"key": optional.of("test")}[?"bogus"].or(@index0[?"bogus"]), @index2.orValue(@index1)], @index3 == "test") +[BLOCK_RECURSION_DEPTH_5]: cel.@block([{"key": "test"}, {?"key": optional.of("test")}[?"bogus"].or(@index0[?"bogus"]).orValue(@index0["key"])], @index1 == "test") +[BLOCK_RECURSION_DEPTH_6]: cel.@block([{"key": "test"}, {?"key": optional.of("test")}[?"bogus"].or(@index0[?"bogus"]).orValue(@index0["key"])], @index1 == "test") +[BLOCK_RECURSION_DEPTH_7]: cel.@block([{"key": "test"}, {?"key": optional.of("test")}[?"bogus"].or(@index0[?"bogus"]).orValue(@index0["key"])], @index1 == "test") +[BLOCK_RECURSION_DEPTH_8]: cel.@block([{"key": "test"}, {?"key": optional.of("test")}[?"bogus"].or(@index0[?"bogus"]).orValue(@index0["key"])], @index1 == "test") +[BLOCK_RECURSION_DEPTH_9]: cel.@block([{"key": "test"}, {?"key": optional.of("test")}[?"bogus"].or(@index0[?"bogus"]).orValue(@index0["key"])], @index1 == "test") + +Test case: OPTIONAL_MESSAGE +Source: TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}.single_int32 + TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}.single_int64 == 5 +=====> +Result: true +[CASCADED_BINDS]: cel.bind(@r0, TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}, @r0.single_int32 + @r0.single_int64) == 5 +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}], @index0.single_int32 + @index0.single_int64 == 5) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([optional.ofNonZeroValue(1), optional.of(4), TestAllTypes{?single_int64: @index0, ?single_int32: @index1}, @index2.single_int64, @index2.single_int32, @index4 + @index3], @index5 == 5) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([optional.ofNonZeroValue(1), optional.of(4), TestAllTypes{?single_int64: @index0, ?single_int32: @index1}, @index2.single_int32 + @index2.single_int64], @index3 == 5) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([optional.ofNonZeroValue(1), optional.of(4), TestAllTypes{?single_int64: @index0, ?single_int32: @index1}, @index2.single_int32 + @index2.single_int64], @index3 == 5) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([optional.ofNonZeroValue(1), optional.of(4), TestAllTypes{?single_int64: @index0, ?single_int32: @index1}, @index2.single_int32 + @index2.single_int64], @index3 == 5) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([optional.ofNonZeroValue(1), optional.of(4), TestAllTypes{?single_int64: @index0, ?single_int32: @index1}, @index2.single_int32 + @index2.single_int64], @index3 == 5) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([optional.ofNonZeroValue(1), optional.of(4), TestAllTypes{?single_int64: @index0, ?single_int32: @index1}, @index2.single_int32 + @index2.single_int64], @index3 == 5) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([optional.ofNonZeroValue(1), optional.of(4), TestAllTypes{?single_int64: @index0, ?single_int32: @index1}, @index2.single_int32 + @index2.single_int64], @index3 == 5) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([optional.ofNonZeroValue(1), optional.of(4), TestAllTypes{?single_int64: @index0, ?single_int32: @index1}, @index2.single_int32 + @index2.single_int64], @index3 == 5) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([optional.ofNonZeroValue(1), optional.of(4), TestAllTypes{?single_int64: @index0, ?single_int32: @index1}, @index2.single_int32 + @index2.single_int64], @index3 == 5) + +Test case: CALL +Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('h' + 'e' + 'l' + 'l' + 'o') +=====> +Result: true +[CASCADED_BINDS]: cel.bind(@r0, "h" + "e" + "l" + "l" + "o", (@r0 + " world").matches(@r0)) +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block(["h" + "e" + "l" + "l" + "o"], (@index0 + " world").matches(@index0)) +[BLOCK_RECURSION_DEPTH_1]: cel.@block(["h" + "e", @index0 + "l", @index1 + "l", @index2 + "o", @index3 + " world"], @index4.matches(@index3)) +[BLOCK_RECURSION_DEPTH_2]: cel.@block(["h" + "e", @index0 + "l", @index1 + "l", @index2 + "o", @index3 + " world"], @index4.matches(@index3)) +[BLOCK_RECURSION_DEPTH_3]: cel.@block(["h" + "e", @index0 + "l", @index1 + "l", @index2 + "o", @index3 + " world"], @index4.matches(@index3)) +[BLOCK_RECURSION_DEPTH_4]: cel.@block(["h" + "e", @index0 + "l", @index1 + "l", @index2 + "o", @index3 + " world"], @index4.matches(@index3)) +[BLOCK_RECURSION_DEPTH_5]: cel.@block(["h" + "e", @index0 + "l", @index1 + "l", @index2 + "o", @index3 + " world"], @index4.matches(@index3)) +[BLOCK_RECURSION_DEPTH_6]: cel.@block(["h" + "e", @index0 + "l", @index1 + "l", @index2 + "o", @index3 + " world"], @index4.matches(@index3)) +[BLOCK_RECURSION_DEPTH_7]: cel.@block(["h" + "e", @index0 + "l", @index1 + "l", @index2 + "o", @index3 + " world"], @index4.matches(@index3)) +[BLOCK_RECURSION_DEPTH_8]: cel.@block(["h" + "e", @index0 + "l", @index1 + "l", @index2 + "o", @index3 + " world"], @index4.matches(@index3)) +[BLOCK_RECURSION_DEPTH_9]: cel.@block(["h" + "e", @index0 + "l", @index1 + "l", @index2 + "o", @index3 + " world"], @index4.matches(@index3)) + +Test case: CALL_ARGUMENT_NESTED_NO_COMMON_SUBEXPR +Source: 'hello world'.matches('h' + 'e' + 'l' + 'l' + 'o') +=====> +Result: true +[CASCADED_BINDS]: "hello world".matches("h" + "e" + "l" + "l" + "o") +[BLOCK_COMMON_SUBEXPR_ONLY]: "hello world".matches("h" + "e" + "l" + "l" + "o") +[BLOCK_RECURSION_DEPTH_1]: cel.@block(["h" + "e", @index0 + "l", @index1 + "l", @index2 + "o"], "hello world".matches(@index3)) +[BLOCK_RECURSION_DEPTH_2]: cel.@block(["h" + "e" + "l", @index0 + "l" + "o"], "hello world".matches(@index1)) +[BLOCK_RECURSION_DEPTH_3]: cel.@block(["h" + "e" + "l" + "l", @index0 + "o"], "hello world".matches(@index1)) +[BLOCK_RECURSION_DEPTH_4]: cel.@block(["h" + "e" + "l" + "l" + "o"], "hello world".matches(@index0)) +[BLOCK_RECURSION_DEPTH_5]: cel.@block(["h" + "e" + "l" + "l" + "o"], "hello world".matches(@index0)) +[BLOCK_RECURSION_DEPTH_6]: cel.@block(["h" + "e" + "l" + "l" + "o"], "hello world".matches(@index0)) +[BLOCK_RECURSION_DEPTH_7]: cel.@block(["h" + "e" + "l" + "l" + "o"], "hello world".matches(@index0)) +[BLOCK_RECURSION_DEPTH_8]: cel.@block(["h" + "e" + "l" + "l" + "o"], "hello world".matches(@index0)) +[BLOCK_RECURSION_DEPTH_9]: cel.@block(["h" + "e" + "l" + "l" + "o"], "hello world".matches(@index0)) + +Test case: CALL_TARGET_NESTED_NO_COMMON_SUBEXPR +Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('hello') +=====> +Result: true +[CASCADED_BINDS]: ("h" + "e" + "l" + "l" + "o" + " world").matches("hello") +[BLOCK_COMMON_SUBEXPR_ONLY]: ("h" + "e" + "l" + "l" + "o" + " world").matches("hello") +[BLOCK_RECURSION_DEPTH_1]: cel.@block(["h" + "e", @index0 + "l", @index1 + "l", @index2 + "o", @index3 + " world"], @index4.matches("hello")) +[BLOCK_RECURSION_DEPTH_2]: cel.@block(["h" + "e" + "l", @index0 + "l" + "o", @index1 + " world"], @index2.matches("hello")) +[BLOCK_RECURSION_DEPTH_3]: cel.@block(["h" + "e" + "l" + "l", @index0 + "o" + " world"], @index1.matches("hello")) +[BLOCK_RECURSION_DEPTH_4]: cel.@block(["h" + "e" + "l" + "l" + "o", @index0 + " world"], @index1.matches("hello")) +[BLOCK_RECURSION_DEPTH_5]: cel.@block(["h" + "e" + "l" + "l" + "o" + " world"], @index0.matches("hello")) +[BLOCK_RECURSION_DEPTH_6]: cel.@block(["h" + "e" + "l" + "l" + "o" + " world"], @index0.matches("hello")) +[BLOCK_RECURSION_DEPTH_7]: cel.@block(["h" + "e" + "l" + "l" + "o" + " world"], @index0.matches("hello")) +[BLOCK_RECURSION_DEPTH_8]: cel.@block(["h" + "e" + "l" + "l" + "o" + " world"], @index0.matches("hello")) +[BLOCK_RECURSION_DEPTH_9]: cel.@block(["h" + "e" + "l" + "l" + "o" + " world"], @index0.matches("hello")) + +Test case: CALL_BOTH_ARGUMENT_TARGET_NESTED_NO_COMMON_SUBEXPR +Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('w' + 'o' + 'r' + 'l' + 'd') +=====> +Result: true +[CASCADED_BINDS]: ("h" + "e" + "l" + "l" + "o" + " world").matches("w" + "o" + "r" + "l" + "d") +[BLOCK_COMMON_SUBEXPR_ONLY]: ("h" + "e" + "l" + "l" + "o" + " world").matches("w" + "o" + "r" + "l" + "d") +[BLOCK_RECURSION_DEPTH_1]: cel.@block(["w" + "o", @index0 + "r", @index1 + "l", @index2 + "d", "h" + "e", @index4 + "l", @index5 + "l", @index6 + "o", @index7 + " world"], @index8.matches(@index3)) +[BLOCK_RECURSION_DEPTH_2]: cel.@block(["w" + "o" + "r", @index0 + "l" + "d", "h" + "e" + "l", @index2 + "l" + "o", @index3 + " world"], @index4.matches(@index1)) +[BLOCK_RECURSION_DEPTH_3]: cel.@block(["w" + "o" + "r" + "l", @index0 + "d", "h" + "e" + "l" + "l", @index2 + "o" + " world"], @index3.matches(@index1)) +[BLOCK_RECURSION_DEPTH_4]: cel.@block(["w" + "o" + "r" + "l" + "d", "h" + "e" + "l" + "l" + "o", @index1 + " world"], @index2.matches(@index0)) +[BLOCK_RECURSION_DEPTH_5]: cel.@block(["w" + "o" + "r" + "l" + "d", "h" + "e" + "l" + "l" + "o" + " world"], @index1.matches(@index0)) +[BLOCK_RECURSION_DEPTH_6]: cel.@block(["w" + "o" + "r" + "l" + "d", "h" + "e" + "l" + "l" + "o" + " world"], @index1.matches(@index0)) +[BLOCK_RECURSION_DEPTH_7]: cel.@block(["w" + "o" + "r" + "l" + "d", "h" + "e" + "l" + "l" + "o" + " world"], @index1.matches(@index0)) +[BLOCK_RECURSION_DEPTH_8]: cel.@block(["w" + "o" + "r" + "l" + "d", "h" + "e" + "l" + "l" + "o" + " world"], @index1.matches(@index0)) +[BLOCK_RECURSION_DEPTH_9]: cel.@block(["w" + "o" + "r" + "l" + "d", "h" + "e" + "l" + "l" + "o" + " world"], @index1.matches(@index0)) From 9ebad483f5a52c4d023afaea2f9c076ebe2792e1 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Tue, 27 Feb 2024 13:10:34 -0800 Subject: [PATCH 042/486] Accept eliminable custom functions as an option PiperOrigin-RevId: 610849935 --- .../dev/cel/optimizer/optimizers/BUILD.bazel | 1 + .../optimizers/SubexpressionOptimizer.java | 61 +++-- .../SubexpressionOptimizerBaselineTest.java | 97 ++++---- .../SubexpressionOptimizerTest.java | 18 +- ...ion_ast_block_common_subexpr_only.baseline | 145 ++++++++++++ ...ssion_ast_block_recursion_depth_1.baseline | 178 +++++++++++++++ ...ssion_ast_block_recursion_depth_2.baseline | 169 ++++++++++++++ ...ssion_ast_block_recursion_depth_3.baseline | 169 ++++++++++++++ ...ssion_ast_block_recursion_depth_4.baseline | 166 ++++++++++++++ ...ssion_ast_block_recursion_depth_5.baseline | 166 ++++++++++++++ ...ssion_ast_block_recursion_depth_6.baseline | 166 ++++++++++++++ ...ssion_ast_block_recursion_depth_7.baseline | 166 ++++++++++++++ ...ssion_ast_block_recursion_depth_8.baseline | 166 ++++++++++++++ ...ssion_ast_block_recursion_depth_9.baseline | 166 ++++++++++++++ .../subexpression_ast_cascaded_binds.baseline | 215 ++++++++++++++++++ .../resources/subexpression_unparsed.baseline | 32 +++ 16 files changed, 1998 insertions(+), 83 deletions(-) diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel b/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel index 279323603..38267774f 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel @@ -52,6 +52,7 @@ java_library( "//optimizer:ast_optimizer", "//optimizer:mutable_ast", "//parser:operator", + "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", "@maven//:org_jspecify_jspecify", ], diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java index ee2ec067b..a8e431ab9 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java @@ -14,6 +14,7 @@ package dev.cel.optimizer.optimizers; +import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.collect.ImmutableList.toImmutableList; import static com.google.common.collect.ImmutableSet.toImmutableSet; import static java.util.Arrays.stream; @@ -25,6 +26,7 @@ import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.common.collect.Streams; +import com.google.errorprone.annotations.CanIgnoreReturnValue; import dev.cel.bundle.CelBuilder; import dev.cel.checker.Standard; import dev.cel.common.CelAbstractSyntaxTree; @@ -52,6 +54,7 @@ import dev.cel.optimizer.MutableAst.MangledComprehensionAst; import dev.cel.parser.Operator; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -84,6 +87,12 @@ * */ public class SubexpressionOptimizer implements CelAstOptimizer { + private static final ImmutableSet CSE_DEFAULT_ELIMINABLE_FUNCTIONS = + Streams.concat( + stream(Operator.values()).map(Operator::getFunction), + stream(Standard.Function.values()).map(Standard.Function::getFunction), + stream(CelOptionalLibrary.Function.values()).map(Function::getFunction)) + .collect(toImmutableSet()); private static final SubexpressionOptimizer INSTANCE = new SubexpressionOptimizer(SubexpressionOptimizerOptions.newBuilder().build()); private static final String BIND_IDENTIFIER_PREFIX = "@r"; @@ -91,18 +100,12 @@ public class SubexpressionOptimizer implements CelAstOptimizer { private static final String MANGLED_COMPREHENSION_RESULT_PREFIX = "@x"; private static final String CEL_BLOCK_FUNCTION = "cel.@block"; private static final String BLOCK_INDEX_PREFIX = "@index"; - private static final ImmutableSet CSE_ALLOWED_FUNCTIONS = - Streams.concat( - stream(Operator.values()).map(Operator::getFunction), - stream(Standard.Function.values()).map(Standard.Function::getFunction), - stream(CelOptionalLibrary.Function.values()).map(Function::getFunction)) - .collect(toImmutableSet()); - private static final Extension CEL_BLOCK_AST_EXTENSION_TAG = Extension.create("cel_block", Version.of(1L, 1L), Component.COMPONENT_RUNTIME); private final SubexpressionOptimizerOptions cseOptions; private final MutableAst mutableAst; + private final ImmutableSet cseEliminableFunctions; /** * Returns a default instance of common subexpression elimination optimizer with preconfigured @@ -359,7 +362,7 @@ private Stream getAllCseCandidatesStream( return CelNavigableAst.fromAst(ast) .getRoot() .allNodes() - .filter(SubexpressionOptimizer::canEliminate) + .filter(this::canEliminate) .map(CelNavigableExpr::expr) .filter(expr -> areSemanticallyEqual(cseCandidate, expr)); } @@ -423,7 +426,7 @@ private Optional findCseCandidateWithRecursionDepth( CelNavigableAst.fromAst(ast) .getRoot() .allNodes(TraversalOrder.POST_ORDER) - .filter(SubexpressionOptimizer::canEliminate) + .filter(this::canEliminate) .filter(node -> node.height() <= recursionLimit) .filter(node -> !areSemanticallyEqual(ast.getExpr(), node.expr())) .collect(toImmutableList()); @@ -462,18 +465,18 @@ private Optional findCseCandidateWithCommonSubexpr(CelAbstract CelNavigableAst.fromAst(ast) .getRoot() .allNodes(TraversalOrder.PRE_ORDER) - .filter(SubexpressionOptimizer::canEliminate) + .filter(this::canEliminate) .collect(toImmutableList()); return findCseCandidateWithCommonSubexpr(allNodes); } - private static boolean canEliminate(CelNavigableExpr navigableExpr) { + private boolean canEliminate(CelNavigableExpr navigableExpr) { return !navigableExpr.getKind().equals(Kind.CONSTANT) && !navigableExpr.getKind().equals(Kind.IDENT) && !navigableExpr.expr().identOrDefault().name().startsWith(BIND_IDENTIFIER_PREFIX) && !navigableExpr.expr().selectOrDefault().testOnly() - && containsAllowedFunctionOnly(navigableExpr) + && containsEliminableFunctionOnly(navigableExpr) && isWithinInlineableComprehension(navigableExpr); } @@ -507,13 +510,13 @@ private boolean areSemanticallyEqual(CelExpr expr1, CelExpr expr2) { return normalizeForEquality(expr1).equals(normalizeForEquality(expr2)); } - private static boolean containsAllowedFunctionOnly(CelNavigableExpr navigableExpr) { + private boolean containsEliminableFunctionOnly(CelNavigableExpr navigableExpr) { return navigableExpr .allNodes() .allMatch( node -> { if (node.getKind().equals(Kind.CALL)) { - return CSE_ALLOWED_FUNCTIONS.contains(node.expr().call().function()); + return cseEliminableFunctions.contains(node.expr().call().function()); } return true; @@ -580,6 +583,8 @@ public abstract static class SubexpressionOptimizerOptions { public abstract int subexpressionMaxRecursionDepth(); + public abstract ImmutableSet eliminableFunctions(); + /** Builder for configuring the {@link SubexpressionOptimizerOptions}. */ @AutoValue.Builder public abstract static class Builder { @@ -630,11 +635,34 @@ public abstract static class Builder { */ public abstract Builder subexpressionMaxRecursionDepth(int value); + abstract ImmutableSet.Builder eliminableFunctionsBuilder(); + + /** + * Adds a collection of custom functions that will be a candidate for common subexpression + * elimination. By default, standard functions are eliminable. + * + *

Note that the implementation of custom functions must be free of side effects. + */ + @CanIgnoreReturnValue + public Builder addEliminableFunctions(Iterable functions) { + checkNotNull(functions); + this.eliminableFunctionsBuilder().addAll(functions); + return this; + } + + /** See {@link #addEliminableFunctions(Iterable)}. */ + @CanIgnoreReturnValue + public Builder addEliminableFunctions(String... functions) { + return addEliminableFunctions(Arrays.asList(functions)); + } + public abstract SubexpressionOptimizerOptions build(); Builder() {} } + abstract Builder toBuilder(); + /** Returns a new options builder with recommended defaults pre-configured. */ public static Builder newBuilder() { return new AutoValue_SubexpressionOptimizer_SubexpressionOptimizerOptions.Builder() @@ -650,5 +678,10 @@ public static Builder newBuilder() { private SubexpressionOptimizer(SubexpressionOptimizerOptions cseOptions) { this.cseOptions = cseOptions; this.mutableAst = MutableAst.newInstance(cseOptions.iterationLimit()); + this.cseEliminableFunctions = + ImmutableSet.builder() + .addAll(CSE_DEFAULT_ELIMINABLE_FUNCTIONS) + .addAll(cseOptions.eliminableFunctions()) + .build(); } } diff --git a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerBaselineTest.java b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerBaselineTest.java index 8590ff587..278a79976 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerBaselineTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerBaselineTest.java @@ -39,6 +39,7 @@ import dev.cel.parser.CelStandardMacro; import dev.cel.parser.CelUnparser; import dev.cel.parser.CelUnparserFactory; +import dev.cel.runtime.CelRuntime.CelFunctionBinding; import dev.cel.testing.BaselineTestCase; import dev.cel.testing.testdata.proto3.TestAllTypesProto.NestedTestAllTypes; import dev.cel.testing.testdata.proto3.TestAllTypesProto.TestAllTypes; @@ -68,6 +69,13 @@ public class SubexpressionOptimizerBaselineTest extends BaselineTestCase { .build(); private static final Cel CEL = newCelBuilder().build(); + private static final SubexpressionOptimizerOptions OPTIMIZER_COMMON_OPTIONS = + SubexpressionOptimizerOptions.newBuilder() + .populateMacroCalls(true) + .enableCelBlock(true) + .addEliminableFunctions("pure_custom_func") + .build(); + private String overriddenBaseFilePath = ""; @Before @@ -287,8 +295,16 @@ private static CelBuilder newCelBuilder() { .addRuntimeLibraries(CelOptionalLibrary.INSTANCE) .addFunctionDeclarations( CelFunctionDecl.newFunctionDeclaration( - "custom_func", - newGlobalOverload("custom_func_overload", SimpleType.INT, SimpleType.INT))) + "pure_custom_func", + newGlobalOverload("pure_custom_func_overload", SimpleType.INT, SimpleType.INT)), + CelFunctionDecl.newFunctionDeclaration( + "non_pure_custom_func", + newGlobalOverload("non_pure_custom_func_overload", SimpleType.INT, SimpleType.INT))) + .addFunctionBindings( + // This is pure, but for the purposes of excluding it as a CSE candidate, pretend that + // it isn't. + CelFunctionBinding.from("non_pure_custom_func_overload", Long.class, val -> val), + CelFunctionBinding.from("pure_custom_func_overload", Long.class, val -> val)) .addVar("x", SimpleType.DYN) .addVar("opt_x", OptionalType.create(SimpleType.DYN)) .addVar("msg", StructTypeReference.create(TestAllTypes.getDescriptor().getFullName())); @@ -302,70 +318,26 @@ private static CelOptimizer newCseOptimizer(Cel cel, SubexpressionOptimizerOptio @SuppressWarnings("Immutable") // Test only private enum CseTestOptimizer { - CASCADED_BINDS( - SubexpressionOptimizerOptions.newBuilder() - .populateMacroCalls(true) - .enableCelBlock(false) - .build()), - BLOCK_COMMON_SUBEXPR_ONLY( - SubexpressionOptimizerOptions.newBuilder() - .populateMacroCalls(true) - .enableCelBlock(true) - .build()), + CASCADED_BINDS(OPTIMIZER_COMMON_OPTIONS.toBuilder().enableCelBlock(false).build()), + BLOCK_COMMON_SUBEXPR_ONLY(OPTIMIZER_COMMON_OPTIONS), BLOCK_RECURSION_DEPTH_1( - SubexpressionOptimizerOptions.newBuilder() - .populateMacroCalls(true) - .enableCelBlock(true) - .subexpressionMaxRecursionDepth(1) - .build()), + OPTIMIZER_COMMON_OPTIONS.toBuilder().subexpressionMaxRecursionDepth(1).build()), BLOCK_RECURSION_DEPTH_2( - SubexpressionOptimizerOptions.newBuilder() - .populateMacroCalls(true) - .enableCelBlock(true) - .subexpressionMaxRecursionDepth(2) - .build()), + OPTIMIZER_COMMON_OPTIONS.toBuilder().subexpressionMaxRecursionDepth(2).build()), BLOCK_RECURSION_DEPTH_3( - SubexpressionOptimizerOptions.newBuilder() - .populateMacroCalls(true) - .enableCelBlock(true) - .subexpressionMaxRecursionDepth(3) - .build()), + OPTIMIZER_COMMON_OPTIONS.toBuilder().subexpressionMaxRecursionDepth(3).build()), BLOCK_RECURSION_DEPTH_4( - SubexpressionOptimizerOptions.newBuilder() - .populateMacroCalls(true) - .enableCelBlock(true) - .subexpressionMaxRecursionDepth(4) - .build()), + OPTIMIZER_COMMON_OPTIONS.toBuilder().subexpressionMaxRecursionDepth(4).build()), BLOCK_RECURSION_DEPTH_5( - SubexpressionOptimizerOptions.newBuilder() - .populateMacroCalls(true) - .enableCelBlock(true) - .subexpressionMaxRecursionDepth(5) - .build()), + OPTIMIZER_COMMON_OPTIONS.toBuilder().subexpressionMaxRecursionDepth(5).build()), BLOCK_RECURSION_DEPTH_6( - SubexpressionOptimizerOptions.newBuilder() - .populateMacroCalls(true) - .enableCelBlock(true) - .subexpressionMaxRecursionDepth(6) - .build()), + OPTIMIZER_COMMON_OPTIONS.toBuilder().subexpressionMaxRecursionDepth(6).build()), BLOCK_RECURSION_DEPTH_7( - SubexpressionOptimizerOptions.newBuilder() - .populateMacroCalls(true) - .enableCelBlock(true) - .subexpressionMaxRecursionDepth(7) - .build()), + OPTIMIZER_COMMON_OPTIONS.toBuilder().subexpressionMaxRecursionDepth(7).build()), BLOCK_RECURSION_DEPTH_8( - SubexpressionOptimizerOptions.newBuilder() - .populateMacroCalls(true) - .enableCelBlock(true) - .subexpressionMaxRecursionDepth(8) - .build()), + OPTIMIZER_COMMON_OPTIONS.toBuilder().subexpressionMaxRecursionDepth(8).build()), BLOCK_RECURSION_DEPTH_9( - SubexpressionOptimizerOptions.newBuilder() - .populateMacroCalls(true) - .enableCelBlock(true) - .subexpressionMaxRecursionDepth(9) - .build()); + OPTIMIZER_COMMON_OPTIONS.toBuilder().subexpressionMaxRecursionDepth(9).build()); private final CelOptimizer celOptimizer; @@ -507,7 +479,16 @@ private enum CseTestCase { "('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('hello')"), CALL_BOTH_ARGUMENT_TARGET_NESTED_NO_COMMON_SUBEXPR( "('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('w' + 'o' + 'r' + 'l' + 'd')"), - ; + CUSTOM_FUNCTION_INELIMINABLE( + "non_pure_custom_func(msg.oneof_type.payload.single_int64) +" + + " non_pure_custom_func(msg.oneof_type.payload.single_int32) +" + + " non_pure_custom_func(msg.oneof_type.payload.single_int64) +" + + " non_pure_custom_func(msg.single_int64)"), + CUSTOM_FUNCTION_ELIMINABLE( + "pure_custom_func(msg.oneof_type.payload.single_int64) +" + + " pure_custom_func(msg.oneof_type.payload.single_int32) +" + + " pure_custom_func(msg.oneof_type.payload.single_int64) +" + + " pure_custom_func(msg.single_int64)"); private final String source; CseTestCase(String source) { diff --git a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java index f09a7e9c7..3668d776e 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java @@ -41,11 +41,9 @@ import dev.cel.common.navigation.CelNavigableAst; import dev.cel.common.navigation.CelNavigableExpr; import dev.cel.common.types.ListType; -import dev.cel.common.types.OptionalType; import dev.cel.common.types.SimpleType; import dev.cel.common.types.StructTypeReference; import dev.cel.extensions.CelExtensions; -import dev.cel.extensions.CelOptionalLibrary; import dev.cel.optimizer.CelOptimizationException; import dev.cel.optimizer.CelOptimizer; import dev.cel.optimizer.CelOptimizerFactory; @@ -107,18 +105,15 @@ public class SubexpressionOptimizerTest { private static CelBuilder newCelBuilder() { return CelFactory.standardCelBuilder() .addMessageTypes(TestAllTypes.getDescriptor()) - .setContainer("dev.cel.testing.testdata.proto3") .setStandardMacros(CelStandardMacro.STANDARD_MACROS) .setOptions( CelOptions.current().enableTimestampEpoch(true).populateMacroCalls(true).build()) - .addCompilerLibraries(CelOptionalLibrary.INSTANCE, CelExtensions.bindings()) - .addRuntimeLibraries(CelOptionalLibrary.INSTANCE) + .addCompilerLibraries(CelExtensions.bindings()) .addFunctionDeclarations( CelFunctionDecl.newFunctionDeclaration( - "custom_func", - newGlobalOverload("custom_func_overload", SimpleType.INT, SimpleType.INT))) + "non_pure_custom_func", + newGlobalOverload("non_pure_custom_func_overload", SimpleType.INT, SimpleType.INT))) .addVar("x", SimpleType.DYN) - .addVar("opt_x", OptionalType.create(SimpleType.DYN)) .addVar("msg", StructTypeReference.create(TestAllTypes.getDescriptor().getFullName())); } @@ -156,9 +151,10 @@ private enum CseNoOpTestCase { // Constants and identifiers within a function CONST_WITHIN_FUNCTION("size(\"hello\" + \"hello\" + \"hello\")"), IDENT_WITHIN_FUNCTION("string(x + x + x)"), - // Non-standard functions are considered non-pure for time being - NON_STANDARD_FUNCTION_1("custom_func(1) + custom_func(1)"), - NON_STANDARD_FUNCTION_2("1 + custom_func(1) + 1 + custom_func(1)"), + // Non-standard functions that have not been explicitly added as a candidate are not + // optimized. + NON_STANDARD_FUNCTION_1("non_pure_custom_func(1) + non_pure_custom_func(1)"), + NON_STANDARD_FUNCTION_2("1 + non_pure_custom_func(1) + 1 + non_pure_custom_func(1)"), // Duplicated but nested calls. NESTED_FUNCTION("int(timestamp(int(timestamp(1000000000))))"), // This cannot be optimized. Extracting the common subexpression would presence test diff --git a/optimizer/src/test/resources/subexpression_ast_block_common_subexpr_only.baseline b/optimizer/src/test/resources/subexpression_ast_block_common_subexpr_only.baseline index 1b0adb211..960821d8a 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_common_subexpr_only.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_common_subexpr_only.baseline @@ -2922,3 +2922,148 @@ CALL [12] { } } } +Test case: CUSTOM_FUNCTION_INELIMINABLE +Source: non_pure_custom_func(msg.oneof_type.payload.single_int64) + non_pure_custom_func(msg.oneof_type.payload.single_int32) + non_pure_custom_func(msg.oneof_type.payload.single_int64) + non_pure_custom_func(msg.single_int64) +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + SELECT [4] { + IDENT [5] { + name: msg + }.oneof_type + }.payload + } + SELECT [6] { + IDENT [7] { + name: @index0 + }.single_int64 + } + } + } + CALL [8] { + function: _+_ + args: { + CALL [9] { + function: _+_ + args: { + CALL [10] { + function: _+_ + args: { + CALL [11] { + function: non_pure_custom_func + args: { + IDENT [12] { + name: @index1 + } + } + } + CALL [13] { + function: non_pure_custom_func + args: { + SELECT [14] { + IDENT [15] { + name: @index0 + }.single_int32 + } + } + } + } + } + CALL [16] { + function: non_pure_custom_func + args: { + IDENT [17] { + name: @index1 + } + } + } + } + } + CALL [18] { + function: non_pure_custom_func + args: { + SELECT [19] { + IDENT [20] { + name: msg + }.single_int64 + } + } + } + } + } + } +} +Test case: CUSTOM_FUNCTION_ELIMINABLE +Source: pure_custom_func(msg.oneof_type.payload.single_int64) + pure_custom_func(msg.oneof_type.payload.single_int32) + pure_custom_func(msg.oneof_type.payload.single_int64) + pure_custom_func(msg.single_int64) +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + SELECT [4] { + IDENT [5] { + name: msg + }.oneof_type + }.payload + } + CALL [6] { + function: pure_custom_func + args: { + SELECT [7] { + IDENT [8] { + name: @index0 + }.single_int64 + } + } + } + } + } + CALL [9] { + function: _+_ + args: { + CALL [10] { + function: _+_ + args: { + CALL [11] { + function: _+_ + args: { + IDENT [12] { + name: @index1 + } + CALL [13] { + function: pure_custom_func + args: { + SELECT [14] { + IDENT [15] { + name: @index0 + }.single_int32 + } + } + } + } + } + IDENT [16] { + name: @index1 + } + } + } + CALL [17] { + function: pure_custom_func + args: { + SELECT [18] { + IDENT [19] { + name: msg + }.single_int64 + } + } + } + } + } + } +} diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_1.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_1.baseline index 77f95f1a3..a8b6c243c 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_1.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_1.baseline @@ -3708,3 +3708,181 @@ CALL [1] { } } } +Test case: CUSTOM_FUNCTION_INELIMINABLE +Source: non_pure_custom_func(msg.oneof_type.payload.single_int64) + non_pure_custom_func(msg.oneof_type.payload.single_int32) + non_pure_custom_func(msg.oneof_type.payload.single_int64) + non_pure_custom_func(msg.single_int64) +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.single_int64 + } + SELECT [9] { + IDENT [10] { + name: msg + }.single_int64 + } + SELECT [11] { + IDENT [12] { + name: @index1 + }.single_int32 + } + } + } + CALL [13] { + function: _+_ + args: { + CALL [14] { + function: _+_ + args: { + CALL [15] { + function: _+_ + args: { + CALL [16] { + function: non_pure_custom_func + args: { + IDENT [17] { + name: @index2 + } + } + } + CALL [18] { + function: non_pure_custom_func + args: { + IDENT [19] { + name: @index4 + } + } + } + } + } + CALL [20] { + function: non_pure_custom_func + args: { + IDENT [21] { + name: @index2 + } + } + } + } + } + CALL [22] { + function: non_pure_custom_func + args: { + IDENT [23] { + name: @index3 + } + } + } + } + } + } +} +Test case: CUSTOM_FUNCTION_ELIMINABLE +Source: pure_custom_func(msg.oneof_type.payload.single_int64) + pure_custom_func(msg.oneof_type.payload.single_int32) + pure_custom_func(msg.oneof_type.payload.single_int64) + pure_custom_func(msg.single_int64) +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.single_int64 + } + CALL [9] { + function: pure_custom_func + args: { + IDENT [10] { + name: @index2 + } + } + } + SELECT [11] { + IDENT [12] { + name: msg + }.single_int64 + } + CALL [13] { + function: pure_custom_func + args: { + IDENT [14] { + name: @index4 + } + } + } + SELECT [15] { + IDENT [16] { + name: @index1 + }.single_int32 + } + CALL [17] { + function: pure_custom_func + args: { + IDENT [18] { + name: @index6 + } + } + } + CALL [19] { + function: _+_ + args: { + IDENT [20] { + name: @index3 + } + IDENT [21] { + name: @index7 + } + } + } + CALL [22] { + function: _+_ + args: { + IDENT [23] { + name: @index8 + } + IDENT [24] { + name: @index3 + } + } + } + } + } + CALL [25] { + function: _+_ + args: { + IDENT [26] { + name: @index9 + } + IDENT [27] { + name: @index5 + } + } + } + } +} diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_2.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_2.baseline index 5a2a4272c..ff087237a 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_2.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_2.baseline @@ -3567,3 +3567,172 @@ CALL [1] { } } } +Test case: CUSTOM_FUNCTION_INELIMINABLE +Source: non_pure_custom_func(msg.oneof_type.payload.single_int64) + non_pure_custom_func(msg.oneof_type.payload.single_int32) + non_pure_custom_func(msg.oneof_type.payload.single_int64) + non_pure_custom_func(msg.single_int64) +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.single_int64 + } + SELECT [9] { + IDENT [10] { + name: msg + }.single_int64 + } + SELECT [11] { + IDENT [12] { + name: @index1 + }.single_int32 + } + } + } + CALL [13] { + function: _+_ + args: { + CALL [14] { + function: _+_ + args: { + CALL [15] { + function: _+_ + args: { + CALL [16] { + function: non_pure_custom_func + args: { + IDENT [17] { + name: @index2 + } + } + } + CALL [18] { + function: non_pure_custom_func + args: { + IDENT [19] { + name: @index4 + } + } + } + } + } + CALL [20] { + function: non_pure_custom_func + args: { + IDENT [21] { + name: @index2 + } + } + } + } + } + CALL [22] { + function: non_pure_custom_func + args: { + IDENT [23] { + name: @index3 + } + } + } + } + } + } +} +Test case: CUSTOM_FUNCTION_ELIMINABLE +Source: pure_custom_func(msg.oneof_type.payload.single_int64) + pure_custom_func(msg.oneof_type.payload.single_int32) + pure_custom_func(msg.oneof_type.payload.single_int64) + pure_custom_func(msg.single_int64) +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.single_int64 + } + CALL [9] { + function: pure_custom_func + args: { + IDENT [10] { + name: @index2 + } + } + } + CALL [11] { + function: pure_custom_func + args: { + SELECT [12] { + IDENT [13] { + name: msg + }.single_int64 + } + } + } + CALL [14] { + function: pure_custom_func + args: { + SELECT [15] { + IDENT [16] { + name: @index1 + }.single_int32 + } + } + } + CALL [17] { + function: _+_ + args: { + CALL [18] { + function: _+_ + args: { + IDENT [19] { + name: @index3 + } + IDENT [20] { + name: @index5 + } + } + } + IDENT [21] { + name: @index3 + } + } + } + } + } + CALL [22] { + function: _+_ + args: { + IDENT [23] { + name: @index6 + } + IDENT [24] { + name: @index4 + } + } + } + } +} diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_3.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_3.baseline index bf930a9e5..a0ff868b1 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_3.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_3.baseline @@ -3357,3 +3357,172 @@ CALL [1] { } } } +Test case: CUSTOM_FUNCTION_INELIMINABLE +Source: non_pure_custom_func(msg.oneof_type.payload.single_int64) + non_pure_custom_func(msg.oneof_type.payload.single_int32) + non_pure_custom_func(msg.oneof_type.payload.single_int64) + non_pure_custom_func(msg.single_int64) +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.single_int64 + } + SELECT [9] { + IDENT [10] { + name: msg + }.single_int64 + } + SELECT [11] { + IDENT [12] { + name: @index1 + }.single_int32 + } + } + } + CALL [13] { + function: _+_ + args: { + CALL [14] { + function: _+_ + args: { + CALL [15] { + function: _+_ + args: { + CALL [16] { + function: non_pure_custom_func + args: { + IDENT [17] { + name: @index2 + } + } + } + CALL [18] { + function: non_pure_custom_func + args: { + IDENT [19] { + name: @index4 + } + } + } + } + } + CALL [20] { + function: non_pure_custom_func + args: { + IDENT [21] { + name: @index2 + } + } + } + } + } + CALL [22] { + function: non_pure_custom_func + args: { + IDENT [23] { + name: @index3 + } + } + } + } + } + } +} +Test case: CUSTOM_FUNCTION_ELIMINABLE +Source: pure_custom_func(msg.oneof_type.payload.single_int64) + pure_custom_func(msg.oneof_type.payload.single_int32) + pure_custom_func(msg.oneof_type.payload.single_int64) + pure_custom_func(msg.single_int64) +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.single_int64 + } + CALL [9] { + function: pure_custom_func + args: { + IDENT [10] { + name: @index2 + } + } + } + CALL [11] { + function: pure_custom_func + args: { + SELECT [12] { + IDENT [13] { + name: msg + }.single_int64 + } + } + } + CALL [14] { + function: _+_ + args: { + IDENT [15] { + name: @index3 + } + CALL [16] { + function: pure_custom_func + args: { + SELECT [17] { + IDENT [18] { + name: @index1 + }.single_int32 + } + } + } + } + } + CALL [19] { + function: _+_ + args: { + IDENT [20] { + name: @index5 + } + IDENT [21] { + name: @index3 + } + } + } + } + } + CALL [22] { + function: _+_ + args: { + IDENT [23] { + name: @index6 + } + IDENT [24] { + name: @index4 + } + } + } + } +} diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_4.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_4.baseline index c51cefac6..71a440692 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_4.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_4.baseline @@ -3324,3 +3324,169 @@ CALL [1] { } } } +Test case: CUSTOM_FUNCTION_INELIMINABLE +Source: non_pure_custom_func(msg.oneof_type.payload.single_int64) + non_pure_custom_func(msg.oneof_type.payload.single_int32) + non_pure_custom_func(msg.oneof_type.payload.single_int64) + non_pure_custom_func(msg.single_int64) +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.single_int64 + } + SELECT [9] { + IDENT [10] { + name: msg + }.single_int64 + } + SELECT [11] { + IDENT [12] { + name: @index1 + }.single_int32 + } + } + } + CALL [13] { + function: _+_ + args: { + CALL [14] { + function: _+_ + args: { + CALL [15] { + function: _+_ + args: { + CALL [16] { + function: non_pure_custom_func + args: { + IDENT [17] { + name: @index2 + } + } + } + CALL [18] { + function: non_pure_custom_func + args: { + IDENT [19] { + name: @index4 + } + } + } + } + } + CALL [20] { + function: non_pure_custom_func + args: { + IDENT [21] { + name: @index2 + } + } + } + } + } + CALL [22] { + function: non_pure_custom_func + args: { + IDENT [23] { + name: @index3 + } + } + } + } + } + } +} +Test case: CUSTOM_FUNCTION_ELIMINABLE +Source: pure_custom_func(msg.oneof_type.payload.single_int64) + pure_custom_func(msg.oneof_type.payload.single_int32) + pure_custom_func(msg.oneof_type.payload.single_int64) + pure_custom_func(msg.single_int64) +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.single_int64 + } + CALL [9] { + function: pure_custom_func + args: { + IDENT [10] { + name: @index2 + } + } + } + CALL [11] { + function: pure_custom_func + args: { + SELECT [12] { + IDENT [13] { + name: msg + }.single_int64 + } + } + } + CALL [14] { + function: _+_ + args: { + CALL [15] { + function: _+_ + args: { + IDENT [16] { + name: @index3 + } + CALL [17] { + function: pure_custom_func + args: { + SELECT [18] { + IDENT [19] { + name: @index1 + }.single_int32 + } + } + } + } + } + IDENT [20] { + name: @index3 + } + } + } + } + } + CALL [21] { + function: _+_ + args: { + IDENT [22] { + name: @index5 + } + IDENT [23] { + name: @index4 + } + } + } + } +} diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_5.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_5.baseline index 092b22477..d5d799e1f 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_5.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_5.baseline @@ -3297,3 +3297,169 @@ CALL [1] { } } } +Test case: CUSTOM_FUNCTION_INELIMINABLE +Source: non_pure_custom_func(msg.oneof_type.payload.single_int64) + non_pure_custom_func(msg.oneof_type.payload.single_int32) + non_pure_custom_func(msg.oneof_type.payload.single_int64) + non_pure_custom_func(msg.single_int64) +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.single_int64 + } + SELECT [9] { + IDENT [10] { + name: msg + }.single_int64 + } + SELECT [11] { + IDENT [12] { + name: @index1 + }.single_int32 + } + } + } + CALL [13] { + function: _+_ + args: { + CALL [14] { + function: _+_ + args: { + CALL [15] { + function: _+_ + args: { + CALL [16] { + function: non_pure_custom_func + args: { + IDENT [17] { + name: @index2 + } + } + } + CALL [18] { + function: non_pure_custom_func + args: { + IDENT [19] { + name: @index4 + } + } + } + } + } + CALL [20] { + function: non_pure_custom_func + args: { + IDENT [21] { + name: @index2 + } + } + } + } + } + CALL [22] { + function: non_pure_custom_func + args: { + IDENT [23] { + name: @index3 + } + } + } + } + } + } +} +Test case: CUSTOM_FUNCTION_ELIMINABLE +Source: pure_custom_func(msg.oneof_type.payload.single_int64) + pure_custom_func(msg.oneof_type.payload.single_int32) + pure_custom_func(msg.oneof_type.payload.single_int64) + pure_custom_func(msg.single_int64) +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.single_int64 + } + CALL [9] { + function: pure_custom_func + args: { + IDENT [10] { + name: @index2 + } + } + } + CALL [11] { + function: pure_custom_func + args: { + SELECT [12] { + IDENT [13] { + name: msg + }.single_int64 + } + } + } + CALL [14] { + function: _+_ + args: { + CALL [15] { + function: _+_ + args: { + IDENT [16] { + name: @index3 + } + CALL [17] { + function: pure_custom_func + args: { + SELECT [18] { + IDENT [19] { + name: @index1 + }.single_int32 + } + } + } + } + } + IDENT [20] { + name: @index3 + } + } + } + } + } + CALL [21] { + function: _+_ + args: { + IDENT [22] { + name: @index5 + } + IDENT [23] { + name: @index4 + } + } + } + } +} diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_6.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_6.baseline index fb329babc..a2ecbc777 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_6.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_6.baseline @@ -3291,3 +3291,169 @@ CALL [1] { } } } +Test case: CUSTOM_FUNCTION_INELIMINABLE +Source: non_pure_custom_func(msg.oneof_type.payload.single_int64) + non_pure_custom_func(msg.oneof_type.payload.single_int32) + non_pure_custom_func(msg.oneof_type.payload.single_int64) + non_pure_custom_func(msg.single_int64) +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.single_int64 + } + SELECT [9] { + IDENT [10] { + name: msg + }.single_int64 + } + SELECT [11] { + IDENT [12] { + name: @index1 + }.single_int32 + } + } + } + CALL [13] { + function: _+_ + args: { + CALL [14] { + function: _+_ + args: { + CALL [15] { + function: _+_ + args: { + CALL [16] { + function: non_pure_custom_func + args: { + IDENT [17] { + name: @index2 + } + } + } + CALL [18] { + function: non_pure_custom_func + args: { + IDENT [19] { + name: @index4 + } + } + } + } + } + CALL [20] { + function: non_pure_custom_func + args: { + IDENT [21] { + name: @index2 + } + } + } + } + } + CALL [22] { + function: non_pure_custom_func + args: { + IDENT [23] { + name: @index3 + } + } + } + } + } + } +} +Test case: CUSTOM_FUNCTION_ELIMINABLE +Source: pure_custom_func(msg.oneof_type.payload.single_int64) + pure_custom_func(msg.oneof_type.payload.single_int32) + pure_custom_func(msg.oneof_type.payload.single_int64) + pure_custom_func(msg.single_int64) +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.single_int64 + } + CALL [9] { + function: pure_custom_func + args: { + IDENT [10] { + name: @index2 + } + } + } + CALL [11] { + function: pure_custom_func + args: { + SELECT [12] { + IDENT [13] { + name: msg + }.single_int64 + } + } + } + CALL [14] { + function: _+_ + args: { + CALL [15] { + function: _+_ + args: { + IDENT [16] { + name: @index3 + } + CALL [17] { + function: pure_custom_func + args: { + SELECT [18] { + IDENT [19] { + name: @index1 + }.single_int32 + } + } + } + } + } + IDENT [20] { + name: @index3 + } + } + } + } + } + CALL [21] { + function: _+_ + args: { + IDENT [22] { + name: @index5 + } + IDENT [23] { + name: @index4 + } + } + } + } +} diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_7.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_7.baseline index c318f8779..973b97c3a 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_7.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_7.baseline @@ -3285,3 +3285,169 @@ CALL [1] { } } } +Test case: CUSTOM_FUNCTION_INELIMINABLE +Source: non_pure_custom_func(msg.oneof_type.payload.single_int64) + non_pure_custom_func(msg.oneof_type.payload.single_int32) + non_pure_custom_func(msg.oneof_type.payload.single_int64) + non_pure_custom_func(msg.single_int64) +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.single_int64 + } + SELECT [9] { + IDENT [10] { + name: msg + }.single_int64 + } + SELECT [11] { + IDENT [12] { + name: @index1 + }.single_int32 + } + } + } + CALL [13] { + function: _+_ + args: { + CALL [14] { + function: _+_ + args: { + CALL [15] { + function: _+_ + args: { + CALL [16] { + function: non_pure_custom_func + args: { + IDENT [17] { + name: @index2 + } + } + } + CALL [18] { + function: non_pure_custom_func + args: { + IDENT [19] { + name: @index4 + } + } + } + } + } + CALL [20] { + function: non_pure_custom_func + args: { + IDENT [21] { + name: @index2 + } + } + } + } + } + CALL [22] { + function: non_pure_custom_func + args: { + IDENT [23] { + name: @index3 + } + } + } + } + } + } +} +Test case: CUSTOM_FUNCTION_ELIMINABLE +Source: pure_custom_func(msg.oneof_type.payload.single_int64) + pure_custom_func(msg.oneof_type.payload.single_int32) + pure_custom_func(msg.oneof_type.payload.single_int64) + pure_custom_func(msg.single_int64) +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.single_int64 + } + CALL [9] { + function: pure_custom_func + args: { + IDENT [10] { + name: @index2 + } + } + } + CALL [11] { + function: pure_custom_func + args: { + SELECT [12] { + IDENT [13] { + name: msg + }.single_int64 + } + } + } + CALL [14] { + function: _+_ + args: { + CALL [15] { + function: _+_ + args: { + IDENT [16] { + name: @index3 + } + CALL [17] { + function: pure_custom_func + args: { + SELECT [18] { + IDENT [19] { + name: @index1 + }.single_int32 + } + } + } + } + } + IDENT [20] { + name: @index3 + } + } + } + } + } + CALL [21] { + function: _+_ + args: { + IDENT [22] { + name: @index5 + } + IDENT [23] { + name: @index4 + } + } + } + } +} diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_8.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_8.baseline index 10e94e557..67f1b1308 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_8.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_8.baseline @@ -3279,3 +3279,169 @@ CALL [1] { } } } +Test case: CUSTOM_FUNCTION_INELIMINABLE +Source: non_pure_custom_func(msg.oneof_type.payload.single_int64) + non_pure_custom_func(msg.oneof_type.payload.single_int32) + non_pure_custom_func(msg.oneof_type.payload.single_int64) + non_pure_custom_func(msg.single_int64) +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.single_int64 + } + SELECT [9] { + IDENT [10] { + name: msg + }.single_int64 + } + SELECT [11] { + IDENT [12] { + name: @index1 + }.single_int32 + } + } + } + CALL [13] { + function: _+_ + args: { + CALL [14] { + function: _+_ + args: { + CALL [15] { + function: _+_ + args: { + CALL [16] { + function: non_pure_custom_func + args: { + IDENT [17] { + name: @index2 + } + } + } + CALL [18] { + function: non_pure_custom_func + args: { + IDENT [19] { + name: @index4 + } + } + } + } + } + CALL [20] { + function: non_pure_custom_func + args: { + IDENT [21] { + name: @index2 + } + } + } + } + } + CALL [22] { + function: non_pure_custom_func + args: { + IDENT [23] { + name: @index3 + } + } + } + } + } + } +} +Test case: CUSTOM_FUNCTION_ELIMINABLE +Source: pure_custom_func(msg.oneof_type.payload.single_int64) + pure_custom_func(msg.oneof_type.payload.single_int32) + pure_custom_func(msg.oneof_type.payload.single_int64) + pure_custom_func(msg.single_int64) +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.single_int64 + } + CALL [9] { + function: pure_custom_func + args: { + IDENT [10] { + name: @index2 + } + } + } + CALL [11] { + function: pure_custom_func + args: { + SELECT [12] { + IDENT [13] { + name: msg + }.single_int64 + } + } + } + CALL [14] { + function: _+_ + args: { + CALL [15] { + function: _+_ + args: { + IDENT [16] { + name: @index3 + } + CALL [17] { + function: pure_custom_func + args: { + SELECT [18] { + IDENT [19] { + name: @index1 + }.single_int32 + } + } + } + } + } + IDENT [20] { + name: @index3 + } + } + } + } + } + CALL [21] { + function: _+_ + args: { + IDENT [22] { + name: @index5 + } + IDENT [23] { + name: @index4 + } + } + } + } +} diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_9.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_9.baseline index 0988f15f9..fc16cdf85 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_9.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_9.baseline @@ -3276,3 +3276,169 @@ CALL [1] { } } } +Test case: CUSTOM_FUNCTION_INELIMINABLE +Source: non_pure_custom_func(msg.oneof_type.payload.single_int64) + non_pure_custom_func(msg.oneof_type.payload.single_int32) + non_pure_custom_func(msg.oneof_type.payload.single_int64) + non_pure_custom_func(msg.single_int64) +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.single_int64 + } + SELECT [9] { + IDENT [10] { + name: msg + }.single_int64 + } + SELECT [11] { + IDENT [12] { + name: @index1 + }.single_int32 + } + } + } + CALL [13] { + function: _+_ + args: { + CALL [14] { + function: _+_ + args: { + CALL [15] { + function: _+_ + args: { + CALL [16] { + function: non_pure_custom_func + args: { + IDENT [17] { + name: @index2 + } + } + } + CALL [18] { + function: non_pure_custom_func + args: { + IDENT [19] { + name: @index4 + } + } + } + } + } + CALL [20] { + function: non_pure_custom_func + args: { + IDENT [21] { + name: @index2 + } + } + } + } + } + CALL [22] { + function: non_pure_custom_func + args: { + IDENT [23] { + name: @index3 + } + } + } + } + } + } +} +Test case: CUSTOM_FUNCTION_ELIMINABLE +Source: pure_custom_func(msg.oneof_type.payload.single_int64) + pure_custom_func(msg.oneof_type.payload.single_int32) + pure_custom_func(msg.oneof_type.payload.single_int64) + pure_custom_func(msg.single_int64) +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.single_int64 + } + CALL [9] { + function: pure_custom_func + args: { + IDENT [10] { + name: @index2 + } + } + } + CALL [11] { + function: pure_custom_func + args: { + SELECT [12] { + IDENT [13] { + name: msg + }.single_int64 + } + } + } + CALL [14] { + function: _+_ + args: { + CALL [15] { + function: _+_ + args: { + IDENT [16] { + name: @index3 + } + CALL [17] { + function: pure_custom_func + args: { + SELECT [18] { + IDENT [19] { + name: @index1 + }.single_int32 + } + } + } + } + } + IDENT [20] { + name: @index3 + } + } + } + } + } + CALL [21] { + function: _+_ + args: { + IDENT [22] { + name: @index5 + } + IDENT [23] { + name: @index4 + } + } + } + } +} diff --git a/optimizer/src/test/resources/subexpression_ast_cascaded_binds.baseline b/optimizer/src/test/resources/subexpression_ast_cascaded_binds.baseline index 0dd7c6734..08e584050 100644 --- a/optimizer/src/test/resources/subexpression_ast_cascaded_binds.baseline +++ b/optimizer/src/test/resources/subexpression_ast_cascaded_binds.baseline @@ -3892,3 +3892,218 @@ CALL [12] { } } } +Test case: CUSTOM_FUNCTION_INELIMINABLE +Source: non_pure_custom_func(msg.oneof_type.payload.single_int64) + non_pure_custom_func(msg.oneof_type.payload.single_int32) + non_pure_custom_func(msg.oneof_type.payload.single_int64) + non_pure_custom_func(msg.single_int64) +=====> +CALL [1] { + function: _+_ + args: { + COMPREHENSION [2] { + iter_var: #unused + iter_range: { + CREATE_LIST [3] { + elements: { + } + } + } + accu_var: @r0 + accu_init: { + SELECT [4] { + SELECT [5] { + IDENT [6] { + name: msg + }.oneof_type + }.payload + } + } + loop_condition: { + CONSTANT [7] { value: false } + } + loop_step: { + IDENT [8] { + name: @r0 + } + } + result: { + COMPREHENSION [9] { + iter_var: #unused + iter_range: { + CREATE_LIST [10] { + elements: { + } + } + } + accu_var: @r1 + accu_init: { + SELECT [11] { + IDENT [12] { + name: @r0 + }.single_int64 + } + } + loop_condition: { + CONSTANT [13] { value: false } + } + loop_step: { + IDENT [14] { + name: @r1 + } + } + result: { + CALL [15] { + function: _+_ + args: { + CALL [16] { + function: _+_ + args: { + CALL [17] { + function: non_pure_custom_func + args: { + IDENT [18] { + name: @r1 + } + } + } + CALL [19] { + function: non_pure_custom_func + args: { + SELECT [20] { + IDENT [21] { + name: @r0 + }.single_int32 + } + } + } + } + } + CALL [22] { + function: non_pure_custom_func + args: { + IDENT [23] { + name: @r1 + } + } + } + } + } + } + } + } + } + CALL [24] { + function: non_pure_custom_func + args: { + SELECT [25] { + IDENT [26] { + name: msg + }.single_int64 + } + } + } + } +} +Test case: CUSTOM_FUNCTION_ELIMINABLE +Source: pure_custom_func(msg.oneof_type.payload.single_int64) + pure_custom_func(msg.oneof_type.payload.single_int32) + pure_custom_func(msg.oneof_type.payload.single_int64) + pure_custom_func(msg.single_int64) +=====> +CALL [1] { + function: _+_ + args: { + COMPREHENSION [2] { + iter_var: #unused + iter_range: { + CREATE_LIST [3] { + elements: { + } + } + } + accu_var: @r0 + accu_init: { + SELECT [4] { + SELECT [5] { + IDENT [6] { + name: msg + }.oneof_type + }.payload + } + } + loop_condition: { + CONSTANT [7] { value: false } + } + loop_step: { + IDENT [8] { + name: @r0 + } + } + result: { + COMPREHENSION [9] { + iter_var: #unused + iter_range: { + CREATE_LIST [10] { + elements: { + } + } + } + accu_var: @r1 + accu_init: { + CALL [11] { + function: pure_custom_func + args: { + SELECT [12] { + IDENT [13] { + name: @r0 + }.single_int64 + } + } + } + } + loop_condition: { + CONSTANT [14] { value: false } + } + loop_step: { + IDENT [15] { + name: @r1 + } + } + result: { + CALL [16] { + function: _+_ + args: { + CALL [17] { + function: _+_ + args: { + IDENT [18] { + name: @r1 + } + CALL [19] { + function: pure_custom_func + args: { + SELECT [20] { + IDENT [21] { + name: @r0 + }.single_int32 + } + } + } + } + } + IDENT [22] { + name: @r1 + } + } + } + } + } + } + } + CALL [23] { + function: pure_custom_func + args: { + SELECT [24] { + IDENT [25] { + name: msg + }.single_int64 + } + } + } + } +} diff --git a/optimizer/src/test/resources/subexpression_unparsed.baseline b/optimizer/src/test/resources/subexpression_unparsed.baseline index 73e3507fc..f820ae1e8 100644 --- a/optimizer/src/test/resources/subexpression_unparsed.baseline +++ b/optimizer/src/test/resources/subexpression_unparsed.baseline @@ -621,3 +621,35 @@ Result: true [BLOCK_RECURSION_DEPTH_7]: cel.@block(["w" + "o" + "r" + "l" + "d", "h" + "e" + "l" + "l" + "o" + " world"], @index1.matches(@index0)) [BLOCK_RECURSION_DEPTH_8]: cel.@block(["w" + "o" + "r" + "l" + "d", "h" + "e" + "l" + "l" + "o" + " world"], @index1.matches(@index0)) [BLOCK_RECURSION_DEPTH_9]: cel.@block(["w" + "o" + "r" + "l" + "d", "h" + "e" + "l" + "l" + "o" + " world"], @index1.matches(@index0)) + +Test case: CUSTOM_FUNCTION_INELIMINABLE +Source: non_pure_custom_func(msg.oneof_type.payload.single_int64) + non_pure_custom_func(msg.oneof_type.payload.single_int32) + non_pure_custom_func(msg.oneof_type.payload.single_int64) + non_pure_custom_func(msg.single_int64) +=====> +Result: 31 +[CASCADED_BINDS]: cel.bind(@r0, msg.oneof_type.payload, cel.bind(@r1, @r0.single_int64, non_pure_custom_func(@r1) + non_pure_custom_func(@r0.single_int32) + non_pure_custom_func(@r1))) + non_pure_custom_func(msg.single_int64) +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.oneof_type.payload, @index0.single_int64], non_pure_custom_func(@index1) + non_pure_custom_func(@index0.single_int32) + non_pure_custom_func(@index1) + non_pure_custom_func(msg.single_int64)) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, msg.single_int64, @index1.single_int32], non_pure_custom_func(@index2) + non_pure_custom_func(@index4) + non_pure_custom_func(@index2) + non_pure_custom_func(@index3)) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, msg.single_int64, @index1.single_int32], non_pure_custom_func(@index2) + non_pure_custom_func(@index4) + non_pure_custom_func(@index2) + non_pure_custom_func(@index3)) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, msg.single_int64, @index1.single_int32], non_pure_custom_func(@index2) + non_pure_custom_func(@index4) + non_pure_custom_func(@index2) + non_pure_custom_func(@index3)) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, msg.single_int64, @index1.single_int32], non_pure_custom_func(@index2) + non_pure_custom_func(@index4) + non_pure_custom_func(@index2) + non_pure_custom_func(@index3)) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, msg.single_int64, @index1.single_int32], non_pure_custom_func(@index2) + non_pure_custom_func(@index4) + non_pure_custom_func(@index2) + non_pure_custom_func(@index3)) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, msg.single_int64, @index1.single_int32], non_pure_custom_func(@index2) + non_pure_custom_func(@index4) + non_pure_custom_func(@index2) + non_pure_custom_func(@index3)) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, msg.single_int64, @index1.single_int32], non_pure_custom_func(@index2) + non_pure_custom_func(@index4) + non_pure_custom_func(@index2) + non_pure_custom_func(@index3)) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, msg.single_int64, @index1.single_int32], non_pure_custom_func(@index2) + non_pure_custom_func(@index4) + non_pure_custom_func(@index2) + non_pure_custom_func(@index3)) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, msg.single_int64, @index1.single_int32], non_pure_custom_func(@index2) + non_pure_custom_func(@index4) + non_pure_custom_func(@index2) + non_pure_custom_func(@index3)) + +Test case: CUSTOM_FUNCTION_ELIMINABLE +Source: pure_custom_func(msg.oneof_type.payload.single_int64) + pure_custom_func(msg.oneof_type.payload.single_int32) + pure_custom_func(msg.oneof_type.payload.single_int64) + pure_custom_func(msg.single_int64) +=====> +Result: 31 +[CASCADED_BINDS]: cel.bind(@r0, msg.oneof_type.payload, cel.bind(@r1, pure_custom_func(@r0.single_int64), @r1 + pure_custom_func(@r0.single_int32) + @r1)) + pure_custom_func(msg.single_int64) +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.oneof_type.payload, pure_custom_func(@index0.single_int64)], @index1 + pure_custom_func(@index0.single_int32) + @index1 + pure_custom_func(msg.single_int64)) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, pure_custom_func(@index2), msg.single_int64, pure_custom_func(@index4), @index1.single_int32, pure_custom_func(@index6), @index3 + @index7, @index8 + @index3], @index9 + @index5) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, pure_custom_func(@index2), pure_custom_func(msg.single_int64), pure_custom_func(@index1.single_int32), @index3 + @index5 + @index3], @index6 + @index4) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, pure_custom_func(@index2), pure_custom_func(msg.single_int64), @index3 + pure_custom_func(@index1.single_int32), @index5 + @index3], @index6 + @index4) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, pure_custom_func(@index2), pure_custom_func(msg.single_int64), @index3 + pure_custom_func(@index1.single_int32) + @index3], @index5 + @index4) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, pure_custom_func(@index2), pure_custom_func(msg.single_int64), @index3 + pure_custom_func(@index1.single_int32) + @index3], @index5 + @index4) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, pure_custom_func(@index2), pure_custom_func(msg.single_int64), @index3 + pure_custom_func(@index1.single_int32) + @index3], @index5 + @index4) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, pure_custom_func(@index2), pure_custom_func(msg.single_int64), @index3 + pure_custom_func(@index1.single_int32) + @index3], @index5 + @index4) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, pure_custom_func(@index2), pure_custom_func(msg.single_int64), @index3 + pure_custom_func(@index1.single_int32) + @index3], @index5 + @index4) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, pure_custom_func(@index2), pure_custom_func(msg.single_int64), @index3 + pure_custom_func(@index1.single_int32) + @index3], @index5 + @index4) From cebfd9d863f5fca9ab30f41ff300e1735d3e3f1a Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Tue, 27 Feb 2024 14:48:06 -0800 Subject: [PATCH 043/486] Prepare 0.3.1 release --- README.md | 2 +- publish/cel_version.bzl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c317e960e..f721f8dfc 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ CEL-Java is available in Maven Central Repository. [Download the JARs here][8] o dev.cel cel - 0.3.0 + 0.3.1 ``` diff --git a/publish/cel_version.bzl b/publish/cel_version.bzl index b918db871..3176b284c 100644 --- a/publish/cel_version.bzl +++ b/publish/cel_version.bzl @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. """Maven artifact version for CEL.""" -CEL_VERSION = "0.3.0" +CEL_VERSION = "0.3.1" From 776f95a3f527cf471256291f7f47dd338cce21b8 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Wed, 28 Feb 2024 11:23:14 -0800 Subject: [PATCH 044/486] Properly honor enableStandardEnvironment flag when constructing runtime Fixes https://github.com/google/cel-java/issues/255 PiperOrigin-RevId: 611167529 --- .../dev/cel/runtime/CelRuntimeLegacyImpl.java | 8 ++-- .../dev/cel/runtime/DefaultDispatcher.java | 40 ++++++++++--------- .../java/dev/cel/runtime/CelRuntimeTest.java | 16 ++++++++ 3 files changed, 41 insertions(+), 23 deletions(-) diff --git a/runtime/src/main/java/dev/cel/runtime/CelRuntimeLegacyImpl.java b/runtime/src/main/java/dev/cel/runtime/CelRuntimeLegacyImpl.java index 19059506a..9ef60304f 100644 --- a/runtime/src/main/java/dev/cel/runtime/CelRuntimeLegacyImpl.java +++ b/runtime/src/main/java/dev/cel/runtime/CelRuntimeLegacyImpl.java @@ -227,10 +227,8 @@ public CelRuntimeLegacyImpl build() { DynamicProto dynamicProto = DynamicProto.create(runtimeTypeFactory); - DefaultDispatcher dispatcher = DefaultDispatcher.create(options, dynamicProto); - if (standardEnvironmentEnabled) { - StandardFunctions.add(dispatcher, dynamicProto, options); - } + DefaultDispatcher dispatcher = + DefaultDispatcher.create(options, dynamicProto, standardEnvironmentEnabled); ImmutableMap functionBindingMap = ImmutableMap.copyOf(functionBindings); @@ -306,6 +304,8 @@ private Builder(Builder builder) { this.options = builder.options; this.extensionRegistry = builder.extensionRegistry; this.customTypeFactory = builder.customTypeFactory; + this.standardEnvironmentEnabled = builder.standardEnvironmentEnabled; + this.celValueProvider = builder.celValueProvider; // The following needs to be deep copied as they are collection builders this.fileTypes = deepCopy(builder.fileTypes); this.celRuntimeLibraries = deepCopy(builder.celRuntimeLibraries); diff --git a/runtime/src/main/java/dev/cel/runtime/DefaultDispatcher.java b/runtime/src/main/java/dev/cel/runtime/DefaultDispatcher.java index 09f70c52a..cfc16bee7 100644 --- a/runtime/src/main/java/dev/cel/runtime/DefaultDispatcher.java +++ b/runtime/src/main/java/dev/cel/runtime/DefaultDispatcher.java @@ -43,46 +43,46 @@ @ThreadSafe @Internal public final class DefaultDispatcher implements Dispatcher, Registrar { - @SuppressWarnings("unused") - private final CelOptions celOptions; - /** - * @deprecated use {@link DefaultDispatcher(CelOptions)} instead. + * Creates a new dispatcher with all standard functions. + * + * @deprecated Migrate to fluent APIs. See {@link CelRuntimeFactory}. */ @Deprecated - public DefaultDispatcher(ImmutableSet features) { - this(CelOptions.fromExprFeatures(features)); - } - - public DefaultDispatcher(CelOptions celOptions) { - this.celOptions = celOptions; + public static DefaultDispatcher create() { + return create(CelOptions.LEGACY); } /** * Creates a new dispatcher with all standard functions. * - * @deprecated use {@link #create(CelOptions)} instead. + * @deprecated Migrate to fluent APIs. See {@link CelRuntimeFactory}. */ @Deprecated public static DefaultDispatcher create(ImmutableSet features) { return create(CelOptions.fromExprFeatures(features)); } + /** + * Creates a new dispatcher with all standard functions. + * + * @deprecated Migrate to fluent APIs. See {@link CelRuntimeFactory}. + */ + @Deprecated public static DefaultDispatcher create(CelOptions celOptions) { DynamicProto dynamicProto = DynamicProto.create(DefaultMessageFactory.INSTANCE); - return create(celOptions, dynamicProto); + return create(celOptions, dynamicProto, true); } - public static DefaultDispatcher create(CelOptions celOptions, DynamicProto dynamicProto) { - DefaultDispatcher dispatcher = new DefaultDispatcher(celOptions); - StandardFunctions.add(dispatcher, dynamicProto, celOptions); + public static DefaultDispatcher create( + CelOptions celOptions, DynamicProto dynamicProto, boolean enableStandardEnvironment) { + DefaultDispatcher dispatcher = new DefaultDispatcher(); + if (enableStandardEnvironment) { + StandardFunctions.add(dispatcher, dynamicProto, celOptions); + } return dispatcher; } - public static DefaultDispatcher create() { - return create(CelOptions.LEGACY); - } - /** Internal representation of an overload. */ @Immutable private static final class Overload { @@ -237,4 +237,6 @@ public Dispatcher.ImmutableCopy immutableCopy() { return this; } } + + private DefaultDispatcher() {} } diff --git a/runtime/src/test/java/dev/cel/runtime/CelRuntimeTest.java b/runtime/src/test/java/dev/cel/runtime/CelRuntimeTest.java index 61794aea0..72038992e 100644 --- a/runtime/src/test/java/dev/cel/runtime/CelRuntimeTest.java +++ b/runtime/src/test/java/dev/cel/runtime/CelRuntimeTest.java @@ -15,6 +15,7 @@ package dev.cel.runtime; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertThrows; import com.google.api.expr.v1alpha1.Constant; import com.google.api.expr.v1alpha1.Expr; @@ -398,4 +399,19 @@ public void trace_withVariableResolver() throws Exception { assertThat(result).isEqualTo("hello"); } + + @Test + public void standardEnvironmentDisabledForRuntime_throws() throws Exception { + CelCompiler celCompiler = + CelCompilerFactory.standardCelCompilerBuilder().setStandardEnvironmentEnabled(true).build(); + CelRuntime celRuntime = + CelRuntimeFactory.standardCelRuntimeBuilder().setStandardEnvironmentEnabled(false).build(); + CelAbstractSyntaxTree ast = celCompiler.compile("size('hello')").getAst(); + + CelEvaluationException e = + assertThrows(CelEvaluationException.class, () -> celRuntime.createProgram(ast).eval()); + assertThat(e) + .hasMessageThat() + .contains("Unknown overload id 'size_string' for function 'size'"); + } } From 73d29cf6e87cfd303adaa51e4517d3b98cabd712 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Wed, 28 Feb 2024 13:51:04 -0800 Subject: [PATCH 045/486] Fix replacing namespaced identifiers for accu_init PiperOrigin-RevId: 611217621 --- .../java/dev/cel/checker/ExprChecker.java | 33 ++++++++++++------- .../extensions/CelBindingsExtensionsTest.java | 10 ++++-- 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/checker/src/main/java/dev/cel/checker/ExprChecker.java b/checker/src/main/java/dev/cel/checker/ExprChecker.java index 5c0c21ffd..2506466ce 100644 --- a/checker/src/main/java/dev/cel/checker/ExprChecker.java +++ b/checker/src/main/java/dev/cel/checker/ExprChecker.java @@ -487,11 +487,8 @@ private CelExpr visit(CelExpr expr, CelExpr.CelCreateList createList) { @CheckReturnValue private CelExpr visit(CelExpr expr, CelExpr.CelComprehension compre) { CelExpr visitedRange = visit(compre.iterRange()); - if (namespacedDeclarations && !visitedRange.equals(compre.iterRange())) { - expr = replaceComprehensionRangeSubtree(expr, visitedRange); - } - CelExpr init = visit(compre.accuInit()); - CelType accuType = env.getType(init); + CelExpr visitedInit = visit(compre.accuInit()); + CelType accuType = env.getType(visitedInit); CelType rangeType = inferenceContext.specialize(env.getType(visitedRange)); CelType varType; switch (rangeType.kind()) { @@ -533,17 +530,25 @@ private CelExpr visit(CelExpr expr, CelExpr.CelComprehension compre) { CelExpr condition = visit(compre.loopCondition()); assertType(condition, SimpleType.BOOL); CelExpr visitedStep = visit(compre.loopStep()); - if (namespacedDeclarations && !visitedStep.equals(compre.loopStep())) { - expr = replaceComprehensionStepSubtree(expr, visitedStep); - } assertType(visitedStep, accuType); // Forget iteration variable, as result expression must only depend on accu. env.exitScope(); CelExpr visitedResult = visit(compre.result()); - if (namespacedDeclarations && !visitedResult.equals(compre.result())) { - expr = replaceComprehensionResultSubtree(expr, visitedResult); - } env.exitScope(); + if (namespacedDeclarations) { + if (!visitedRange.equals(compre.iterRange())) { + expr = replaceComprehensionRangeSubtree(expr, visitedRange); + } + if (!visitedInit.equals(compre.accuInit())) { + expr = replaceComprehensionAccuInitSubtree(expr, visitedInit); + } + if (!visitedStep.equals(compre.loopStep())) { + expr = replaceComprehensionStepSubtree(expr, visitedStep); + } + if (!visitedResult.equals(compre.result())) { + expr = replaceComprehensionResultSubtree(expr, visitedResult); + } + } env.setType(expr, inferenceContext.specialize(env.getType(visitedResult))); return expr; } @@ -872,6 +877,12 @@ private static CelExpr replaceMapEntryValueSubtree(CelExpr expr, CelExpr newValu return expr.toBuilder().setCreateMap(createMap).build(); } + private static CelExpr replaceComprehensionAccuInitSubtree(CelExpr expr, CelExpr newAccuInit) { + CelExpr.CelComprehension newComprehension = + expr.comprehension().toBuilder().setAccuInit(newAccuInit).build(); + return expr.toBuilder().setComprehension(newComprehension).build(); + } + private static CelExpr replaceComprehensionRangeSubtree(CelExpr expr, CelExpr newRange) { CelExpr.CelComprehension newComprehension = expr.comprehension().toBuilder().setIterRange(newRange).build(); diff --git a/extensions/src/test/java/dev/cel/extensions/CelBindingsExtensionsTest.java b/extensions/src/test/java/dev/cel/extensions/CelBindingsExtensionsTest.java index 218435d98..1eba6e22c 100644 --- a/extensions/src/test/java/dev/cel/extensions/CelBindingsExtensionsTest.java +++ b/extensions/src/test/java/dev/cel/extensions/CelBindingsExtensionsTest.java @@ -46,10 +46,13 @@ public final class CelBindingsExtensionsTest { private static final CelCompiler COMPILER = CelCompilerFactory.standardCelCompilerBuilder() .setStandardMacros(CelStandardMacro.STANDARD_MACROS) - .addLibraries(CelExtensions.bindings()) + .addLibraries(CelOptionalLibrary.INSTANCE, CelExtensions.bindings()) .build(); - private static final CelRuntime RUNTIME = CelRuntimeFactory.standardCelRuntimeBuilder().build(); + private static final CelRuntime RUNTIME = + CelRuntimeFactory.standardCelRuntimeBuilder() + .addLibraries(CelOptionalLibrary.INSTANCE) + .build(); private enum BindingTestCase { BOOL_LITERAL("cel.bind(t, true, t)"), @@ -63,7 +66,8 @@ private enum BindingTestCase { BIND_WITH_EXISTS_TRUE( "cel.bind(valid_elems, [1, 2, 3], [3, 4, 5].exists(e, e in valid_elems))"), BIND_WITH_EXISTS_FALSE("cel.bind(valid_elems, [1, 2, 3], ![4, 5].exists(e, e in valid_elems))"), - BIND_WITH_MAP("[1,2,3].map(x, cel.bind(y, x + x, [y, y])) == [[2, 2], [4, 4], [6, 6]]"); + BIND_WITH_MAP("[1,2,3].map(x, cel.bind(y, x + x, [y, y])) == [[2, 2], [4, 4], [6, 6]]"), + BIND_OPTIONAL_LIST("cel.bind(r0, optional.none(), [?r0, ?r0]) == []"); private final String source; From b302caa88fb46231f0ca5828350f09358f33b2da Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Wed, 28 Feb 2024 15:15:51 -0800 Subject: [PATCH 046/486] Assert correctness on AST ran through SubexpressionOptimizer PiperOrigin-RevId: 611245287 --- .../optimizers/SubexpressionOptimizer.java | 80 ++++++++++++++++++- .../SubexpressionOptimizerTest.java | 68 ++++++++++++++++ 2 files changed, 145 insertions(+), 3 deletions(-) diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java index a8e431ab9..b55f4614a 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java @@ -22,6 +22,7 @@ import com.google.auto.value.AutoValue; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; +import com.google.common.base.Verify; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; @@ -39,6 +40,7 @@ import dev.cel.common.CelValidationException; import dev.cel.common.CelVarDecl; import dev.cel.common.ast.CelExpr; +import dev.cel.common.ast.CelExpr.CelCall; import dev.cel.common.ast.CelExpr.CelIdent; import dev.cel.common.ast.CelExpr.ExprKind.Kind; import dev.cel.common.navigation.CelNavigableAst; @@ -125,9 +127,14 @@ public static SubexpressionOptimizer newInstance(SubexpressionOptimizerOptions c @Override public CelAbstractSyntaxTree optimize(CelNavigableAst navigableAst, CelBuilder celBuilder) { - return cseOptions.enableCelBlock() - ? optimizeUsingCelBlock(navigableAst, celBuilder) - : optimizeUsingCelBind(navigableAst); + CelAbstractSyntaxTree ast = + cseOptions.enableCelBlock() + ? optimizeUsingCelBlock(navigableAst, celBuilder) + : optimizeUsingCelBind(navigableAst); + + verifyOptimizedAstCorrectness(ast); + + return ast; } private CelAbstractSyntaxTree optimizeUsingCelBlock( @@ -239,6 +246,73 @@ private CelAbstractSyntaxTree optimizeUsingCelBlock( return tagAstExtension(astToModify); } + /** + * Asserts that the optimized AST has no correctness issues. + * + * @throws com.google.common.base.VerifyException if the optimized AST is malformed. + */ + @VisibleForTesting + static void verifyOptimizedAstCorrectness(CelAbstractSyntaxTree ast) { + CelNavigableAst celNavigableAst = CelNavigableAst.fromAst(ast); + + ImmutableList allCelBlocks = + celNavigableAst + .getRoot() + .allNodes() + .map(CelNavigableExpr::expr) + .filter(expr -> expr.callOrDefault().function().equals(CEL_BLOCK_FUNCTION)) + .collect(toImmutableList()); + if (allCelBlocks.isEmpty()) { + return; + } + + CelExpr celBlockExpr = allCelBlocks.get(0); + Verify.verify( + allCelBlocks.size() == 1, + "Expected 1 cel.block function to be present but found %s", + allCelBlocks.size()); + Verify.verify( + celNavigableAst.getRoot().expr().equals(celBlockExpr), + "Expected cel.block to be present at root"); + + // Assert correctness on block indices used in subexpressions + CelCall celBlockCall = celBlockExpr.call(); + ImmutableList subexprs = celBlockCall.args().get(0).createList().elements(); + for (int i = 0; i < subexprs.size(); i++) { + verifyBlockIndex(subexprs.get(i), i); + } + + // Assert correctness on block indices used in block result + CelExpr blockResult = celBlockCall.args().get(1); + verifyBlockIndex(blockResult, subexprs.size()); + boolean resultHasAtLeastOneBlockIndex = + CelNavigableExpr.fromExpr(blockResult) + .allNodes() + .map(CelNavigableExpr::expr) + .anyMatch(expr -> expr.identOrDefault().name().startsWith(BLOCK_INDEX_PREFIX)); + Verify.verify( + resultHasAtLeastOneBlockIndex, + "Expected at least one reference of index in cel.block result"); + } + + private static void verifyBlockIndex(CelExpr celExpr, int maxIndexValue) { + boolean areAllIndicesValid = + CelNavigableExpr.fromExpr(celExpr) + .allNodes() + .map(CelNavigableExpr::expr) + .filter(expr -> expr.identOrDefault().name().startsWith(BLOCK_INDEX_PREFIX)) + .map(CelExpr::ident) + .allMatch( + blockIdent -> + Integer.parseInt(blockIdent.name().substring(BLOCK_INDEX_PREFIX.length())) + < maxIndexValue); + Verify.verify( + areAllIndicesValid, + "Illegal block index found. The index value must be less than %s. Expr: %s", + maxIndexValue, + celExpr); + } + private static CelAbstractSyntaxTree tagAstExtension(CelAbstractSyntaxTree ast) { // Tag the extension CelSource.Builder celSourceBuilder = diff --git a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java index 3668d776e..a67bb5258 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java @@ -18,6 +18,7 @@ import static dev.cel.common.CelOverloadDecl.newGlobalOverload; import static org.junit.Assert.assertThrows; +import com.google.common.base.VerifyException; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.testing.junit.testparameterinjector.TestParameter; @@ -481,6 +482,73 @@ public void blockIndex_invalidArgument_throws() { assertThat(e).hasMessageThat().contains("undeclared reference"); } + @Test + public void verifyOptimizedAstCorrectness_twoCelBlocks_throws() throws Exception { + CelAbstractSyntaxTree ast = + compileUsingInternalFunctions("cel.block([1, 2], cel.block([2], 3))"); + + VerifyException e = + assertThrows( + VerifyException.class, () -> SubexpressionOptimizer.verifyOptimizedAstCorrectness(ast)); + assertThat(e) + .hasMessageThat() + .isEqualTo("Expected 1 cel.block function to be present but found 2"); + } + + @Test + public void verifyOptimizedAstCorrectness_celBlockNotAtRoot_throws() throws Exception { + CelAbstractSyntaxTree ast = compileUsingInternalFunctions("1 + cel.block([1, 2], index0)"); + + VerifyException e = + assertThrows( + VerifyException.class, () -> SubexpressionOptimizer.verifyOptimizedAstCorrectness(ast)); + assertThat(e).hasMessageThat().isEqualTo("Expected cel.block to be present at root"); + } + + @Test + public void verifyOptimizedAstCorrectness_blockContainsNoIndexResult_throws() throws Exception { + CelAbstractSyntaxTree ast = compileUsingInternalFunctions("cel.block([1, index0], 2)"); + + VerifyException e = + assertThrows( + VerifyException.class, () -> SubexpressionOptimizer.verifyOptimizedAstCorrectness(ast)); + assertThat(e) + .hasMessageThat() + .isEqualTo("Expected at least one reference of index in cel.block result"); + } + + @Test + @TestParameters("{source: 'cel.block([], index0)'}") + @TestParameters("{source: 'cel.block([1, 2], index2)'}") + public void verifyOptimizedAstCorrectness_indexOutOfBounds_throws(String source) + throws Exception { + CelAbstractSyntaxTree ast = compileUsingInternalFunctions(source); + + VerifyException e = + assertThrows( + VerifyException.class, () -> SubexpressionOptimizer.verifyOptimizedAstCorrectness(ast)); + assertThat(e) + .hasMessageThat() + .contains("Illegal block index found. The index value must be less than"); + } + + @Test + @TestParameters("{source: 'cel.block([index0], index0)'}") + @TestParameters("{source: 'cel.block([1, index1, 2], index2)'}") + @TestParameters("{source: 'cel.block([1, 2, index2], index2)'}") + @TestParameters("{source: 'cel.block([index2, 1, 2], index2)'}") + public void verifyOptimizedAstCorrectness_indexIsNotForwardReferencing_throws(String source) + throws Exception { + CelAbstractSyntaxTree ast = compileUsingInternalFunctions(source); + + VerifyException e = + assertThrows( + VerifyException.class, () -> SubexpressionOptimizer.verifyOptimizedAstCorrectness(ast)); + assertThat(e) + .hasMessageThat() + .contains("Illegal block index found. The index value must be less than"); + } + /** * Converts AST containing cel.block related test functions to internal functions (e.g: cel.block * -> cel.@block) From 178e9a80d67069ac5deb0b0e12f5670d640a8594 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Wed, 28 Feb 2024 17:35:06 -0800 Subject: [PATCH 047/486] Fix optional list/map indexing with unknowns. Fix optional map indexing via field selection. PiperOrigin-RevId: 611285327 --- .../java/dev/cel/checker/ExprChecker.java | 2 +- .../test/java/dev/cel/extensions/BUILD.bazel | 1 + .../extensions/CelOptionalLibraryTest.java | 47 +++++++++++++++++++ .../dev/cel/runtime/DefaultInterpreter.java | 4 +- 4 files changed, 51 insertions(+), 3 deletions(-) diff --git a/checker/src/main/java/dev/cel/checker/ExprChecker.java b/checker/src/main/java/dev/cel/checker/ExprChecker.java index 2506466ce..cbebcd238 100644 --- a/checker/src/main/java/dev/cel/checker/ExprChecker.java +++ b/checker/src/main/java/dev/cel/checker/ExprChecker.java @@ -705,7 +705,7 @@ private CelExpr visitOptionalCall(CelExpr expr, CelExpr.CelCall call) { CelExpr visitedOperand = visit(operand); if (namespacedDeclarations && !operand.equals(visitedOperand)) { // Subtree has been rewritten. Replace the operand. - expr = replaceSelectOperandSubtree(expr, visitedOperand); + expr = replaceCallArgumentSubtree(expr, visitedOperand, 0); } CelType resultType = visitSelectField(expr, operand, field.constant().stringValue(), true); env.setType(expr, resultType); diff --git a/extensions/src/test/java/dev/cel/extensions/BUILD.bazel b/extensions/src/test/java/dev/cel/extensions/BUILD.bazel index c71df2d8a..7f572f58f 100644 --- a/extensions/src/test/java/dev/cel/extensions/BUILD.bazel +++ b/extensions/src/test/java/dev/cel/extensions/BUILD.bazel @@ -26,6 +26,7 @@ java_library( "//extensions:strings", "//parser:macro", "//runtime", + "//runtime:interpreter_util", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_protobuf_protobuf_java_util", diff --git a/extensions/src/test/java/dev/cel/extensions/CelOptionalLibraryTest.java b/extensions/src/test/java/dev/cel/extensions/CelOptionalLibraryTest.java index 8cb7a11f7..31df7a325 100644 --- a/extensions/src/test/java/dev/cel/extensions/CelOptionalLibraryTest.java +++ b/extensions/src/test/java/dev/cel/extensions/CelOptionalLibraryTest.java @@ -46,6 +46,7 @@ import dev.cel.runtime.CelEvaluationException; import dev.cel.runtime.CelRuntime; import dev.cel.runtime.CelRuntime.CelFunctionBinding; +import dev.cel.runtime.InterpreterUtil; import dev.cel.testing.testdata.proto2.TestAllTypesProto.TestAllTypes; import dev.cel.testing.testdata.proto2.TestAllTypesProto.TestAllTypes.NestedMessage; import java.util.List; @@ -766,6 +767,38 @@ public void optionalIndex_onMap_returnsOptionalValue() throws Exception { assertThat(result).isEqualTo(Optional.of("goodbye")); } + @Test + @TestParameters("{source: '{?x: optional.of(1)}'}") + @TestParameters("{source: '{?1: x}'}") + @TestParameters("{source: '{?x: x}'}") + public void optionalIndex_onMapWithUnknownInput_returnsUnknownResult(String source) + throws Exception { + Cel cel = newCelBuilder().addVar("x", OptionalType.create(SimpleType.INT)).build(); + CelAbstractSyntaxTree ast = cel.compile(source).getAst(); + + Object result = cel.createProgram(ast).eval(); + + assertThat(InterpreterUtil.isUnknown(result)).isTrue(); + } + + @Test + public void optionalIndex_onOptionalMapUsingFieldSelection_returnsOptionalValue() + throws Exception { + Cel cel = + newCelBuilder() + .addVar( + "m", + MapType.create( + SimpleType.STRING, MapType.create(SimpleType.STRING, SimpleType.STRING))) + .setResultType(OptionalType.create(SimpleType.STRING)) + .build(); + CelAbstractSyntaxTree ast = cel.compile("{?'key': optional.of('test')}.?key").getAst(); + + Object result = cel.createProgram(ast).eval(); + + assertThat(result).isEqualTo(Optional.of("test")); + } + @Test public void optionalIndex_onList_returnsOptionalEmpty() throws Exception { Cel cel = @@ -824,6 +857,20 @@ public void optionalIndex_onOptionalList_returnsOptionalValue() throws Exception assertThat(result).isEqualTo(Optional.of("hello")); } + @Test + public void optionalIndex_onListWithUnknownInput_returnsUnknownResult() throws Exception { + Cel cel = + newCelBuilder() + .addVar("x", OptionalType.create(SimpleType.INT)) + .setResultType(ListType.create(SimpleType.INT)) + .build(); + CelAbstractSyntaxTree ast = cel.compile("[?x]").getAst(); + + Object result = cel.createProgram(ast).eval(); + + assertThat(InterpreterUtil.isUnknown(result)).isTrue(); + } + @Test public void traditionalIndex_onOptionalList_returnsOptionalEmpty() throws Exception { Cel cel = diff --git a/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java b/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java index 3c4c0003a..bf6af55ee 100644 --- a/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java +++ b/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java @@ -672,7 +672,7 @@ private IntermediateResult evalList( argChecker.checkArg(evaluatedElement); Object value = evaluatedElement.value(); - if (optionalIndicesSet.contains(i)) { + if (optionalIndicesSet.contains(i) && !isUnknownValue(value)) { Optional optionalVal = (Optional) value; if (!optionalVal.isPresent()) { continue; @@ -712,7 +712,7 @@ private IntermediateResult evalMap(ExecutionFrame frame, CelCreateMap mapExpr) } Object value = valueResult.value(); - if (entry.optionalEntry()) { + if (entry.optionalEntry() && !isUnknownValue(value)) { Optional optionalVal = (Optional) value; if (!optionalVal.isPresent()) { // This is a no-op currently but will be semantically correct when extended proto From 8ca4ed4c6534fdcaab0afd096d2750f117e8c1c2 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Wed, 28 Feb 2024 17:54:07 -0800 Subject: [PATCH 048/486] Collect newly added declarations into OptimizationResult PiperOrigin-RevId: 611289279 --- .../main/java/dev/cel/optimizer/BUILD.bazel | 3 + .../dev/cel/optimizer/CelAstOptimizer.java | 39 ++++++++++- .../dev/cel/optimizer/CelOptimizerImpl.java | 16 +++-- .../optimizers/ConstantFoldingOptimizer.java | 6 +- .../optimizers/SubexpressionOptimizer.java | 66 +++++++++++-------- .../test/java/dev/cel/optimizer/BUILD.bazel | 1 + .../cel/optimizer/CelOptimizerImplTest.java | 15 +++-- 7 files changed, 102 insertions(+), 44 deletions(-) diff --git a/optimizer/src/main/java/dev/cel/optimizer/BUILD.bazel b/optimizer/src/main/java/dev/cel/optimizer/BUILD.bazel index c86b4559b..b4a674cb3 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/BUILD.bazel +++ b/optimizer/src/main/java/dev/cel/optimizer/BUILD.bazel @@ -67,9 +67,12 @@ java_library( ], deps = [ ":optimization_exception", + "//:auto_value", "//bundle:cel", "//common", + "//common:compiler_common", "//common/navigation", + "@maven//:com_google_guava_guava", ], ) diff --git a/optimizer/src/main/java/dev/cel/optimizer/CelAstOptimizer.java b/optimizer/src/main/java/dev/cel/optimizer/CelAstOptimizer.java index 730b5cc3c..0d2edc4b5 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/CelAstOptimizer.java +++ b/optimizer/src/main/java/dev/cel/optimizer/CelAstOptimizer.java @@ -14,14 +14,49 @@ package dev.cel.optimizer; -import dev.cel.bundle.CelBuilder; +import com.google.auto.value.AutoValue; +import com.google.common.collect.ImmutableList; +import dev.cel.bundle.Cel; import dev.cel.common.CelAbstractSyntaxTree; +import dev.cel.common.CelFunctionDecl; +import dev.cel.common.CelVarDecl; 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, CelBuilder cel) + OptimizationResult optimize(CelNavigableAst navigableAst, Cel cel) throws CelOptimizationException; + + /** + * Denotes the result of a single optimization pass on an AST. + * + *

The optimizer may optionally populate new variable and function declarations generated as + * part of optimizing an AST. + */ + @AutoValue + abstract class OptimizationResult { + public abstract CelAbstractSyntaxTree optimizedAst(); + + public abstract ImmutableList newVarDecls(); + + public abstract ImmutableList newFunctionDecls(); + + /** + * Create an optimization result with new declarations. The optimizer must populate these + * declarations after an optimization pass if they are required for type-checking to success. + */ + public static OptimizationResult create( + CelAbstractSyntaxTree optimizedAst, + ImmutableList newVarDecls, + ImmutableList newFunctionDecls) { + return new AutoValue_CelAstOptimizer_OptimizationResult( + optimizedAst, newVarDecls, newFunctionDecls); + } + + public static OptimizationResult create(CelAbstractSyntaxTree optimizedAst) { + return create(optimizedAst, ImmutableList.of(), ImmutableList.of()); + } + } } diff --git a/optimizer/src/main/java/dev/cel/optimizer/CelOptimizerImpl.java b/optimizer/src/main/java/dev/cel/optimizer/CelOptimizerImpl.java index d57181fc2..136788d83 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/CelOptimizerImpl.java +++ b/optimizer/src/main/java/dev/cel/optimizer/CelOptimizerImpl.java @@ -18,10 +18,10 @@ import com.google.common.collect.ImmutableSet; import dev.cel.bundle.Cel; -import dev.cel.bundle.CelBuilder; import dev.cel.common.CelAbstractSyntaxTree; import dev.cel.common.CelValidationException; import dev.cel.common.navigation.CelNavigableAst; +import dev.cel.optimizer.CelAstOptimizer.OptimizationResult; import java.util.Arrays; final class CelOptimizerImpl implements CelOptimizer { @@ -39,13 +39,21 @@ public CelAbstractSyntaxTree optimize(CelAbstractSyntaxTree ast) throws CelOptim throw new IllegalArgumentException("AST must be type-checked."); } + Cel celOptimizerEnv = cel; CelAbstractSyntaxTree optimizedAst = ast; - CelBuilder celBuilder = cel.toCelBuilder(); try { for (CelAstOptimizer optimizer : astOptimizers) { CelNavigableAst navigableAst = CelNavigableAst.fromAst(optimizedAst); - optimizedAst = optimizer.optimize(navigableAst, celBuilder); - optimizedAst = celBuilder.build().check(optimizedAst).getAst(); + OptimizationResult result = optimizer.optimize(navigableAst, celOptimizerEnv); + if (!result.newFunctionDecls().isEmpty() || !result.newVarDecls().isEmpty()) { + celOptimizerEnv = + celOptimizerEnv + .toCelBuilder() + .addVarDeclarations(result.newVarDecls()) + .addFunctionDeclarations(result.newFunctionDecls()) + .build(); + } + optimizedAst = celOptimizerEnv.check(result.optimizedAst()).getAst(); } } catch (CelValidationException e) { throw new CelOptimizationException( diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java b/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java index 6766ae3c4..716cdafc6 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java @@ -19,7 +19,6 @@ import com.google.auto.value.AutoValue; import com.google.common.collect.ImmutableList; import dev.cel.bundle.Cel; -import dev.cel.bundle.CelBuilder; import dev.cel.common.CelAbstractSyntaxTree; import dev.cel.common.CelValidationException; import dev.cel.common.ast.CelConstant; @@ -77,9 +76,8 @@ public static ConstantFoldingOptimizer newInstance( private final MutableAst mutableAst; @Override - public CelAbstractSyntaxTree optimize(CelNavigableAst navigableAst, CelBuilder celBuilder) + public OptimizationResult optimize(CelNavigableAst navigableAst, Cel cel) throws CelOptimizationException { - Cel cel = celBuilder.build(); Set visitedExprs = new HashSet<>(); int iterCount = 0; while (true) { @@ -120,7 +118,7 @@ public CelAbstractSyntaxTree optimize(CelNavigableAst navigableAst, CelBuilder c // If the output is a list, map, or struct which contains optional entries, then prune it // to make sure that the optionals, if resolved, do not surface in the output literal. CelAbstractSyntaxTree newAst = pruneOptionalElements(navigableAst); - return mutableAst.renumberIdsConsecutively(newAst); + return OptimizationResult.create(mutableAst.renumberIdsConsecutively(newAst)); } private static boolean canFold(CelNavigableExpr navigableExpr) { diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java index b55f4614a..214785123 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java @@ -28,6 +28,7 @@ import com.google.common.collect.Iterables; import com.google.common.collect.Streams; import com.google.errorprone.annotations.CanIgnoreReturnValue; +import dev.cel.bundle.Cel; import dev.cel.bundle.CelBuilder; import dev.cel.checker.Standard; import dev.cel.common.CelAbstractSyntaxTree; @@ -126,22 +127,18 @@ public static SubexpressionOptimizer newInstance(SubexpressionOptimizerOptions c } @Override - public CelAbstractSyntaxTree optimize(CelNavigableAst navigableAst, CelBuilder celBuilder) { - CelAbstractSyntaxTree ast = + public OptimizationResult optimize(CelNavigableAst navigableAst, Cel cel) { + OptimizationResult result = cseOptions.enableCelBlock() - ? optimizeUsingCelBlock(navigableAst, celBuilder) + ? optimizeUsingCelBlock(navigableAst, cel) : optimizeUsingCelBind(navigableAst); - verifyOptimizedAstCorrectness(ast); + verifyOptimizedAstCorrectness(result.optimizedAst()); - return ast; + return result; } - private CelAbstractSyntaxTree optimizeUsingCelBlock( - CelNavigableAst navigableAst, CelBuilder celBuilder) { - // Retain the original expected result type, so that it can be reset in celBuilder at the end of - // the optimization pass. - CelType resultType = navigableAst.getAst().getResultType(); + private OptimizationResult optimizeUsingCelBlock(CelNavigableAst navigableAst, Cel cel) { MangledComprehensionAst mangledComprehensionAst = mutableAst.mangleComprehensionIdentifierNames( navigableAst.getAst(), @@ -209,9 +206,11 @@ private CelAbstractSyntaxTree optimizeUsingCelBlock( if (iterCount == 0) { // No modification has been made. - return astToModify; + return OptimizationResult.create(astToModify); } + ImmutableList.Builder newVarDecls = ImmutableList.builder(); + // Add all mangled comprehension identifiers to the environment, so that the subexpressions can // retain context to them. mangledComprehensionAst @@ -221,29 +220,31 @@ private CelAbstractSyntaxTree optimizeUsingCelBlock( type.iterVarType() .ifPresent( iterVarType -> - celBuilder.addVarDeclarations( + newVarDecls.add( CelVarDecl.newVarDeclaration(name.iterVarName(), iterVarType))); type.resultType() .ifPresent( comprehensionResultType -> - celBuilder.addVarDeclarations( + newVarDecls.add( CelVarDecl.newVarDeclaration( name.resultName(), comprehensionResultType))); }); - // Type-check all sub-expressions then add them as block identifiers to the CEL environment - addBlockIdentsToEnv(celBuilder, subexpressions); + // Type-check all sub-expressions then create new block index identifiers. + newVarDecls.addAll(newBlockIndexVariableDeclarations(cel, newVarDecls.build(), subexpressions)); // Wrap the optimized expression in cel.block - celBuilder.addFunctionDeclarations(newCelBlockFunctionDecl(resultType)); astToModify = mutableAst.wrapAstWithNewCelBlock(CEL_BLOCK_FUNCTION, astToModify, subexpressions); astToModify = mutableAst.renumberIdsConsecutively(astToModify); - // Restore the expected result type the environment had prior to optimization. - celBuilder.setResultType(resultType); + // Tag the AST with cel.block designated as an extension + astToModify = tagAstExtension(astToModify); - return tagAstExtension(astToModify); + return OptimizationResult.create( + astToModify, + newVarDecls.build(), + ImmutableList.of(newCelBlockFunctionDecl(navigableAst.getAst().getResultType()))); } /** @@ -322,15 +323,20 @@ private static CelAbstractSyntaxTree tagAstExtension(CelAbstractSyntaxTree ast) } /** - * Adds all subexpression as numbered identifiers that acts as an indexer to cel.block - * (ex: @index0, @index1..) Each subexpressions are type-checked, then its result type is used as - * the new identifiers' types. + * Creates a list of numbered identifiers from the subexpressions that act as an indexer to + * cel.block (ex: @index0, @index1..). Each subexpressions are type-checked, then its result type + * is used as the new identifiers' types. */ - private static void addBlockIdentsToEnv(CelBuilder celBuilder, List subexpressions) { + private static ImmutableList newBlockIndexVariableDeclarations( + Cel cel, ImmutableList mangledVarDecls, List subexpressions) { // The resulting type of the subexpressions will likely be different from the // entire expression's expected result type. - celBuilder.setResultType(SimpleType.DYN); + CelBuilder celBuilder = cel.toCelBuilder().setResultType(SimpleType.DYN); + // Add the mangled comprehension variables to the environment for type-checking subexpressions + // to succeed + celBuilder.addVarDeclarations(mangledVarDecls); + ImmutableList.Builder varDeclBuilder = ImmutableList.builder(); for (int i = 0; i < subexpressions.size(); i++) { CelExpr subexpression = subexpressions.get(i); @@ -343,11 +349,15 @@ private static void addBlockIdentsToEnv(CelBuilder celBuilder, List sub throw new IllegalStateException("Failed to type-check subexpression", e); } - celBuilder.addVar("@index" + i, subAst.getResultType()); + CelVarDecl indexVar = CelVarDecl.newVarDeclaration("@index" + i, subAst.getResultType()); + celBuilder.addVarDeclarations(indexVar); + varDeclBuilder.add(indexVar); } + + return varDeclBuilder.build(); } - private CelAbstractSyntaxTree optimizeUsingCelBind(CelNavigableAst navigableAst) { + private OptimizationResult optimizeUsingCelBind(CelNavigableAst navigableAst) { CelAbstractSyntaxTree astToModify = mutableAst .mangleComprehensionIdentifierNames( @@ -423,12 +433,12 @@ private CelAbstractSyntaxTree optimizeUsingCelBind(CelNavigableAst navigableAst) if (iterCount == 0) { // No modification has been made. - return astToModify; + return OptimizationResult.create(astToModify); } astToModify = mutableAst.renumberIdsConsecutively(astToModify); - return astToModify; + return OptimizationResult.create(astToModify); } private Stream getAllCseCandidatesStream( diff --git a/optimizer/src/test/java/dev/cel/optimizer/BUILD.bazel b/optimizer/src/test/java/dev/cel/optimizer/BUILD.bazel index f40903138..88e244154 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/BUILD.bazel +++ b/optimizer/src/test/java/dev/cel/optimizer/BUILD.bazel @@ -20,6 +20,7 @@ java_library( "//extensions", "//extensions:optional_library", "//optimizer", + "//optimizer:ast_optimizer", "//optimizer:mutable_ast", "//optimizer:optimization_exception", "//optimizer:optimizer_builder", diff --git a/optimizer/src/test/java/dev/cel/optimizer/CelOptimizerImplTest.java b/optimizer/src/test/java/dev/cel/optimizer/CelOptimizerImplTest.java index fdb6cb968..23ffc192a 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/CelOptimizerImplTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/CelOptimizerImplTest.java @@ -23,6 +23,7 @@ import dev.cel.common.CelSource; import dev.cel.common.CelValidationException; import dev.cel.common.ast.CelExpr; +import dev.cel.optimizer.CelAstOptimizer.OptimizationResult; import java.util.ArrayList; import java.util.List; import org.junit.Test; @@ -41,7 +42,7 @@ public void constructCelOptimizer_success() { .addAstOptimizers( (navigableAst, cel) -> // no-op - navigableAst.getAst()) + OptimizationResult.create(navigableAst.getAst())) .build(); assertThat(celOptimizer).isNotNull(); @@ -57,17 +58,17 @@ public void astOptimizers_invokedInOrder() throws Exception { .addAstOptimizers( (navigableAst, cel) -> { list.add(1); - return navigableAst.getAst(); + return OptimizationResult.create(navigableAst.getAst()); }) .addAstOptimizers( (navigableAst, cel) -> { list.add(2); - return navigableAst.getAst(); + return OptimizationResult.create(navigableAst.getAst()); }) .addAstOptimizers( (navigableAst, cel) -> { list.add(3); - return navigableAst.getAst(); + return OptimizationResult.create(navigableAst.getAst()); }) .build(); @@ -112,8 +113,10 @@ public void optimizedAst_failsToTypeCheck_throwsException() { CelOptimizerImpl.newBuilder(CEL) .addAstOptimizers( (navigableAst, cel) -> - CelAbstractSyntaxTree.newParsedAst( - CelExpr.ofIdentExpr(1, "undeclared_ident"), CelSource.newBuilder().build())) + OptimizationResult.create( + CelAbstractSyntaxTree.newParsedAst( + CelExpr.ofIdentExpr(1, "undeclared_ident"), + CelSource.newBuilder().build()))) .build(); CelOptimizationException e = From 3b8fc7669f40cef6a9eff8e94bf0095f7e35f9e9 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Tue, 5 Mar 2024 11:25:05 -0800 Subject: [PATCH 049/486] Remove redundant indices when optimizing with recursion depth PiperOrigin-RevId: 612910401 --- .../optimizers/SubexpressionOptimizer.java | 29 +- ...pressions_block_recursion_depth_3.baseline | 6 +- ...ssion_ast_block_recursion_depth_1.baseline | 770 ++-- ...ssion_ast_block_recursion_depth_2.baseline | 2601 +++++++------- ...ssion_ast_block_recursion_depth_3.baseline | 2763 +++++++-------- ...ssion_ast_block_recursion_depth_4.baseline | 2905 +++++++-------- ...ssion_ast_block_recursion_depth_5.baseline | 2991 +++++++--------- ...ssion_ast_block_recursion_depth_6.baseline | 3108 ++++++++-------- ...ssion_ast_block_recursion_depth_7.baseline | 2980 +++++++--------- ...ssion_ast_block_recursion_depth_8.baseline | 3110 ++++++++-------- ...ssion_ast_block_recursion_depth_9.baseline | 3113 ++++++++--------- .../resources/subexpression_unparsed.baseline | 648 ++-- 12 files changed, 11370 insertions(+), 13654 deletions(-) diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java index 214785123..2ecc21d16 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java @@ -25,7 +25,6 @@ import com.google.common.base.Verify; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Iterables; import com.google.common.collect.Streams; import com.google.errorprone.annotations.CanIgnoreReturnValue; import dev.cel.bundle.Cel; @@ -58,6 +57,7 @@ import dev.cel.parser.Operator; import java.util.ArrayList; import java.util.Arrays; +import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -509,10 +509,11 @@ private Optional findCseCandidateWithRecursionDepth( ImmutableList allNodes = CelNavigableAst.fromAst(ast) .getRoot() - .allNodes(TraversalOrder.POST_ORDER) + .allNodes(TraversalOrder.PRE_ORDER) .filter(this::canEliminate) .filter(node -> node.height() <= recursionLimit) .filter(node -> !areSemanticallyEqual(ast.getExpr(), node.expr())) + .sorted(Comparator.comparingInt(CelNavigableExpr::height).reversed()) .collect(toImmutableList()); if (allNodes.isEmpty()) { @@ -523,9 +524,23 @@ private Optional findCseCandidateWithRecursionDepth( if (commonSubexpr.isPresent()) { return commonSubexpr; } + // If there's no common subexpr, just return the one with the highest height that's still below - // the recursion limit. - return Optional.of(Iterables.getLast(allNodes)); + // the recursion limit, but only if it actually needs to be extracted due to exceeding the + // recursion limit. + boolean astHasMoreExtractableSubexprs = + CelNavigableAst.fromAst(ast) + .getRoot() + .allNodes(TraversalOrder.POST_ORDER) + .filter(node -> node.height() > recursionLimit) + .anyMatch(this::canEliminate); + if (astHasMoreExtractableSubexprs) { + return Optional.of(allNodes.get(0)); + } + + // The height of the remaining subexpression is already below the recursion limit. No need to + // extract. + return Optional.empty(); } private Optional findCseCandidateWithCommonSubexpr( @@ -705,13 +720,15 @@ public abstract static class Builder { *

Note that expressions containing no common subexpressions may become a candidate for * extraction to satisfy the max depth requirement. * - *

This is a no-op if {@link #enableCelBlock} is set to false, or the configured value is - * less than 1. + *

This is a no-op if {@link #enableCelBlock} is set to false, the configured value is less + * than 1, or no subexpression needs to be extracted because the entire expression is already + * under the designated limit. * *

Examples: * *

    *
  1. a.b.c with depth 1 -> cel.@block([x.b, @index0.c], @index1) + *
  2. a.b.c with depth 3 -> a.b.c *
  3. a.b + a.b.c.d with depth 3 -> cel.@block([a.b, @index0.c.d], @index0 + @index1) *
* diff --git a/optimizer/src/test/resources/large_expressions_block_recursion_depth_3.baseline b/optimizer/src/test/resources/large_expressions_block_recursion_depth_3.baseline index 832173f88..24138a632 100644 --- a/optimizer/src/test/resources/large_expressions_block_recursion_depth_3.baseline +++ b/optimizer/src/test/resources/large_expressions_block_recursion_depth_3.baseline @@ -2,16 +2,16 @@ Test case: CALC_FOUR_COMMON_SUBEXPR Source: [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] + [1] + [1,2] + [1,2,3] + [1,2,3,4] =====> Result: [1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 1, 2, 1, 2, 3, 1, 2, 3, 4] -Unparsed: cel.@block([[1], [1, 2], [1, 2, 3], [1, 2, 3, 4], @index0 + @index1 + @index2 + @index3, @index4 + @index0 + @index1 + @index2, @index5 + @index3 + @index0 + @index1, @index6 + @index2 + @index3 + @index0, @index7 + @index1 + @index2 + @index3, @index8 + @index0 + @index1 + @index2, @index9 + @index3 + @index0 + @index1, @index10 + @index2 + @index3 + @index0, @index11 + @index1 + @index2 + @index3, @index12 + @index0 + @index1 + @index2, @index13 + @index3 + @index0 + @index1, @index14 + @index2 + @index3 + @index0, @index15 + @index1 + @index2 + @index3, @index16 + @index0 + @index1 + @index2, @index17 + @index3 + @index0 + @index1, @index18 + @index2 + @index3 + @index0, @index19 + @index1 + @index2 + @index3, @index20 + @index0 + @index1 + @index2, @index21 + @index3 + @index0 + @index1, @index22 + @index2 + @index3 + @index0, @index23 + @index1 + @index2 + @index3, @index24 + @index0 + @index1 + @index2, @index25 + @index3 + @index0 + @index1, @index26 + @index2 + @index3 + @index0, @index27 + @index1 + @index2 + @index3, @index28 + @index0 + @index1 + @index2, @index29 + @index3 + @index0 + @index1, @index30 + @index2 + @index3 + @index0, @index31 + @index1 + @index2 + @index3, @index32 + @index0 + @index1 + @index2, @index33 + @index3 + @index0 + @index1, @index34 + @index2 + @index3 + @index0, @index35 + @index1 + @index2 + @index3, @index36 + @index0 + @index1 + @index2, @index37 + @index3 + @index0 + @index1, @index38 + @index2 + @index3 + @index0, @index39 + @index1 + @index2 + @index3, @index40 + @index0 + @index1 + @index2, @index41 + @index3 + @index0 + @index1, @index42 + @index2 + @index3 + @index0, @index43 + @index1 + @index2 + @index3, @index44 + @index0 + @index1 + @index2, @index45 + @index3 + @index0 + @index1, @index46 + @index2 + @index3 + @index0, @index47 + @index1 + @index2 + @index3, @index48 + @index0 + @index1 + @index2, @index49 + @index3 + @index0 + @index1, @index50 + @index2 + @index3 + @index0, @index51 + @index1 + @index2 + @index3, @index52 + @index0 + @index1 + @index2, @index53 + @index3 + @index0 + @index1, @index54 + @index2 + @index3 + @index0, @index55 + @index1 + @index2], @index56 + @index3) +Unparsed: cel.@block([[1], [1, 2], [1, 2, 3], [1, 2, 3, 4], @index0 + @index1 + @index2 + @index3, @index4 + @index0 + @index1 + @index2, @index5 + @index3 + @index0 + @index1, @index6 + @index2 + @index3 + @index0, @index7 + @index1 + @index2 + @index3, @index8 + @index0 + @index1 + @index2, @index9 + @index3 + @index0 + @index1, @index10 + @index2 + @index3 + @index0, @index11 + @index1 + @index2 + @index3, @index12 + @index0 + @index1 + @index2, @index13 + @index3 + @index0 + @index1, @index14 + @index2 + @index3 + @index0, @index15 + @index1 + @index2 + @index3, @index16 + @index0 + @index1 + @index2, @index17 + @index3 + @index0 + @index1, @index18 + @index2 + @index3 + @index0, @index19 + @index1 + @index2 + @index3, @index20 + @index0 + @index1 + @index2, @index21 + @index3 + @index0 + @index1, @index22 + @index2 + @index3 + @index0, @index23 + @index1 + @index2 + @index3, @index24 + @index0 + @index1 + @index2, @index25 + @index3 + @index0 + @index1, @index26 + @index2 + @index3 + @index0, @index27 + @index1 + @index2 + @index3, @index28 + @index0 + @index1 + @index2, @index29 + @index3 + @index0 + @index1, @index30 + @index2 + @index3 + @index0, @index31 + @index1 + @index2 + @index3, @index32 + @index0 + @index1 + @index2, @index33 + @index3 + @index0 + @index1, @index34 + @index2 + @index3 + @index0, @index35 + @index1 + @index2 + @index3, @index36 + @index0 + @index1 + @index2, @index37 + @index3 + @index0 + @index1, @index38 + @index2 + @index3 + @index0, @index39 + @index1 + @index2 + @index3, @index40 + @index0 + @index1 + @index2, @index41 + @index3 + @index0 + @index1, @index42 + @index2 + @index3 + @index0, @index43 + @index1 + @index2 + @index3, @index44 + @index0 + @index1 + @index2, @index45 + @index3 + @index0 + @index1, @index46 + @index2 + @index3 + @index0, @index47 + @index1 + @index2 + @index3, @index48 + @index0 + @index1 + @index2, @index49 + @index3 + @index0 + @index1, @index50 + @index2 + @index3 + @index0, @index51 + @index1 + @index2 + @index3, @index52 + @index0 + @index1 + @index2, @index53 + @index3 + @index0 + @index1, @index54 + @index2 + @index3 + @index0], @index55 + @index1 + @index2 + @index3) Test case: CALC_ALL_COMMON_SUBEXPR Source: [0, 1] + [0, 1] + [1, 2] + [1, 2] + [2, 3] + [2, 3] + [3, 4] + [3, 4] + [4, 5] + [4, 5] + [5, 6] + [5, 6] + [6, 7] + [6, 7] + [7, 8] + [7, 8] + [8, 9] + [8, 9] + [9, 10] + [9, 10] + [10, 11] + [10, 11] + [11, 12] + [11, 12] + [12, 13] + [12, 13] + [13, 14] + [13, 14] + [14, 15] + [14, 15] + [15, 16] + [15, 16] + [16, 17] + [16, 17] + [17, 18] + [17, 18] + [18, 19] + [18, 19] + [19, 20] + [19, 20] + [20, 21] + [20, 21] + [21, 22] + [21, 22] + [22, 23] + [22, 23] + [23, 24] + [23, 24] + [24, 25] + [24, 25] + [25, 26] + [25, 26] + [26, 27] + [26, 27] + [27, 28] + [27, 28] + [28, 29] + [28, 29] + [29, 30] + [29, 30] + [30, 31] + [30, 31] + [31, 32] + [31, 32] + [32, 33] + [32, 33] + [33, 34] + [33, 34] + [34, 35] + [34, 35] + [35, 36] + [35, 36] + [36, 37] + [36, 37] + [37, 38] + [37, 38] + [38, 39] + [38, 39] + [39, 40] + [39, 40] + [40, 41] + [40, 41] + [41, 42] + [41, 42] + [42, 43] + [42, 43] + [43, 44] + [43, 44] + [44, 45] + [44, 45] + [45, 46] + [45, 46] + [46, 47] + [46, 47] + [47, 48] + [47, 48] + [48, 49] + [48, 49] + [49, 50] + [49, 50] =====> Result: [0, 1, 0, 1, 1, 2, 1, 2, 2, 3, 2, 3, 3, 4, 3, 4, 4, 5, 4, 5, 5, 6, 5, 6, 6, 7, 6, 7, 7, 8, 7, 8, 8, 9, 8, 9, 9, 10, 9, 10, 10, 11, 10, 11, 11, 12, 11, 12, 12, 13, 12, 13, 13, 14, 13, 14, 14, 15, 14, 15, 15, 16, 15, 16, 16, 17, 16, 17, 17, 18, 17, 18, 18, 19, 18, 19, 19, 20, 19, 20, 20, 21, 20, 21, 21, 22, 21, 22, 22, 23, 22, 23, 23, 24, 23, 24, 24, 25, 24, 25, 25, 26, 25, 26, 26, 27, 26, 27, 27, 28, 27, 28, 28, 29, 28, 29, 29, 30, 29, 30, 30, 31, 30, 31, 31, 32, 31, 32, 32, 33, 32, 33, 33, 34, 33, 34, 34, 35, 34, 35, 35, 36, 35, 36, 36, 37, 36, 37, 37, 38, 37, 38, 38, 39, 38, 39, 39, 40, 39, 40, 40, 41, 40, 41, 41, 42, 41, 42, 42, 43, 42, 43, 43, 44, 43, 44, 44, 45, 44, 45, 45, 46, 45, 46, 46, 47, 46, 47, 47, 48, 47, 48, 48, 49, 48, 49, 49, 50, 49, 50] -Unparsed: cel.@block([[0, 1], [1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7], [7, 8], [8, 9], [9, 10], [10, 11], [11, 12], [12, 13], [13, 14], [14, 15], [15, 16], [16, 17], [17, 18], [18, 19], [19, 20], [20, 21], [21, 22], [22, 23], [23, 24], [24, 25], [25, 26], [26, 27], [27, 28], [28, 29], [29, 30], [30, 31], [31, 32], [32, 33], [33, 34], [34, 35], [35, 36], [36, 37], [37, 38], [38, 39], [39, 40], [40, 41], [41, 42], [42, 43], [43, 44], [44, 45], [45, 46], [46, 47], [47, 48], [48, 49], [49, 50], @index0 + @index0 + @index1 + @index1, @index50 + @index2 + @index2 + @index3, @index51 + @index3 + @index4 + @index4, @index52 + @index5 + @index5 + @index6, @index53 + @index6 + @index7 + @index7, @index54 + @index8 + @index8 + @index9, @index55 + @index9 + @index10 + @index10, @index56 + @index11 + @index11 + @index12, @index57 + @index12 + @index13 + @index13, @index58 + @index14 + @index14 + @index15, @index59 + @index15 + @index16 + @index16, @index60 + @index17 + @index17 + @index18, @index61 + @index18 + @index19 + @index19, @index62 + @index20 + @index20 + @index21, @index63 + @index21 + @index22 + @index22, @index64 + @index23 + @index23 + @index24, @index65 + @index24 + @index25 + @index25, @index66 + @index26 + @index26 + @index27, @index67 + @index27 + @index28 + @index28, @index68 + @index29 + @index29 + @index30, @index69 + @index30 + @index31 + @index31, @index70 + @index32 + @index32 + @index33, @index71 + @index33 + @index34 + @index34, @index72 + @index35 + @index35 + @index36, @index73 + @index36 + @index37 + @index37, @index74 + @index38 + @index38 + @index39, @index75 + @index39 + @index40 + @index40, @index76 + @index41 + @index41 + @index42, @index77 + @index42 + @index43 + @index43, @index78 + @index44 + @index44 + @index45, @index79 + @index45 + @index46 + @index46, @index80 + @index47 + @index47 + @index48, @index81 + @index48 + @index49], @index82 + @index49) +Unparsed: cel.@block([[0, 1], [1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7], [7, 8], [8, 9], [9, 10], [10, 11], [11, 12], [12, 13], [13, 14], [14, 15], [15, 16], [16, 17], [17, 18], [18, 19], [19, 20], [20, 21], [21, 22], [22, 23], [23, 24], [24, 25], [25, 26], [26, 27], [27, 28], [28, 29], [29, 30], [30, 31], [31, 32], [32, 33], [33, 34], [34, 35], [35, 36], [36, 37], [37, 38], [38, 39], [39, 40], [40, 41], [41, 42], [42, 43], [43, 44], [44, 45], [45, 46], [46, 47], [47, 48], [48, 49], [49, 50], @index0 + @index0 + @index1 + @index1, @index50 + @index2 + @index2 + @index3, @index51 + @index3 + @index4 + @index4, @index52 + @index5 + @index5 + @index6, @index53 + @index6 + @index7 + @index7, @index54 + @index8 + @index8 + @index9, @index55 + @index9 + @index10 + @index10, @index56 + @index11 + @index11 + @index12, @index57 + @index12 + @index13 + @index13, @index58 + @index14 + @index14 + @index15, @index59 + @index15 + @index16 + @index16, @index60 + @index17 + @index17 + @index18, @index61 + @index18 + @index19 + @index19, @index62 + @index20 + @index20 + @index21, @index63 + @index21 + @index22 + @index22, @index64 + @index23 + @index23 + @index24, @index65 + @index24 + @index25 + @index25, @index66 + @index26 + @index26 + @index27, @index67 + @index27 + @index28 + @index28, @index68 + @index29 + @index29 + @index30, @index69 + @index30 + @index31 + @index31, @index70 + @index32 + @index32 + @index33, @index71 + @index33 + @index34 + @index34, @index72 + @index35 + @index35 + @index36, @index73 + @index36 + @index37 + @index37, @index74 + @index38 + @index38 + @index39, @index75 + @index39 + @index40 + @index40, @index76 + @index41 + @index41 + @index42, @index77 + @index42 + @index43 + @index43, @index78 + @index44 + @index44 + @index45, @index79 + @index45 + @index46 + @index46, @index80 + @index47 + @index47 + @index48], @index81 + @index48 + @index49 + @index49) Test case: NESTED_MACROS Source: [1,2,3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3])))))))) =====> Result: [[[[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]]], [[[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]]], [[[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]]]] -Unparsed: cel.@block([[1, 2, 3], @index0.map(@c7:0, @index0), @index0.map(@c6:0, @index1), @index0.map(@c5:0, @index2), @index0.map(@c4:0, @index3), @index0.map(@c3:0, @index4), @index0.map(@c2:0, @index5), @index0.map(@c1:0, @index6), @x0:0 + [@index7]], @index0.map(@c0:0, @index7)) +Unparsed: cel.@block([[1, 2, 3], @index0.map(@c7:0, @index0), @index0.map(@c6:0, @index1), @index0.map(@c5:0, @index2), @index0.map(@c4:0, @index3), @index0.map(@c3:0, @index4), @index0.map(@c2:0, @index5), @index0.map(@c1:0, @index6)], @index0.map(@c0:0, @index7)) diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_1.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_1.baseline index a8b6c243c..3b4233150 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_1.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_1.baseline @@ -442,7 +442,7 @@ CALL [1] { } } CALL [31] { - function: getMinutes + function: getFullYear target: { IDENT [32] { name: @index13 @@ -452,109 +452,109 @@ CALL [1] { } } CALL [33] { - function: getSeconds - target: { + function: _+_ + args: { IDENT [34] { - name: @index6 + name: @index3 } - } - args: { - } - } - CALL [35] { - function: getFullYear - target: { - IDENT [36] { - name: @index6 + IDENT [35] { + name: @index14 } } - args: { - } } - CALL [37] { + CALL [36] { function: getFullYear target: { - IDENT [38] { - name: @index13 + IDENT [37] { + name: @index6 } } args: { } } - CALL [39] { + CALL [38] { function: _+_ args: { - IDENT [40] { - name: @index3 + IDENT [39] { + name: @index15 } - IDENT [41] { - name: @index17 + IDENT [40] { + name: @index16 } } } - CALL [42] { + CALL [41] { function: _+_ args: { + IDENT [42] { + name: @index17 + } IDENT [43] { - name: @index18 + name: @index3 } - IDENT [44] { - name: @index16 + } + } + CALL [44] { + function: getSeconds + target: { + IDENT [45] { + name: @index6 } } + args: { + } } - CALL [45] { + CALL [46] { function: _+_ args: { - IDENT [46] { - name: @index19 - } IDENT [47] { - name: @index3 + name: @index18 + } + IDENT [48] { + name: @index19 } } } - CALL [48] { + CALL [49] { function: _+_ args: { - IDENT [49] { + IDENT [50] { name: @index20 } - IDENT [50] { - name: @index15 + IDENT [51] { + name: @index10 } } } - CALL [51] { + CALL [52] { function: _+_ args: { - IDENT [52] { + IDENT [53] { name: @index21 } - IDENT [53] { + IDENT [54] { name: @index10 } } } - CALL [54] { - function: _+_ - args: { - IDENT [55] { - name: @index22 - } + CALL [55] { + function: getMinutes + target: { IDENT [56] { - name: @index10 + name: @index13 } } + args: { + } } CALL [57] { function: _+_ args: { IDENT [58] { - name: @index23 + name: @index22 } IDENT [59] { - name: @index14 + name: @index23 } } } @@ -842,69 +842,69 @@ CALL [1] { SELECT [9] { IDENT [10] { name: @index1 - }.oneof_type - } - SELECT [11] { - IDENT [12] { - name: @index3 - }.payload - } - SELECT [13] { - IDENT [14] { - name: @index4 - }.single_int64 - } - SELECT [15] { - IDENT [16] { - name: msg - }.single_int64 - } - SELECT [17] { - IDENT [18] { - name: @index1 }.single_int32 } - CALL [19] { + CALL [11] { function: _+_ args: { - IDENT [20] { + IDENT [12] { name: @index2 } - IDENT [21] { - name: @index7 + IDENT [13] { + name: @index3 } } } - CALL [22] { + CALL [14] { function: _+_ args: { - IDENT [23] { - name: @index8 + IDENT [15] { + name: @index4 } - IDENT [24] { + IDENT [16] { name: @index2 } } } - CALL [25] { + SELECT [17] { + IDENT [18] { + name: msg + }.single_int64 + } + CALL [19] { function: _+_ args: { - IDENT [26] { - name: @index9 + IDENT [20] { + name: @index5 } - IDENT [27] { + IDENT [21] { name: @index6 } } } + SELECT [22] { + IDENT [23] { + name: @index1 + }.oneof_type + } + SELECT [24] { + IDENT [25] { + name: @index8 + }.payload + } + SELECT [26] { + IDENT [27] { + name: @index9 + }.single_int64 + } CALL [28] { function: _+_ args: { IDENT [29] { - name: @index10 + name: @index7 } IDENT [30] { - name: @index5 + name: @index10 } } } @@ -957,12 +957,12 @@ CALL [1] { SELECT [13] { IDENT [14] { name: @index4 - }.child + }.payload } SELECT [15] { IDENT [16] { name: @index5 - }.child + }.oneof_type } SELECT [17] { IDENT [18] { @@ -974,34 +974,34 @@ CALL [1] { name: @index7 }.single_bool } - SELECT [21] { - IDENT [22] { - name: @index4 - }.payload + CALL [21] { + function: _||_ + args: { + CONSTANT [22] { value: true } + IDENT [23] { + name: @index8 + } + } } - SELECT [23] { - IDENT [24] { - name: @index9 - }.oneof_type + SELECT [24] { + IDENT [25] { + name: @index4 + }.child } - SELECT [25] { - IDENT [26] { + SELECT [26] { + IDENT [27] { name: @index10 - }.payload + }.child } - SELECT [27] { - IDENT [28] { + SELECT [28] { + IDENT [29] { name: @index11 - }.single_bool + }.payload } - CALL [29] { - function: _||_ - args: { - CONSTANT [30] { value: true } - IDENT [31] { - name: @index12 - } - } + SELECT [30] { + IDENT [31] { + name: @index12 + }.single_bool } } } @@ -1009,10 +1009,10 @@ CALL [1] { function: _||_ args: { IDENT [33] { - name: @index13 + name: @index9 } IDENT [34] { - name: @index8 + name: @index13 } } } @@ -1114,7 +1114,7 @@ CALL [1] { IDENT [10] { name: @index2 } - CONSTANT [11] { value: 2 } + CONSTANT [11] { value: 0 } } } CALL [12] { @@ -1127,33 +1127,33 @@ CALL [1] { } } CALL [15] { - function: _[_] + function: _+_ args: { IDENT [16] { - name: @index2 + name: @index3 + } + IDENT [17] { + name: @index4 } - CONSTANT [17] { value: 0 } } } CALL [18] { - function: _+_ + function: _[_] args: { IDENT [19] { - name: @index5 - } - IDENT [20] { - name: @index4 + name: @index2 } + CONSTANT [20] { value: 2 } } } CALL [21] { function: _+_ args: { IDENT [22] { - name: @index6 + name: @index5 } IDENT [23] { - name: @index3 + name: @index6 } } } @@ -1358,14 +1358,12 @@ CALL [1] { }.single_int32 } CALL [7] { - function: _+_ + function: _>_ args: { IDENT [8] { name: @index0 } - IDENT [9] { - name: @index1 - } + CONSTANT [9] { value: 0 } } } CALL [10] { @@ -1378,22 +1376,24 @@ CALL [1] { } } CALL [13] { - function: _?_:_ + function: _+_ args: { IDENT [14] { - name: @index3 + name: @index0 } IDENT [15] { - name: @index2 + name: @index1 } - CONSTANT [16] { value: 0 } } } - CALL [17] { - function: _>_ + CALL [16] { + function: _?_:_ args: { + IDENT [17] { + name: @index3 + } IDENT [18] { - name: @index0 + name: @index4 } CONSTANT [19] { value: 0 } } @@ -1402,10 +1402,10 @@ CALL [1] { function: _?_:_ args: { IDENT [21] { - name: @index5 + name: @index2 } IDENT [22] { - name: @index4 + name: @index5 } CONSTANT [23] { value: 0 } } @@ -1969,43 +1969,43 @@ CALL [1] { CONSTANT [10] { value: 4 } } } - CREATE_LIST [11] { - elements: { - IDENT [12] { - name: @index1 - } - IDENT [13] { - name: @index1 - } - IDENT [14] { - name: @index1 - } - } - } - CALL [15] { + CALL [11] { function: _+_ args: { - IDENT [16] { + IDENT [12] { name: @c1:0 } - CONSTANT [17] { value: 1 } + CONSTANT [13] { value: 1 } } } - CREATE_LIST [18] { + CREATE_LIST [14] { elements: { - IDENT [19] { - name: @index3 + IDENT [15] { + name: @index2 } } } - CALL [20] { + CALL [16] { function: _+_ args: { - IDENT [21] { + IDENT [17] { name: @x1:0 } + IDENT [18] { + name: @index3 + } + } + } + CREATE_LIST [19] { + elements: { + IDENT [20] { + name: @index1 + } + IDENT [21] { + name: @index1 + } IDENT [22] { - name: @index4 + name: @index1 } } } @@ -2059,7 +2059,7 @@ CALL [1] { } loop_step: { IDENT [35] { - name: @index5 + name: @index4 } } result: { @@ -2080,7 +2080,7 @@ CALL [1] { } } IDENT [38] { - name: @index2 + name: @index5 } } } @@ -2096,50 +2096,43 @@ CALL [1] { elements: { CREATE_LIST [3] { elements: { - CONSTANT [4] { value: 2 } + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } } } - CREATE_LIST [5] { - elements: { - CONSTANT [6] { value: 1 } - } - } - CREATE_LIST [7] { + CREATE_LIST [6] { elements: { - IDENT [8] { - name: @index1 - } - IDENT [9] { - name: @index0 - } + CONSTANT [7] { value: 1 } + CONSTANT [8] { value: 2 } + CONSTANT [9] { value: 3 } } } - CREATE_LIST [10] { - elements: { + CALL [10] { + function: _==_ + args: { IDENT [11] { name: @c1:0 } + IDENT [12] { + name: @c0:0 + } } } - CALL [12] { - function: _+_ - args: { - IDENT [13] { - name: @x1:0 - } + CREATE_LIST [13] { + elements: { IDENT [14] { - name: @index3 + name: @c1:0 } } } CALL [15] { - function: _==_ + function: _+_ args: { IDENT [16] { - name: @c1:0 + name: @x1:0 } IDENT [17] { - name: @c0:0 + name: @index3 } } } @@ -2147,7 +2140,7 @@ CALL [1] { function: _?_:_ args: { IDENT [19] { - name: @index5 + name: @index2 } IDENT [20] { name: @index4 @@ -2160,14 +2153,21 @@ CALL [1] { CREATE_LIST [22] { elements: { CONSTANT [23] { value: 1 } - CONSTANT [24] { value: 2 } - CONSTANT [25] { value: 3 } + } + } + CREATE_LIST [24] { + elements: { + CONSTANT [25] { value: 2 } } } CREATE_LIST [26] { elements: { - CONSTANT [27] { value: 1 } - CONSTANT [28] { value: 2 } + IDENT [27] { + name: @index6 + } + IDENT [28] { + name: @index7 + } } } } @@ -2179,7 +2179,7 @@ CALL [1] { iter_var: @c0:0 iter_range: { IDENT [31] { - name: @index8 + name: @index0 } } accu_var: @x0:0 @@ -2205,7 +2205,7 @@ CALL [1] { iter_var: @c1:0 iter_range: { IDENT [38] { - name: @index7 + name: @index1 } } accu_var: @x1:0 @@ -2220,7 +2220,7 @@ CALL [1] { } loop_step: { IDENT [41] { - name: @index6 + name: @index5 } } result: { @@ -2241,7 +2241,7 @@ CALL [1] { } } IDENT [44] { - name: @index2 + name: @index8 } } } @@ -2271,40 +2271,40 @@ CALL [1] { } } } - CREATE_LIST [10] { - elements: { - CONSTANT [11] { value: 3 } + CALL [10] { + function: @in + args: { + CONSTANT [11] { value: 2 } IDENT [12] { name: @index0 } } } CALL [13] { - function: @in + function: _&&_ args: { - CONSTANT [14] { value: 3 } + IDENT [14] { + name: @index1 + } IDENT [15] { name: @index2 } } } - CALL [16] { - function: _&&_ - args: { - IDENT [17] { - name: @index3 - } + CREATE_LIST [16] { + elements: { + CONSTANT [17] { value: 3 } IDENT [18] { - name: @index1 + name: @index0 } } } CALL [19] { function: @in args: { - CONSTANT [20] { value: 2 } + CONSTANT [20] { value: 3 } IDENT [21] { - name: @index0 + name: @index4 } } } @@ -2312,10 +2312,10 @@ CALL [1] { function: _&&_ args: { IDENT [23] { - name: @index1 + name: @index5 } IDENT [24] { - name: @index5 + name: @index1 } } } @@ -2325,10 +2325,10 @@ CALL [1] { function: _&&_ args: { IDENT [26] { - name: @index6 + name: @index3 } IDENT [27] { - name: @index4 + name: @index6 } } } @@ -2428,28 +2428,28 @@ CALL [1] { CREATE_LIST [12] { elements: { IDENT [13] { - name: @index2 - } - IDENT [14] { - name: @index2 + name: @index1 } } } - CREATE_LIST [15] { - elements: { + CALL [14] { + function: _+_ + args: { + IDENT [15] { + name: @x1:0 + } IDENT [16] { - name: @index1 + name: @index3 } } } - CALL [17] { - function: _+_ - args: { + CREATE_LIST [17] { + elements: { IDENT [18] { - name: @x1:0 + name: @index2 } IDENT [19] { - name: @index4 + name: @index2 } } } @@ -2503,7 +2503,7 @@ CALL [1] { } loop_step: { IDENT [32] { - name: @index5 + name: @index4 } } result: { @@ -2524,7 +2524,7 @@ CALL [1] { } } IDENT [35] { - name: @index3 + name: @index5 } } } @@ -2557,48 +2557,48 @@ CALL [1] { } } CALL [9] { - function: _-_ + function: _?_:_ args: { IDENT [10] { - name: @c0:0 + name: @index1 } - CONSTANT [11] { value: 1 } + IDENT [11] { + name: @index0 + } + CONSTANT [12] { value: 5 } } } - CALL [12] { - function: _>_ - args: { - IDENT [13] { + CREATE_LIST [13] { + elements: { + IDENT [14] { name: @index2 } - CONSTANT [14] { value: 3 } } } CALL [15] { - function: _||_ + function: _-_ args: { IDENT [16] { - name: @x0:0 - } - IDENT [17] { - name: @index3 + name: @c0:0 } + CONSTANT [17] { value: 1 } } } CALL [18] { - function: _?_:_ + function: _>_ args: { IDENT [19] { - name: @index1 - } - IDENT [20] { - name: @index0 + name: @index4 } - CONSTANT [21] { value: 5 } + CONSTANT [20] { value: 3 } } } - CREATE_LIST [22] { - elements: { + CALL [21] { + function: _||_ + args: { + IDENT [22] { + name: @x0:0 + } IDENT [23] { name: @index5 } @@ -2613,7 +2613,7 @@ CALL [1] { iter_var: @c0:0 iter_range: { IDENT [26] { - name: @index6 + name: @index3 } } accu_var: @x0:0 @@ -2637,7 +2637,7 @@ CALL [1] { } loop_step: { IDENT [31] { - name: @index4 + name: @index6 } } result: { @@ -2685,64 +2685,64 @@ CALL [1] { } CREATE_LIST [9] { elements: { - IDENT [10] { - name: @index1 - } - IDENT [11] { - name: @index1 - } + CONSTANT [10] { value: "foo" } + CONSTANT [11] { value: "bar" } } } CREATE_LIST [12] { elements: { IDENT [13] { - name: @index2 + name: @index0 + } + IDENT [14] { + name: @index0 } } } - CALL [14] { - function: _+_ - args: { - IDENT [15] { - name: @x0:0 - } + CREATE_LIST [15] { + elements: { IDENT [16] { name: @index3 } } } - CREATE_LIST [17] { - elements: { + CALL [17] { + function: _+_ + args: { IDENT [18] { - name: @index0 + name: @x1:0 } IDENT [19] { - name: @index0 + name: @index4 } } } CREATE_LIST [20] { elements: { IDENT [21] { - name: @index5 + name: @index1 + } + IDENT [22] { + name: @index1 } } } - CALL [22] { - function: _+_ - args: { - IDENT [23] { - name: @x1:0 - } + CREATE_LIST [23] { + elements: { IDENT [24] { name: @index6 } } } - CREATE_LIST [25] { - elements: { - CONSTANT [26] { value: "foo" } - CONSTANT [27] { value: "bar" } + CALL [25] { + function: _+_ + args: { + IDENT [26] { + name: @x0:0 + } + IDENT [27] { + name: @index7 + } } } } @@ -2754,7 +2754,7 @@ CALL [1] { iter_var: @c1:0 iter_range: { IDENT [30] { - name: @index8 + name: @index2 } } accu_var: @x1:0 @@ -2769,7 +2769,7 @@ CALL [1] { } loop_step: { IDENT [33] { - name: @index7 + name: @index5 } } result: { @@ -2791,7 +2791,7 @@ CALL [1] { } loop_step: { IDENT [37] { - name: @index4 + name: @index8 } } result: { @@ -3138,27 +3138,27 @@ CALL [1] { elements: { CONSTANT [10] { value: 10 } IDENT [11] { - name: @index2 + name: @index0 } IDENT [12] { - name: @index2 + name: @index1 + } + IDENT [13] { + name: @index1 } } + optional_indices: [0] } - CREATE_LIST [13] { + CREATE_LIST [14] { elements: { - CONSTANT [14] { value: 10 } - IDENT [15] { - name: @index0 - } + CONSTANT [15] { value: 10 } IDENT [16] { - name: @index1 + name: @index2 } IDENT [17] { - name: @index1 + name: @index2 } } - optional_indices: [0] } } } @@ -3166,10 +3166,10 @@ CALL [1] { function: _==_ args: { IDENT [19] { - name: @index4 + name: @index3 } IDENT [20] { - name: @index3 + name: @index4 } } } @@ -3254,74 +3254,74 @@ CALL [1] { } } CALL [7] { - function: _[_] - args: { - IDENT [8] { - name: @index0 - } - CONSTANT [9] { value: "key" } - } - } - CALL [10] { - function: _[?_] - args: { - IDENT [11] { - name: @index0 - } - CONSTANT [12] { value: "bogus" } - } - } - CALL [13] { function: optional.of args: { - CONSTANT [14] { value: "test" } + CONSTANT [8] { value: "test" } } } - CREATE_MAP [15] { - MAP_ENTRY [16] { + CREATE_MAP [9] { + MAP_ENTRY [10] { key: { - CONSTANT [17] { value: "key" } + CONSTANT [11] { value: "key" } } optional_entry: true value: { - IDENT [18] { - name: @index3 + IDENT [12] { + name: @index1 } } } } - CALL [19] { + CALL [13] { function: _[?_] args: { - IDENT [20] { - name: @index4 + IDENT [14] { + name: @index2 } - CONSTANT [21] { value: "bogus" } + CONSTANT [15] { value: "bogus" } } } - CALL [22] { + CALL [16] { + function: _[?_] + args: { + IDENT [17] { + name: @index0 + } + CONSTANT [18] { value: "bogus" } + } + } + CALL [19] { function: or target: { - IDENT [23] { - name: @index5 + IDENT [20] { + name: @index3 } } args: { - IDENT [24] { - name: @index2 + IDENT [21] { + name: @index4 + } + } + } + CALL [22] { + function: _[_] + args: { + IDENT [23] { + name: @index0 } + CONSTANT [24] { value: "key" } } } CALL [25] { function: orValue target: { IDENT [26] { - name: @index6 + name: @index5 } } args: { IDENT [27] { - name: @index1 + name: @index6 } } } @@ -3384,21 +3384,21 @@ CALL [1] { SELECT [12] { IDENT [13] { name: @index2 - }.single_int64 + }.single_int32 } SELECT [14] { IDENT [15] { name: @index2 - }.single_int32 + }.single_int64 } CALL [16] { function: _+_ args: { IDENT [17] { - name: @index4 + name: @index3 } IDENT [18] { - name: @index3 + name: @index4 } } } @@ -3617,8 +3617,8 @@ CALL [1] { CALL [3] { function: _+_ args: { - CONSTANT [4] { value: "w" } - CONSTANT [5] { value: "o" } + CONSTANT [4] { value: "h" } + CONSTANT [5] { value: "e" } } } CALL [6] { @@ -3627,7 +3627,7 @@ CALL [1] { IDENT [7] { name: @index0 } - CONSTANT [8] { value: "r" } + CONSTANT [8] { value: "l" } } } CALL [9] { @@ -3645,23 +3645,23 @@ CALL [1] { IDENT [13] { name: @index2 } - CONSTANT [14] { value: "d" } + CONSTANT [14] { value: "o" } } } CALL [15] { function: _+_ args: { - CONSTANT [16] { value: "h" } - CONSTANT [17] { value: "e" } + IDENT [16] { + name: @index3 + } + CONSTANT [17] { value: " world" } } } CALL [18] { function: _+_ args: { - IDENT [19] { - name: @index4 - } - CONSTANT [20] { value: "l" } + CONSTANT [19] { value: "w" } + CONSTANT [20] { value: "o" } } } CALL [21] { @@ -3670,7 +3670,7 @@ CALL [1] { IDENT [22] { name: @index5 } - CONSTANT [23] { value: "l" } + CONSTANT [23] { value: "r" } } } CALL [24] { @@ -3679,7 +3679,7 @@ CALL [1] { IDENT [25] { name: @index6 } - CONSTANT [26] { value: "o" } + CONSTANT [26] { value: "l" } } } CALL [27] { @@ -3688,7 +3688,7 @@ CALL [1] { IDENT [28] { name: @index7 } - CONSTANT [29] { value: " world" } + CONSTANT [29] { value: "d" } } } } @@ -3697,12 +3697,12 @@ CALL [1] { function: matches target: { IDENT [31] { - name: @index8 + name: @index4 } } args: { IDENT [32] { - name: @index3 + name: @index8 } } } @@ -3731,60 +3731,54 @@ CALL [1] { name: @index1 }.single_int64 } - SELECT [9] { - IDENT [10] { - name: msg - }.single_int64 - } - SELECT [11] { - IDENT [12] { - name: @index1 - }.single_int32 - } } } - CALL [13] { + CALL [9] { function: _+_ args: { - CALL [14] { + CALL [10] { function: _+_ args: { - CALL [15] { + CALL [11] { function: _+_ args: { - CALL [16] { + CALL [12] { function: non_pure_custom_func args: { - IDENT [17] { + IDENT [13] { name: @index2 } } } - CALL [18] { + CALL [14] { function: non_pure_custom_func args: { - IDENT [19] { - name: @index4 + SELECT [15] { + IDENT [16] { + name: @index1 + }.single_int32 } } } } } - CALL [20] { + CALL [17] { function: non_pure_custom_func args: { - IDENT [21] { + IDENT [18] { name: @index2 } } } } } - CALL [22] { + CALL [19] { function: non_pure_custom_func args: { - IDENT [23] { - name: @index3 + SELECT [20] { + IDENT [21] { + name: msg + }.single_int64 } } } @@ -3825,8 +3819,8 @@ CALL [1] { } SELECT [11] { IDENT [12] { - name: msg - }.single_int64 + name: @index1 + }.single_int32 } CALL [13] { function: pure_custom_func @@ -3836,38 +3830,38 @@ CALL [1] { } } } - SELECT [15] { - IDENT [16] { - name: @index1 - }.single_int32 - } - CALL [17] { - function: pure_custom_func + CALL [15] { + function: _+_ args: { - IDENT [18] { - name: @index6 + IDENT [16] { + name: @index3 + } + IDENT [17] { + name: @index5 } } } - CALL [19] { + CALL [18] { function: _+_ args: { + IDENT [19] { + name: @index6 + } IDENT [20] { name: @index3 } - IDENT [21] { - name: @index7 - } } } - CALL [22] { - function: _+_ + SELECT [21] { + IDENT [22] { + name: msg + }.single_int64 + } + CALL [23] { + function: pure_custom_func args: { - IDENT [23] { - name: @index8 - } IDENT [24] { - name: @index3 + name: @index8 } } } @@ -3877,10 +3871,10 @@ CALL [1] { function: _+_ args: { IDENT [26] { - name: @index9 + name: @index7 } IDENT [27] { - name: @index5 + name: @index9 } } } diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_2.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_2.baseline index ff087237a..e294e828b 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_2.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_2.baseline @@ -6,46 +6,43 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_LIST [3] { - elements: { - CONSTANT [4] { value: 1 } - CONSTANT [5] { value: 2 } - } - } - CALL [6] { + CALL [3] { function: size args: { - IDENT [7] { - name: @index0 + CREATE_LIST [4] { + elements: { + CONSTANT [5] { value: 1 } + CONSTANT [6] { value: 2 } + } } } } - CALL [8] { + CALL [7] { function: _+_ args: { - CALL [9] { + CALL [8] { function: _+_ args: { - IDENT [10] { - name: @index1 + IDENT [9] { + name: @index0 } - IDENT [11] { - name: @index1 + IDENT [10] { + name: @index0 } } } - CONSTANT [12] { value: 1 } + CONSTANT [11] { value: 1 } } } } } - CALL [13] { + CALL [12] { function: _==_ args: { - IDENT [14] { - name: @index2 + IDENT [13] { + name: @index1 } - CONSTANT [15] { value: 5 } + CONSTANT [14] { value: 5 } } } } @@ -58,55 +55,49 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_LIST [3] { - elements: { - CONSTANT [4] { value: 1 } - CONSTANT [5] { value: 2 } - } - } - CALL [6] { + CALL [3] { function: size args: { - IDENT [7] { - name: @index0 + CREATE_LIST [4] { + elements: { + CONSTANT [5] { value: 1 } + CONSTANT [6] { value: 2 } + } } } } - CALL [8] { + CALL [7] { function: _+_ args: { - CALL [9] { + CALL [8] { function: _+_ args: { - CONSTANT [10] { value: 2 } - IDENT [11] { - name: @index1 + CONSTANT [9] { value: 2 } + IDENT [10] { + name: @index0 } } } - IDENT [12] { - name: @index1 + IDENT [11] { + name: @index0 } } } + } + } + CALL [12] { + function: _==_ + args: { CALL [13] { function: _+_ args: { IDENT [14] { - name: @index2 + name: @index1 } CONSTANT [15] { value: 1 } } } - } - } - CALL [16] { - function: _==_ - args: { - IDENT [17] { - name: @index3 - } - CONSTANT [18] { value: 7 } + CONSTANT [16] { value: 7 } } } } @@ -119,72 +110,63 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_LIST [3] { - elements: { - CONSTANT [4] { value: 0 } - } - } - CALL [5] { + CALL [3] { function: size args: { - IDENT [6] { - name: @index0 + CREATE_LIST [4] { + elements: { + CONSTANT [5] { value: 0 } + } } } } - CREATE_LIST [7] { - elements: { - CONSTANT [8] { value: 1 } - CONSTANT [9] { value: 2 } - } - } - CALL [10] { + CALL [6] { function: size args: { - IDENT [11] { - name: @index2 + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 1 } + CONSTANT [9] { value: 2 } + } } } } - CALL [12] { + CALL [10] { function: _+_ args: { - CALL [13] { + CALL [11] { function: _+_ args: { - IDENT [14] { - name: @index1 + IDENT [12] { + name: @index0 } - IDENT [15] { - name: @index1 + IDENT [13] { + name: @index0 } } } - IDENT [16] { - name: @index3 + IDENT [14] { + name: @index1 } } } - CALL [17] { + } + } + CALL [15] { + function: _==_ + args: { + CALL [16] { function: _+_ args: { - IDENT [18] { - name: @index4 + IDENT [17] { + name: @index2 } - IDENT [19] { - name: @index3 + IDENT [18] { + name: @index1 } } } - } - } - CALL [20] { - function: _==_ - args: { - IDENT [21] { - name: @index5 - } - CONSTANT [22] { value: 6 } + CONSTANT [19] { value: 6 } } } } @@ -197,112 +179,103 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_LIST [3] { - elements: { - CONSTANT [4] { value: 0 } - } - } - CALL [5] { + CALL [3] { function: size args: { - IDENT [6] { - name: @index0 + CREATE_LIST [4] { + elements: { + CONSTANT [5] { value: 0 } + } } } } - CREATE_LIST [7] { - elements: { - CONSTANT [8] { value: 1 } - CONSTANT [9] { value: 2 } - } - } - CALL [10] { + CALL [6] { function: size args: { - IDENT [11] { - name: @index2 + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 1 } + CONSTANT [9] { value: 2 } + } } } } - CREATE_LIST [12] { - elements: { - CONSTANT [13] { value: 1 } - CONSTANT [14] { value: 2 } - CONSTANT [15] { value: 3 } - } - } - CALL [16] { + CALL [10] { function: size args: { - IDENT [17] { - name: @index4 + CREATE_LIST [11] { + elements: { + CONSTANT [12] { value: 1 } + CONSTANT [13] { value: 2 } + CONSTANT [14] { value: 3 } + } } } } - CALL [18] { + CALL [15] { function: _+_ args: { - CALL [19] { + CALL [16] { function: _+_ args: { - CONSTANT [20] { value: 5 } - IDENT [21] { - name: @index1 + CONSTANT [17] { value: 5 } + IDENT [18] { + name: @index0 } } } - IDENT [22] { - name: @index1 + IDENT [19] { + name: @index0 } } } - CALL [23] { + CALL [20] { function: _+_ args: { - CALL [24] { + CALL [21] { function: _+_ args: { - IDENT [25] { - name: @index6 - } - IDENT [26] { + IDENT [22] { name: @index3 } + IDENT [23] { + name: @index1 + } } } - IDENT [27] { - name: @index3 + IDENT [24] { + name: @index1 } } } - CALL [28] { + CALL [25] { function: _+_ args: { - CALL [29] { + CALL [26] { function: _+_ args: { - IDENT [30] { - name: @index7 + IDENT [27] { + name: @index4 } - IDENT [31] { - name: @index5 + IDENT [28] { + name: @index2 } } } - IDENT [32] { - name: @index5 + IDENT [29] { + name: @index2 } } } } } - CALL [33] { + CALL [30] { function: _==_ args: { - IDENT [34] { - name: @index8 + IDENT [31] { + name: @index5 } - CONSTANT [35] { value: 17 } + CONSTANT [32] { value: 17 } } } } @@ -316,154 +289,106 @@ CALL [1] { CREATE_LIST [2] { elements: { CALL [3] { - function: timestamp - args: { - CONSTANT [4] { value: 1000000000 } - } - } - CALL [5] { function: int args: { - IDENT [6] { - name: @index0 - } - } - } - CALL [7] { - function: timestamp - args: { - IDENT [8] { - name: @index1 + CALL [4] { + function: timestamp + args: { + CONSTANT [5] { value: 1000000000 } + } } } } - CALL [9] { + CALL [6] { function: getFullYear target: { - IDENT [10] { - name: @index2 + CALL [7] { + function: timestamp + args: { + IDENT [8] { + name: @index0 + } + } } } args: { } } - CALL [11] { - function: timestamp - args: { - CONSTANT [12] { value: 50 } - } - } - CALL [13] { + CALL [9] { function: int args: { - IDENT [14] { - name: @index4 - } - } - } - CALL [15] { - function: timestamp - args: { - IDENT [16] { - name: @index5 + CALL [10] { + function: timestamp + args: { + CONSTANT [11] { value: 50 } + } } } } - CALL [17] { - function: timestamp - args: { - CONSTANT [18] { value: 200 } - } - } - CALL [19] { + CALL [12] { function: int args: { - IDENT [20] { - name: @index7 - } - } - } - CALL [21] { - function: timestamp - args: { - IDENT [22] { - name: @index8 + CALL [13] { + function: timestamp + args: { + CONSTANT [14] { value: 200 } + } } } } - CALL [23] { + CALL [15] { function: getFullYear target: { - IDENT [24] { - name: @index9 - } - } - args: { - } - } - CALL [25] { - function: timestamp - args: { - CONSTANT [26] { value: 75 } - } - } - CALL [27] { - function: int - args: { - IDENT [28] { - name: @index11 - } - } - } - CALL [29] { - function: timestamp - args: { - IDENT [30] { - name: @index12 - } - } - } - CALL [31] { - function: getMinutes - target: { - IDENT [32] { - name: @index13 + CALL [16] { + function: timestamp + args: { + IDENT [17] { + name: @index3 + } + } } } args: { } } - CALL [33] { - function: getSeconds - target: { - IDENT [34] { - name: @index6 - } - } + CALL [18] { + function: int args: { + CALL [19] { + function: timestamp + args: { + CONSTANT [20] { value: 75 } + } + } } } - CALL [35] { - function: getFullYear - target: { - IDENT [36] { - name: @index6 + CALL [21] { + function: timestamp + args: { + IDENT [22] { + name: @index2 } } + } + CALL [23] { + function: timestamp args: { + IDENT [24] { + name: @index5 + } } } - CALL [37] { + CALL [25] { function: _+_ args: { - IDENT [38] { - name: @index3 + IDENT [26] { + name: @index1 } - CALL [39] { + CALL [27] { function: getFullYear target: { - IDENT [40] { - name: @index13 + IDENT [28] { + name: @index7 } } args: { @@ -471,83 +396,104 @@ CALL [1] { } } } - CALL [41] { + CALL [29] { function: _+_ args: { - CALL [42] { - function: _+_ - args: { - IDENT [43] { - name: @index17 - } - IDENT [44] { - name: @index16 + IDENT [30] { + name: @index8 + } + CALL [31] { + function: getFullYear + target: { + IDENT [32] { + name: @index6 } } - } - IDENT [45] { - name: @index3 + args: { + } } } } - CALL [46] { + CALL [33] { function: _+_ args: { - CALL [47] { + CALL [34] { function: _+_ args: { - IDENT [48] { - name: @index18 + IDENT [35] { + name: @index9 } - IDENT [49] { - name: @index15 + IDENT [36] { + name: @index1 } } } - IDENT [50] { - name: @index10 + CALL [37] { + function: getSeconds + target: { + IDENT [38] { + name: @index6 + } + } + args: { + } } } } - CALL [51] { + CALL [39] { function: _+_ args: { - CALL [52] { + CALL [40] { function: _+_ args: { - IDENT [53] { - name: @index19 - } - IDENT [54] { + IDENT [41] { name: @index10 } + IDENT [42] { + name: @index4 + } } } - IDENT [55] { - name: @index14 + IDENT [43] { + name: @index4 } } } - CALL [56] { + CALL [44] { function: _+_ args: { - IDENT [57] { - name: @index20 + IDENT [45] { + name: @index11 } - IDENT [58] { - name: @index3 + CALL [46] { + function: getMinutes + target: { + IDENT [47] { + name: @index7 + } + } + args: { + } } } } } } - CALL [59] { + CALL [48] { function: _==_ args: { - IDENT [60] { - name: @index21 + CALL [49] { + function: _+_ + args: { + IDENT [50] { + name: @index12 + } + IDENT [51] { + name: @index1 + } + } } - CONSTANT [61] { value: 13934 } + CONSTANT [52] { value: 13934 } } } } @@ -560,39 +506,36 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_MAP [3] { - MAP_ENTRY [4] { - key: { - CONSTANT [5] { value: "a" } - } - value: { - CONSTANT [6] { value: 2 } - } - } - } - CALL [7] { + CALL [3] { function: _[_] args: { - IDENT [8] { - name: @index0 + CREATE_MAP [4] { + MAP_ENTRY [5] { + key: { + CONSTANT [6] { value: "a" } + } + value: { + CONSTANT [7] { value: 2 } + } + } } - CONSTANT [9] { value: "a" } + CONSTANT [8] { value: "a" } } } - CALL [10] { + CALL [9] { function: _+_ args: { - IDENT [11] { - name: @index1 + IDENT [10] { + name: @index0 } - CALL [12] { + CALL [11] { function: _*_ args: { - IDENT [13] { - name: @index1 + IDENT [12] { + name: @index0 } - IDENT [14] { - name: @index1 + IDENT [13] { + name: @index0 } } } @@ -600,13 +543,13 @@ CALL [1] { } } } - CALL [15] { + CALL [14] { function: _==_ args: { - IDENT [16] { - name: @index2 + IDENT [15] { + name: @index1 } - CONSTANT [17] { value: 6 } + CONSTANT [16] { value: 6 } } } } @@ -622,51 +565,48 @@ CALL [1] { CREATE_MAP [3] { MAP_ENTRY [4] { key: { - CONSTANT [5] { value: "b" } + CONSTANT [5] { value: "e" } } value: { - CONSTANT [6] { value: 1 } + CREATE_MAP [6] { + MAP_ENTRY [7] { + key: { + CONSTANT [8] { value: "b" } + } + value: { + CONSTANT [9] { value: 1 } + } + } + } } } } - CREATE_MAP [7] { - MAP_ENTRY [8] { + CREATE_MAP [10] { + MAP_ENTRY [11] { key: { - CONSTANT [9] { value: "e" } + CONSTANT [12] { value: "b" } } value: { - IDENT [10] { - name: @index0 - } + CONSTANT [13] { value: 1 } } } } } } - CREATE_MAP [11] { - MAP_ENTRY [12] { - key: { - CONSTANT [13] { value: "a" } - } - value: { - IDENT [14] { - name: @index0 - } - } - } + CREATE_MAP [14] { MAP_ENTRY [15] { key: { - CONSTANT [16] { value: "c" } + CONSTANT [16] { value: "a" } } value: { IDENT [17] { - name: @index0 + name: @index1 } } } MAP_ENTRY [18] { key: { - CONSTANT [19] { value: "d" } + CONSTANT [19] { value: "c" } } value: { IDENT [20] { @@ -676,11 +616,21 @@ CALL [1] { } MAP_ENTRY [21] { key: { - CONSTANT [22] { value: "e" } + CONSTANT [22] { value: "d" } } value: { IDENT [23] { - name: @index1 + name: @index0 + } + } + } + MAP_ENTRY [24] { + key: { + CONSTANT [25] { value: "e" } + } + value: { + IDENT [26] { + name: @index0 } } } @@ -709,37 +659,34 @@ CALL [1] { CONSTANT [10] { value: 2 } } } - CREATE_LIST [11] { - elements: { - IDENT [12] { - name: @index1 - } - IDENT [13] { - name: @index0 - } - } - } } } - CREATE_LIST [14] { + CREATE_LIST [11] { elements: { - CONSTANT [15] { value: 1 } - IDENT [16] { + CONSTANT [12] { value: 1 } + IDENT [13] { name: @index0 } - CONSTANT [17] { value: 2 } - IDENT [18] { + CONSTANT [14] { value: 2 } + IDENT [15] { name: @index0 } - CONSTANT [19] { value: 5 } - IDENT [20] { + CONSTANT [16] { value: 5 } + IDENT [17] { name: @index0 } - CONSTANT [21] { value: 7 } - IDENT [22] { - name: @index2 + CONSTANT [18] { value: 7 } + CREATE_LIST [19] { + elements: { + IDENT [20] { + name: @index1 + } + IDENT [21] { + name: @index0 + } + } } - IDENT [23] { + IDENT [22] { name: @index1 } } @@ -759,26 +706,23 @@ CALL [1] { name: msg }.single_int64 } - CALL [5] { + } + } + CALL [5] { + function: _==_ + args: { + CALL [6] { function: _+_ args: { - IDENT [6] { + IDENT [7] { name: @index0 } - IDENT [7] { + IDENT [8] { name: @index0 } } } - } - } - CALL [8] { - function: _==_ - args: { - IDENT [9] { - name: @index1 - } - CONSTANT [10] { value: 6 } + CONSTANT [9] { value: 6 } } } } @@ -792,89 +736,80 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload - } - SELECT [7] { - IDENT [8] { - name: @index1 - }.single_int64 - } - SELECT [9] { - SELECT [10] { - IDENT [11] { - name: @index1 + SELECT [4] { + IDENT [5] { + name: msg }.oneof_type }.payload } - SELECT [12] { - IDENT [13] { - name: @index3 - }.single_int64 - } - SELECT [14] { - IDENT [15] { - name: msg + SELECT [6] { + IDENT [7] { + name: @index0 }.single_int64 } - CALL [16] { + CALL [8] { function: _+_ args: { - IDENT [17] { - name: @index2 + IDENT [9] { + name: @index1 } - SELECT [18] { - IDENT [19] { - name: @index1 + SELECT [10] { + IDENT [11] { + name: @index0 }.single_int32 } } } - CALL [20] { + CALL [12] { function: _+_ args: { - CALL [21] { + CALL [13] { function: _+_ args: { - IDENT [22] { - name: @index6 - } - IDENT [23] { + IDENT [14] { name: @index2 } + IDENT [15] { + name: @index1 + } } } - IDENT [24] { - name: @index5 + SELECT [16] { + IDENT [17] { + name: msg + }.single_int64 } } } - CALL [25] { + SELECT [18] { + SELECT [19] { + IDENT [20] { + name: @index0 + }.oneof_type + }.payload + } + CALL [21] { function: _+_ args: { - IDENT [26] { - name: @index7 + IDENT [22] { + name: @index3 } - IDENT [27] { - name: @index4 + SELECT [23] { + IDENT [24] { + name: @index4 + }.single_int64 } } } } } - CALL [28] { + CALL [25] { function: _==_ args: { - IDENT [29] { - name: @index8 + IDENT [26] { + name: @index5 } - CONSTANT [30] { value: 31 } + CONSTANT [27] { value: 31 } } } } @@ -888,76 +823,67 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 + SELECT [4] { + IDENT [5] { + name: msg + }.oneof_type }.payload } - SELECT [7] { - IDENT [8] { - name: @index1 - }.oneof_type + SELECT [6] { + SELECT [7] { + IDENT [8] { + name: @index0 + }.oneof_type + }.payload } SELECT [9] { IDENT [10] { - name: @index2 - }.payload + name: @index1 + }.oneof_type } SELECT [11] { - IDENT [12] { - name: @index3 + SELECT [12] { + IDENT [13] { + name: @index2 + }.payload }.oneof_type } - SELECT [13] { - SELECT [14] { - IDENT [15] { - name: @index4 - }.child - }.child - } - SELECT [16] { - SELECT [17] { - IDENT [18] { - name: @index5 + SELECT [14] { + SELECT [15] { + IDENT [16] { + name: @index3 }.payload }.single_bool } - SELECT [19] { - SELECT [20] { - IDENT [21] { - name: @index4 - }.payload - }.oneof_type + SELECT [17] { + SELECT [18] { + IDENT [19] { + name: @index2 + }.child + }.child } - SELECT [22] { - SELECT [23] { - IDENT [24] { - name: @index7 + SELECT [20] { + SELECT [21] { + IDENT [22] { + name: @index5 }.payload }.single_bool } - CALL [25] { - function: _||_ - args: { - CONSTANT [26] { value: true } - IDENT [27] { - name: @index8 - } - } - } } } - CALL [28] { + CALL [23] { function: _||_ args: { - IDENT [29] { - name: @index9 + CALL [24] { + function: _||_ + args: { + CONSTANT [25] { value: true } + IDENT [26] { + name: @index4 + } + } } - IDENT [30] { + IDENT [27] { name: @index6 } } @@ -973,57 +899,51 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 + SELECT [4] { + IDENT [5] { + name: msg + }.oneof_type }.payload } - SELECT [7] { - IDENT [8] { - name: @index1 - }.map_int32_int64 - } - CALL [9] { + CALL [6] { function: _[_] args: { - IDENT [10] { - name: @index2 + SELECT [7] { + IDENT [8] { + name: @index0 + }.map_int32_int64 } - CONSTANT [11] { value: 1 } + CONSTANT [9] { value: 1 } } } - CALL [12] { + CALL [10] { function: _+_ args: { - CALL [13] { + CALL [11] { function: _+_ args: { - IDENT [14] { - name: @index3 + IDENT [12] { + name: @index1 } - IDENT [15] { - name: @index3 + IDENT [13] { + name: @index1 } } } - IDENT [16] { - name: @index3 + IDENT [14] { + name: @index1 } } } } } - CALL [17] { + CALL [15] { function: _==_ args: { - IDENT [18] { - name: @index4 + IDENT [16] { + name: @index2 } - CONSTANT [19] { value: 15 } + CONSTANT [17] { value: 15 } } } } @@ -1037,72 +957,66 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 + SELECT [4] { + IDENT [5] { + name: msg + }.oneof_type }.payload } - SELECT [7] { - IDENT [8] { - name: @index1 + SELECT [6] { + IDENT [7] { + name: @index0 }.map_int32_int64 } - CALL [9] { - function: _[_] - args: { - IDENT [10] { - name: @index2 - } - CONSTANT [11] { value: 2 } - } - } - CALL [12] { + CALL [8] { function: _+_ args: { - CALL [13] { + CALL [9] { function: _[_] args: { - IDENT [14] { - name: @index2 + IDENT [10] { + name: @index1 } - CONSTANT [15] { value: 0 } + CONSTANT [11] { value: 0 } } } - CALL [16] { + CALL [12] { function: _[_] args: { - IDENT [17] { - name: @index2 + IDENT [13] { + name: @index1 } - CONSTANT [18] { value: 1 } + CONSTANT [14] { value: 1 } } } } } - CALL [19] { + CALL [15] { function: _+_ args: { - IDENT [20] { - name: @index4 + IDENT [16] { + name: @index2 } - IDENT [21] { - name: @index3 + CALL [17] { + function: _[_] + args: { + IDENT [18] { + name: @index1 + } + CONSTANT [19] { value: 2 } + } } } } } } - CALL [22] { + CALL [20] { function: _==_ args: { - IDENT [23] { - name: @index5 + IDENT [21] { + name: @index3 } - CONSTANT [24] { value: 8 } + CONSTANT [22] { value: 8 } } } } @@ -1338,18 +1252,21 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_LIST [3] { - elements: { - CONSTANT [4] { value: 1 } - } - } - CALL [5] { - function: _>_ + CALL [3] { + function: _||_ args: { - IDENT [6] { - name: @c0:0 + IDENT [4] { + name: @x0:0 + } + CALL [5] { + function: _>_ + args: { + IDENT [6] { + name: @c0:0 + } + CONSTANT [7] { value: 0 } + } } - CONSTANT [7] { value: 0 } } } CALL [8] { @@ -1358,74 +1275,65 @@ CALL [1] { IDENT [9] { name: @x0:0 } - IDENT [10] { - name: @index1 + CALL [10] { + function: _>_ + args: { + IDENT [11] { + name: @c0:0 + } + CONSTANT [12] { value: 1 } + } } } } - CREATE_LIST [11] { + CREATE_LIST [13] { elements: { - CONSTANT [12] { value: 2 } - } - } - CALL [13] { - function: _>_ - args: { - IDENT [14] { - name: @c0:0 - } - CONSTANT [15] { value: 1 } + CONSTANT [14] { value: 1 } } } - CALL [16] { - function: _||_ - args: { - IDENT [17] { - name: @x0:0 - } - IDENT [18] { - name: @index4 - } + CREATE_LIST [15] { + elements: { + CONSTANT [16] { value: 2 } } } } } - CALL [19] { + CALL [17] { function: _==_ args: { - CALL [20] { + CALL [18] { function: _+_ args: { - CALL [21] { + CALL [19] { function: _+_ args: { - CALL [22] { + CALL [20] { function: _+_ args: { - CALL [23] { + CALL [21] { function: size args: { - CREATE_LIST [24] { + CREATE_LIST [22] { elements: { - COMPREHENSION [25] { + COMPREHENSION [23] { iter_var: @c0:0 iter_range: { - IDENT [26] { - name: @index0 + IDENT [24] { + name: @index2 } } accu_var: @x0:0 accu_init: { - CONSTANT [27] { value: false } + CONSTANT [25] { value: false } } loop_condition: { - CALL [28] { + CALL [26] { function: @not_strictly_false args: { - CALL [29] { + CALL [27] { function: !_ args: { - IDENT [30] { + IDENT [28] { name: @x0:0 } } @@ -1434,12 +1342,12 @@ CALL [1] { } } loop_step: { - IDENT [31] { - name: @index2 + IDENT [29] { + name: @index0 } } result: { - IDENT [32] { + IDENT [30] { name: @x0:0 } } @@ -1448,30 +1356,30 @@ CALL [1] { } } } - CALL [33] { + CALL [31] { function: size args: { - CREATE_LIST [34] { + CREATE_LIST [32] { elements: { - COMPREHENSION [35] { + COMPREHENSION [33] { iter_var: @c0:0 iter_range: { - IDENT [36] { - name: @index0 + IDENT [34] { + name: @index2 } } accu_var: @x0:0 accu_init: { - CONSTANT [37] { value: false } + CONSTANT [35] { value: false } } loop_condition: { - CALL [38] { + CALL [36] { function: @not_strictly_false args: { - CALL [39] { + CALL [37] { function: !_ args: { - IDENT [40] { + IDENT [38] { name: @x0:0 } } @@ -1480,12 +1388,12 @@ CALL [1] { } } loop_step: { - IDENT [41] { - name: @index2 + IDENT [39] { + name: @index0 } } result: { - IDENT [42] { + IDENT [40] { name: @x0:0 } } @@ -1496,30 +1404,30 @@ CALL [1] { } } } - CALL [43] { + CALL [41] { function: size args: { - CREATE_LIST [44] { + CREATE_LIST [42] { elements: { - COMPREHENSION [45] { + COMPREHENSION [43] { iter_var: @c0:0 iter_range: { - IDENT [46] { + IDENT [44] { name: @index3 } } accu_var: @x0:0 accu_init: { - CONSTANT [47] { value: false } + CONSTANT [45] { value: false } } loop_condition: { - CALL [48] { + CALL [46] { function: @not_strictly_false args: { - CALL [49] { + CALL [47] { function: !_ args: { - IDENT [50] { + IDENT [48] { name: @x0:0 } } @@ -1528,12 +1436,12 @@ CALL [1] { } } loop_step: { - IDENT [51] { - name: @index5 + IDENT [49] { + name: @index1 } } result: { - IDENT [52] { + IDENT [50] { name: @x0:0 } } @@ -1544,30 +1452,30 @@ CALL [1] { } } } - CALL [53] { + CALL [51] { function: size args: { - CREATE_LIST [54] { + CREATE_LIST [52] { elements: { - COMPREHENSION [55] { + COMPREHENSION [53] { iter_var: @c0:0 iter_range: { - IDENT [56] { + IDENT [54] { name: @index3 } } accu_var: @x0:0 accu_init: { - CONSTANT [57] { value: false } + CONSTANT [55] { value: false } } loop_condition: { - CALL [58] { + CALL [56] { function: @not_strictly_false args: { - CALL [59] { + CALL [57] { function: !_ args: { - IDENT [60] { + IDENT [58] { name: @x0:0 } } @@ -1576,12 +1484,12 @@ CALL [1] { } } loop_step: { - IDENT [61] { - name: @index5 + IDENT [59] { + name: @index1 } } result: { - IDENT [62] { + IDENT [60] { name: @x0:0 } } @@ -1592,112 +1500,106 @@ CALL [1] { } } } - CONSTANT [63] { value: 4 } + CONSTANT [61] { value: 4 } } } } } Test case: MULTIPLE_MACROS_2 Source: [[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == 'a')] + [['a'].exists(l, l == 'a')] == [true, true, true, true] -=====> -CALL [1] { - function: cel.@block - args: { - CREATE_LIST [2] { - elements: { - CREATE_LIST [3] { - elements: { - CONSTANT [4] { value: 1 } - } - } - CALL [5] { - function: _>_ +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CALL [3] { + function: _||_ args: { - IDENT [6] { - name: @c0:0 + IDENT [4] { + name: @x0:0 + } + CALL [5] { + function: _>_ + args: { + IDENT [6] { + name: @c0:0 + } + CONSTANT [7] { value: 0 } + } } - CONSTANT [7] { value: 0 } } } CALL [8] { function: _||_ args: { IDENT [9] { - name: @x0:0 + name: @x0:1 } - IDENT [10] { - name: @index1 + CALL [10] { + function: _==_ + args: { + IDENT [11] { + name: @c0:1 + } + CONSTANT [12] { value: "a" } + } } } } - CREATE_LIST [11] { + CREATE_LIST [13] { elements: { - CONSTANT [12] { value: "a" } - } - } - CALL [13] { - function: _==_ - args: { - IDENT [14] { - name: @c0:1 - } - CONSTANT [15] { value: "a" } + CONSTANT [14] { value: 1 } } } - CALL [16] { - function: _||_ - args: { - IDENT [17] { - name: @x0:1 - } - IDENT [18] { - name: @index4 - } + CREATE_LIST [15] { + elements: { + CONSTANT [16] { value: "a" } } } - CREATE_LIST [19] { + CREATE_LIST [17] { elements: { + CONSTANT [18] { value: true } + CONSTANT [19] { value: true } CONSTANT [20] { value: true } CONSTANT [21] { value: true } - CONSTANT [22] { value: true } - CONSTANT [23] { value: true } } } } } - CALL [24] { + CALL [22] { function: _==_ args: { - CALL [25] { + CALL [23] { function: _+_ args: { - CALL [26] { + CALL [24] { function: _+_ args: { - CALL [27] { + CALL [25] { function: _+_ args: { - CREATE_LIST [28] { + CREATE_LIST [26] { elements: { - COMPREHENSION [29] { + COMPREHENSION [27] { iter_var: @c0:0 iter_range: { - IDENT [30] { - name: @index0 + IDENT [28] { + name: @index2 } } accu_var: @x0:0 accu_init: { - CONSTANT [31] { value: false } + CONSTANT [29] { value: false } } loop_condition: { - CALL [32] { + CALL [30] { function: @not_strictly_false args: { - CALL [33] { + CALL [31] { function: !_ args: { - IDENT [34] { + IDENT [32] { name: @x0:0 } } @@ -1706,39 +1608,39 @@ CALL [1] { } } loop_step: { - IDENT [35] { - name: @index2 + IDENT [33] { + name: @index0 } } result: { - IDENT [36] { + IDENT [34] { name: @x0:0 } } } } } - CREATE_LIST [37] { + CREATE_LIST [35] { elements: { - COMPREHENSION [38] { + COMPREHENSION [36] { iter_var: @c0:0 iter_range: { - IDENT [39] { - name: @index0 + IDENT [37] { + name: @index2 } } accu_var: @x0:0 accu_init: { - CONSTANT [40] { value: false } + CONSTANT [38] { value: false } } loop_condition: { - CALL [41] { + CALL [39] { function: @not_strictly_false args: { - CALL [42] { + CALL [40] { function: !_ args: { - IDENT [43] { + IDENT [41] { name: @x0:0 } } @@ -1747,12 +1649,12 @@ CALL [1] { } } loop_step: { - IDENT [44] { - name: @index2 + IDENT [42] { + name: @index0 } } result: { - IDENT [45] { + IDENT [43] { name: @x0:0 } } @@ -1761,27 +1663,27 @@ CALL [1] { } } } - CREATE_LIST [46] { + CREATE_LIST [44] { elements: { - COMPREHENSION [47] { + COMPREHENSION [45] { iter_var: @c0:1 iter_range: { - IDENT [48] { + IDENT [46] { name: @index3 } } accu_var: @x0:1 accu_init: { - CONSTANT [49] { value: false } + CONSTANT [47] { value: false } } loop_condition: { - CALL [50] { + CALL [48] { function: @not_strictly_false args: { - CALL [51] { + CALL [49] { function: !_ args: { - IDENT [52] { + IDENT [50] { name: @x0:1 } } @@ -1790,12 +1692,12 @@ CALL [1] { } } loop_step: { - IDENT [53] { - name: @index5 + IDENT [51] { + name: @index1 } } result: { - IDENT [54] { + IDENT [52] { name: @x0:1 } } @@ -1804,27 +1706,27 @@ CALL [1] { } } } - CREATE_LIST [55] { + CREATE_LIST [53] { elements: { - COMPREHENSION [56] { + COMPREHENSION [54] { iter_var: @c0:1 iter_range: { - IDENT [57] { + IDENT [55] { name: @index3 } } accu_var: @x0:1 accu_init: { - CONSTANT [58] { value: false } + CONSTANT [56] { value: false } } loop_condition: { - CALL [59] { + CALL [57] { function: @not_strictly_false args: { - CALL [60] { + CALL [58] { function: !_ args: { - IDENT [61] { + IDENT [59] { name: @x0:1 } } @@ -1833,12 +1735,12 @@ CALL [1] { } } loop_step: { - IDENT [62] { - name: @index5 + IDENT [60] { + name: @index1 } } result: { - IDENT [63] { + IDENT [61] { name: @x0:1 } } @@ -1847,8 +1749,8 @@ CALL [1] { } } } - IDENT [64] { - name: @index6 + IDENT [62] { + name: @index4 } } } @@ -1878,119 +1780,116 @@ CALL [1] { } CREATE_LIST [11] { elements: { - IDENT [12] { - name: @index1 - } - IDENT [13] { - name: @index1 - } - IDENT [14] { - name: @index1 - } - } - } - CREATE_LIST [15] { - elements: { - CALL [16] { + CALL [12] { function: _+_ args: { - IDENT [17] { + IDENT [13] { name: @c1:0 } - CONSTANT [18] { value: 1 } + CONSTANT [14] { value: 1 } } } } } - COMPREHENSION [19] { + COMPREHENSION [15] { iter_var: @c1:0 iter_range: { - IDENT [20] { + IDENT [16] { name: @index0 } } accu_var: @x1:0 accu_init: { - CREATE_LIST [21] { + CREATE_LIST [17] { elements: { } } } loop_condition: { - CONSTANT [22] { value: true } + CONSTANT [18] { value: true } } loop_step: { - CALL [23] { + CALL [19] { function: _+_ args: { - IDENT [24] { + IDENT [20] { name: @x1:0 } - IDENT [25] { - name: @index3 + IDENT [21] { + name: @index2 } } } } result: { - IDENT [26] { + IDENT [22] { name: @x1:0 } } } - CALL [27] { + CALL [23] { function: _+_ args: { - IDENT [28] { + IDENT [24] { name: @x0:0 } - CREATE_LIST [29] { + CREATE_LIST [25] { elements: { - IDENT [30] { - name: @index4 + IDENT [26] { + name: @index3 } } } } } - COMPREHENSION [31] { + COMPREHENSION [27] { iter_var: @c0:0 iter_range: { - IDENT [32] { + IDENT [28] { name: @index0 } } accu_var: @x0:0 accu_init: { - CREATE_LIST [33] { + CREATE_LIST [29] { elements: { } } } loop_condition: { - CONSTANT [34] { value: true } + CONSTANT [30] { value: true } } loop_step: { - IDENT [35] { - name: @index5 + IDENT [31] { + name: @index4 } } result: { - IDENT [36] { + IDENT [32] { name: @x0:0 } } } } } - CALL [37] { + CALL [33] { function: _==_ args: { - IDENT [38] { - name: @index6 + IDENT [34] { + name: @index5 } - IDENT [39] { - name: @index2 + CREATE_LIST [35] { + elements: { + IDENT [36] { + name: @index1 + } + IDENT [37] { + name: @index1 + } + IDENT [38] { + name: @index1 + } + } } } } @@ -2004,145 +1903,145 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_LIST [3] { - elements: { - CREATE_LIST [4] { - elements: { - CONSTANT [5] { value: 1 } - } - } - CREATE_LIST [6] { - elements: { - CONSTANT [7] { value: 2 } - } - } - } - } - CALL [8] { + CALL [3] { function: _+_ args: { - IDENT [9] { + IDENT [4] { name: @x1:0 } - CREATE_LIST [10] { + CREATE_LIST [5] { elements: { - IDENT [11] { + IDENT [6] { name: @c1:0 } } } } } - CALL [12] { + CALL [7] { function: _?_:_ args: { - CALL [13] { + CALL [8] { function: _==_ args: { - IDENT [14] { + IDENT [9] { name: @c1:0 } - IDENT [15] { + IDENT [10] { name: @c0:0 } } } - IDENT [16] { - name: @index1 + IDENT [11] { + name: @index0 } - IDENT [17] { + IDENT [12] { name: @x1:0 } } } - COMPREHENSION [18] { + COMPREHENSION [13] { iter_var: @c1:0 iter_range: { - CREATE_LIST [19] { + CREATE_LIST [14] { elements: { - CONSTANT [20] { value: 1 } - CONSTANT [21] { value: 2 } - CONSTANT [22] { value: 3 } + CONSTANT [15] { value: 1 } + CONSTANT [16] { value: 2 } + CONSTANT [17] { value: 3 } } } } accu_var: @x1:0 accu_init: { - CREATE_LIST [23] { + CREATE_LIST [18] { elements: { } } } loop_condition: { - CONSTANT [24] { value: true } + CONSTANT [19] { value: true } } loop_step: { - IDENT [25] { - name: @index2 + IDENT [20] { + name: @index1 } } result: { - IDENT [26] { + IDENT [21] { name: @x1:0 } } } - CALL [27] { + CALL [22] { function: _+_ args: { - IDENT [28] { + IDENT [23] { name: @x0:0 } - CREATE_LIST [29] { + CREATE_LIST [24] { elements: { - IDENT [30] { - name: @index3 + IDENT [25] { + name: @index2 } } } } } - COMPREHENSION [31] { + COMPREHENSION [26] { iter_var: @c0:0 iter_range: { - CREATE_LIST [32] { + CREATE_LIST [27] { elements: { - CONSTANT [33] { value: 1 } - CONSTANT [34] { value: 2 } + CONSTANT [28] { value: 1 } + CONSTANT [29] { value: 2 } } } } accu_var: @x0:0 accu_init: { - CREATE_LIST [35] { + CREATE_LIST [30] { elements: { } } } loop_condition: { - CONSTANT [36] { value: true } + CONSTANT [31] { value: true } } loop_step: { - IDENT [37] { - name: @index4 + IDENT [32] { + name: @index3 } } result: { - IDENT [38] { + IDENT [33] { name: @x0:0 } } } + CREATE_LIST [34] { + elements: { + CREATE_LIST [35] { + elements: { + CONSTANT [36] { value: 1 } + } + } + CREATE_LIST [37] { + elements: { + CONSTANT [38] { value: 2 } + } + } + } + } } } CALL [39] { function: _==_ args: { IDENT [40] { - name: @index5 + name: @index4 } IDENT [41] { - name: @index0 + name: @index5 } } } @@ -2156,59 +2055,52 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_LIST [3] { - elements: { - CONSTANT [4] { value: 1 } - CONSTANT [5] { value: 2 } - CONSTANT [6] { value: 3 } - } - } - CALL [7] { - function: @in - args: { - CONSTANT [8] { value: 1 } - IDENT [9] { - name: @index0 - } - } - } - CALL [10] { + CALL [3] { function: @in args: { - CONSTANT [11] { value: 3 } - CREATE_LIST [12] { + CONSTANT [4] { value: 1 } + CREATE_LIST [5] { elements: { - CONSTANT [13] { value: 3 } - IDENT [14] { - name: @index0 - } + CONSTANT [6] { value: 1 } + CONSTANT [7] { value: 2 } + CONSTANT [8] { value: 3 } } } } } - CALL [15] { + CREATE_LIST [9] { + elements: { + CONSTANT [10] { value: 1 } + CONSTANT [11] { value: 2 } + CONSTANT [12] { value: 3 } + } + } + CALL [13] { function: _&&_ args: { - IDENT [16] { - name: @index2 + IDENT [14] { + name: @index0 } - IDENT [17] { - name: @index1 + CALL [15] { + function: @in + args: { + CONSTANT [16] { value: 2 } + IDENT [17] { + name: @index1 + } + } } } } CALL [18] { - function: _&&_ + function: @in args: { - IDENT [19] { - name: @index1 - } - CALL [20] { - function: @in - args: { - CONSTANT [21] { value: 2 } + CONSTANT [19] { value: 3 } + CREATE_LIST [20] { + elements: { + CONSTANT [21] { value: 3 } IDENT [22] { - name: @index0 + name: @index1 } } } @@ -2220,10 +2112,18 @@ CALL [1] { function: _&&_ args: { IDENT [24] { - name: @index4 + name: @index2 } - IDENT [25] { - name: @index3 + CALL [25] { + function: _&&_ + args: { + IDENT [26] { + name: @index3 + } + IDENT [27] { + name: @index0 + } + } } } } @@ -2247,31 +2147,37 @@ CALL [1] { } } } - CREATE_MAP [7] { - MAP_ENTRY [8] { + } + } + CALL [7] { + function: @in + args: { + CONSTANT [8] { value: 2 } + CREATE_MAP [9] { + MAP_ENTRY [10] { key: { - CONSTANT [9] { value: "a" } + CONSTANT [11] { value: "a" } } value: { - CONSTANT [10] { value: 1 } + CONSTANT [12] { value: 1 } } } - MAP_ENTRY [11] { + MAP_ENTRY [13] { key: { - CONSTANT [12] { value: 2 } + CONSTANT [14] { value: 2 } } value: { - IDENT [13] { + IDENT [15] { name: @index0 } } } - MAP_ENTRY [14] { + MAP_ENTRY [16] { key: { - CONSTANT [15] { value: 3 } + CONSTANT [17] { value: 3 } } value: { - IDENT [16] { + IDENT [18] { name: @index0 } } @@ -2279,15 +2185,6 @@ CALL [1] { } } } - CALL [17] { - function: @in - args: { - CONSTANT [18] { value: 2 } - IDENT [19] { - name: @index1 - } - } - } } } Test case: MACRO_ITER_VAR_NOT_REFERENCED @@ -2300,71 +2197,64 @@ CALL [1] { elements: { CREATE_LIST [3] { elements: { - CONSTANT [4] { value: 1 } - CONSTANT [5] { value: 2 } - } - } - CREATE_LIST [6] { - elements: { - CONSTANT [7] { value: 3 } - CONSTANT [8] { value: 4 } - } - } - CREATE_LIST [9] { - elements: { - IDENT [10] { - name: @index1 + CREATE_LIST [4] { + elements: { + CONSTANT [5] { value: 3 } + CONSTANT [6] { value: 4 } + } } - IDENT [11] { - name: @index1 + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 3 } + CONSTANT [9] { value: 4 } + } } } } - CREATE_LIST [12] { + CREATE_LIST [10] { elements: { - IDENT [13] { - name: @index2 - } - IDENT [14] { - name: @index2 - } + CONSTANT [11] { value: 1 } + CONSTANT [12] { value: 2 } } } - CALL [15] { - function: _+_ - args: { - IDENT [16] { - name: @x1:0 - } - CREATE_LIST [17] { + CREATE_LIST [13] { + elements: { + CREATE_LIST [14] { elements: { - IDENT [18] { - name: @index1 - } + CONSTANT [15] { value: 3 } + CONSTANT [16] { value: 4 } } } } } - COMPREHENSION [19] { + COMPREHENSION [17] { iter_var: @c1:0 iter_range: { - IDENT [20] { - name: @index0 + IDENT [18] { + name: @index1 } } accu_var: @x1:0 accu_init: { - CREATE_LIST [21] { + CREATE_LIST [19] { elements: { } } } loop_condition: { - CONSTANT [22] { value: true } + CONSTANT [20] { value: true } } loop_step: { - IDENT [23] { - name: @index4 + CALL [21] { + function: _+_ + args: { + IDENT [22] { + name: @x1:0 + } + IDENT [23] { + name: @index2 + } + } } } result: { @@ -2382,7 +2272,7 @@ CALL [1] { CREATE_LIST [27] { elements: { IDENT [28] { - name: @index5 + name: @index3 } } } @@ -2392,7 +2282,7 @@ CALL [1] { iter_var: @c0:0 iter_range: { IDENT [30] { - name: @index0 + name: @index1 } } accu_var: @x0:0 @@ -2407,7 +2297,7 @@ CALL [1] { } loop_step: { IDENT [33] { - name: @index6 + name: @index4 } } result: { @@ -2422,10 +2312,17 @@ CALL [1] { function: _==_ args: { IDENT [36] { - name: @index7 + name: @index5 } - IDENT [37] { - name: @index3 + CREATE_LIST [37] { + elements: { + IDENT [38] { + name: @index0 + } + IDENT [39] { + name: @index0 + } + } } } } @@ -2440,89 +2337,95 @@ CALL [1] { CREATE_LIST [2] { elements: { CALL [3] { - function: _-_ + function: _>_ args: { - IDENT [4] { - name: x + CALL [4] { + function: _-_ + args: { + IDENT [5] { + name: x + } + CONSTANT [6] { value: 1 } + } } - CONSTANT [5] { value: 1 } + CONSTANT [7] { value: 3 } } } - CALL [6] { - function: _>_ + CALL [8] { + function: _?_:_ args: { - IDENT [7] { + IDENT [9] { name: @index0 } - CONSTANT [8] { value: 3 } + CALL [10] { + function: _-_ + args: { + IDENT [11] { + name: x + } + CONSTANT [12] { value: 1 } + } + } + CONSTANT [13] { value: 5 } } } - CALL [9] { + CALL [14] { function: _>_ args: { - CALL [10] { + CALL [15] { function: _-_ args: { - IDENT [11] { + IDENT [16] { name: @c0:0 } - CONSTANT [12] { value: 1 } + CONSTANT [17] { value: 1 } } } - CONSTANT [13] { value: 3 } + CONSTANT [18] { value: 3 } } } - CALL [14] { + CREATE_LIST [19] { + elements: { + IDENT [20] { + name: @index1 + } + } + } + CALL [21] { function: _||_ args: { - IDENT [15] { + IDENT [22] { name: @x0:0 } - IDENT [16] { + IDENT [23] { name: @index2 } } } - CREATE_LIST [17] { - elements: { - CALL [18] { - function: _?_:_ - args: { - IDENT [19] { - name: @index1 - } - IDENT [20] { - name: @index0 - } - CONSTANT [21] { value: 5 } - } - } - } - } } } - CALL [22] { + CALL [24] { function: _||_ args: { - COMPREHENSION [23] { + COMPREHENSION [25] { iter_var: @c0:0 iter_range: { - IDENT [24] { - name: @index4 + IDENT [26] { + name: @index3 } } accu_var: @x0:0 accu_init: { - CONSTANT [25] { value: false } + CONSTANT [27] { value: false } } loop_condition: { - CALL [26] { + CALL [28] { function: @not_strictly_false args: { - CALL [27] { + CALL [29] { function: !_ args: { - IDENT [28] { + IDENT [30] { name: @x0:0 } } @@ -2531,18 +2434,18 @@ CALL [1] { } } loop_step: { - IDENT [29] { - name: @index3 + IDENT [31] { + name: @index4 } } result: { - IDENT [30] { + IDENT [32] { name: @x0:0 } } } - IDENT [31] { - name: @index1 + IDENT [33] { + name: @index0 } } } @@ -2583,105 +2486,102 @@ CALL [1] { CREATE_LIST [10] { elements: { IDENT [11] { - name: @index1 - } - IDENT [12] { - name: @index1 - } - } - } - } - } - CALL [13] { - function: _+_ - args: { - IDENT [14] { - name: @x0:0 - } - IDENT [15] { - name: @index2 - } - } - } - CREATE_LIST [16] { - elements: { - CREATE_LIST [17] { - elements: { - IDENT [18] { name: @index0 } - IDENT [19] { + IDENT [12] { name: @index0 } } } } } - COMPREHENSION [20] { + COMPREHENSION [13] { iter_var: @c1:0 iter_range: { - CREATE_LIST [21] { + CREATE_LIST [14] { elements: { - CONSTANT [22] { value: "foo" } - CONSTANT [23] { value: "bar" } + CONSTANT [15] { value: "foo" } + CONSTANT [16] { value: "bar" } } } } accu_var: @x1:0 accu_init: { - CREATE_LIST [24] { + CREATE_LIST [17] { elements: { } } } loop_condition: { - CONSTANT [25] { value: true } + CONSTANT [18] { value: true } } loop_step: { - CALL [26] { + CALL [19] { function: _+_ args: { - IDENT [27] { + IDENT [20] { name: @x1:0 } - IDENT [28] { - name: @index4 + IDENT [21] { + name: @index2 } } } } result: { - IDENT [29] { + IDENT [22] { name: @x1:0 } } } + CREATE_LIST [23] { + elements: { + CREATE_LIST [24] { + elements: { + IDENT [25] { + name: @index1 + } + IDENT [26] { + name: @index1 + } + } + } + } + } } } - COMPREHENSION [30] { + COMPREHENSION [27] { iter_var: @c0:0 iter_range: { - IDENT [31] { - name: @index5 + IDENT [28] { + name: @index3 } } accu_var: @x0:0 accu_init: { - CREATE_LIST [32] { + CREATE_LIST [29] { elements: { } } } loop_condition: { - CONSTANT [33] { value: true } + CONSTANT [30] { value: true } } loop_step: { - IDENT [34] { - name: @index3 + CALL [31] { + function: _+_ + args: { + IDENT [32] { + name: @x0:0 + } + IDENT [33] { + name: @index4 + } + } } } result: { - IDENT [35] { + IDENT [34] { name: @x0:0 } } @@ -2706,27 +2606,24 @@ CALL [1] { } } } - CALL [7] { - function: _[_] - args: { - IDENT [8] { - name: @index0 - } - CONSTANT [9] { value: "a" } - } - } } } - CALL [10] { + CALL [7] { function: _&&_ args: { - SELECT [11] { - IDENT [12] { + SELECT [8] { + IDENT [9] { name: @index0 }.a~presence_test } - IDENT [13] { - name: @index1 + CALL [10] { + function: _[_] + args: { + IDENT [11] { + name: @index0 + } + CONSTANT [12] { value: "a" } + } } } } @@ -2788,51 +2685,53 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 + SELECT [4] { + IDENT [5] { + name: msg + }.oneof_type }.payload } - SELECT [7] { - IDENT [8] { - name: @index1 + SELECT [6] { + IDENT [7] { + name: @index0 }.single_int64 } - CALL [9] { + SELECT [8] { + IDENT [9] { + name: msg + }.oneof_type + } + CALL [10] { function: _?_:_ args: { - SELECT [10] { - IDENT [11] { - name: @index0 + SELECT [11] { + IDENT [12] { + name: @index2 }.payload~presence_test } - IDENT [12] { - name: @index2 + IDENT [13] { + name: @index1 } - CALL [13] { + CALL [14] { function: _*_ args: { - IDENT [14] { - name: @index2 + IDENT [15] { + name: @index1 } - CONSTANT [15] { value: 0 } + CONSTANT [16] { value: 0 } } } } } } } - CALL [16] { + CALL [17] { function: _==_ args: { - IDENT [17] { + IDENT [18] { name: @index3 } - CONSTANT [18] { value: 10 } + CONSTANT [19] { value: 10 } } } } @@ -2846,51 +2745,48 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 + SELECT [4] { + IDENT [5] { + name: msg + }.oneof_type }.payload } - SELECT [7] { - IDENT [8] { - name: @index1 + SELECT [6] { + IDENT [7] { + name: @index0 }.single_int64 } - CALL [9] { + CALL [8] { function: _?_:_ args: { - SELECT [10] { - IDENT [11] { - name: @index1 + SELECT [9] { + IDENT [10] { + name: @index0 }.single_int64~presence_test } - IDENT [12] { - name: @index2 + IDENT [11] { + name: @index1 } - CALL [13] { + CALL [12] { function: _*_ args: { - IDENT [14] { - name: @index2 + IDENT [13] { + name: @index1 } - CONSTANT [15] { value: 0 } + CONSTANT [14] { value: 0 } } } } } } } - CALL [16] { + CALL [15] { function: _==_ args: { - IDENT [17] { - name: @index3 + IDENT [16] { + name: @index2 } - CONSTANT [18] { value: 10 } + CONSTANT [17] { value: 10 } } } } @@ -2904,96 +2800,95 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 + SELECT [4] { + IDENT [5] { + name: msg + }.oneof_type }.payload } - SELECT [7] { - IDENT [8] { - name: @index1 + SELECT [6] { + IDENT [7] { + name: @index0 }.map_string_string } - CALL [9] { - function: _==_ + CALL [8] { + function: _&&_ args: { - SELECT [10] { - IDENT [11] { - name: @index2 - }.key + SELECT [9] { + IDENT [10] { + name: @index0 + }.map_string_string~presence_test + } + SELECT [11] { + IDENT [12] { + name: @index1 + }.key~presence_test } - CONSTANT [12] { value: "A" } } } CALL [13] { - function: _&&_ + function: _==_ args: { SELECT [14] { IDENT [15] { name: @index1 - }.map_string_string~presence_test - } - SELECT [16] { - IDENT [17] { - name: @index2 - }.key~presence_test + }.key } + CONSTANT [16] { value: "A" } } } - CALL [18] { - function: _?_:_ - args: { - IDENT [19] { - name: @index4 - } - IDENT [20] { - name: @index3 - } - CONSTANT [21] { value: false } - } + SELECT [17] { + IDENT [18] { + name: msg + }.oneof_type } - CALL [22] { + CALL [19] { function: _&&_ args: { - SELECT [23] { - IDENT [24] { + SELECT [20] { + IDENT [21] { name: msg }.oneof_type~presence_test } - SELECT [25] { - IDENT [26] { - name: @index0 + SELECT [22] { + IDENT [23] { + name: @index4 }.payload~presence_test } } } - CALL [27] { + CALL [24] { function: _&&_ args: { - IDENT [28] { - name: @index6 + IDENT [25] { + name: @index5 } - SELECT [29] { - IDENT [30] { - name: @index1 + SELECT [26] { + IDENT [27] { + name: @index0 }.single_int64~presence_test } } } } } - CALL [31] { + CALL [28] { function: _?_:_ args: { - IDENT [32] { - name: @index7 + IDENT [29] { + name: @index6 } - IDENT [33] { - name: @index5 + CALL [30] { + function: _?_:_ + args: { + IDENT [31] { + name: @index2 + } + IDENT [32] { + name: @index3 + } + CONSTANT [33] { value: false } + } } CONSTANT [34] { value: false } } @@ -3008,63 +2903,59 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CALL [3] { - function: optional.none - args: { - } - } - CREATE_LIST [4] { + CREATE_LIST [3] { elements: { - IDENT [5] { - name: @index0 + CALL [4] { + function: optional.none + args: { + } } - IDENT [6] { + IDENT [5] { name: opt_x } } optional_indices: [0, 1] } - CREATE_LIST [7] { + CREATE_LIST [6] { elements: { - CONSTANT [8] { value: 5 } + CONSTANT [7] { value: 5 } } } - CREATE_LIST [9] { + CREATE_LIST [8] { elements: { - CONSTANT [10] { value: 10 } + CONSTANT [9] { value: 10 } + CALL [10] { + function: optional.none + args: { + } + } IDENT [11] { - name: @index2 + name: @index0 } IDENT [12] { - name: @index2 - } - } - } - CREATE_LIST [13] { - elements: { - CONSTANT [14] { value: 10 } - IDENT [15] { name: @index0 } - IDENT [16] { - name: @index1 - } - IDENT [17] { - name: @index1 - } } optional_indices: [0] } } } - CALL [18] { + CALL [13] { function: _==_ args: { - IDENT [19] { - name: @index4 + IDENT [14] { + name: @index2 } - IDENT [20] { - name: @index3 + CREATE_LIST [15] { + elements: { + CONSTANT [16] { value: 10 } + IDENT [17] { + name: @index1 + } + IDENT [18] { + name: @index1 + } + } } } } @@ -3078,54 +2969,48 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CALL [3] { - function: optional.of - args: { - CONSTANT [4] { value: "hello" } - } - } - CREATE_MAP [5] { - MAP_ENTRY [6] { + CREATE_MAP [3] { + MAP_ENTRY [4] { key: { - CONSTANT [7] { value: "hello" } + CONSTANT [5] { value: "hello" } } optional_entry: true value: { - IDENT [8] { - name: @index0 + CALL [6] { + function: optional.of + args: { + CONSTANT [7] { value: "hello" } + } } } } } - CALL [9] { + CALL [8] { function: _[_] args: { - IDENT [10] { - name: @index1 + IDENT [9] { + name: @index0 } - CONSTANT [11] { value: "hello" } + CONSTANT [10] { value: "hello" } } } + } + } + CALL [11] { + function: _==_ + args: { CALL [12] { function: _+_ args: { IDENT [13] { - name: @index2 + name: @index1 } IDENT [14] { - name: @index2 + name: @index1 } } } - } - } - CALL [15] { - function: _==_ - args: { - IDENT [16] { - name: @index3 - } - CONSTANT [17] { value: "hellohello" } + CONSTANT [15] { value: "hellohello" } } } } @@ -3148,81 +3033,75 @@ CALL [1] { } } } - CALL [7] { - function: _[_] - args: { - IDENT [8] { - name: @index0 - } - CONSTANT [9] { value: "key" } - } - } - CALL [10] { - function: _[?_] - args: { - IDENT [11] { - name: @index0 - } - CONSTANT [12] { value: "bogus" } - } - } - CREATE_MAP [13] { - MAP_ENTRY [14] { + CREATE_MAP [7] { + MAP_ENTRY [8] { key: { - CONSTANT [15] { value: "key" } + CONSTANT [9] { value: "key" } } optional_entry: true value: { - CALL [16] { + CALL [10] { function: optional.of args: { - CONSTANT [17] { value: "test" } + CONSTANT [11] { value: "test" } } } } } } - CALL [18] { + CALL [12] { function: or target: { - CALL [19] { + CALL [13] { function: _[?_] args: { - IDENT [20] { - name: @index3 + IDENT [14] { + name: @index1 + } + CONSTANT [15] { value: "bogus" } + } + } + } + args: { + CALL [16] { + function: _[?_] + args: { + IDENT [17] { + name: @index0 } - CONSTANT [21] { value: "bogus" } + CONSTANT [18] { value: "bogus" } } } } - args: { - IDENT [22] { - name: @index2 - } - } } - CALL [23] { + CALL [19] { function: orValue target: { - IDENT [24] { - name: @index4 + IDENT [20] { + name: @index2 } } args: { - IDENT [25] { - name: @index1 + CALL [21] { + function: _[_] + args: { + IDENT [22] { + name: @index0 + } + CONSTANT [23] { value: "key" } + } } } } } } - CALL [26] { + CALL [24] { function: _==_ args: { - IDENT [27] { - name: @index5 + IDENT [25] { + name: @index3 } - CONSTANT [28] { value: "test" } + CONSTANT [26] { value: "test" } } } } @@ -3235,65 +3114,59 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CALL [3] { - function: optional.ofNonZeroValue - args: { - CONSTANT [4] { value: 1 } - } - } - CALL [5] { - function: optional.of - args: { - CONSTANT [6] { value: 4 } - } - } - CREATE_STRUCT [7] { + CREATE_STRUCT [3] { name: TestAllTypes entries: { - ENTRY [8] { + ENTRY [4] { field_key: single_int64 optional_entry: true value: { - IDENT [9] { - name: @index0 + CALL [5] { + function: optional.ofNonZeroValue + args: { + CONSTANT [6] { value: 1 } + } } } } - ENTRY [10] { + ENTRY [7] { field_key: single_int32 optional_entry: true value: { - IDENT [11] { - name: @index1 + CALL [8] { + function: optional.of + args: { + CONSTANT [9] { value: 4 } + } } } } } } - CALL [12] { + CALL [10] { function: _+_ args: { - SELECT [13] { - IDENT [14] { - name: @index2 + SELECT [11] { + IDENT [12] { + name: @index0 }.single_int32 } - SELECT [15] { - IDENT [16] { - name: @index2 + SELECT [13] { + IDENT [14] { + name: @index0 }.single_int64 } } } } } - CALL [17] { + CALL [15] { function: _==_ args: { - IDENT [18] { - name: @index3 + IDENT [16] { + name: @index1 } - CONSTANT [19] { value: 5 } + CONSTANT [17] { value: 5 } } } } @@ -3309,58 +3182,49 @@ CALL [1] { CALL [3] { function: _+_ args: { - CONSTANT [4] { value: "h" } - CONSTANT [5] { value: "e" } - } - } - CALL [6] { - function: _+_ - args: { - IDENT [7] { - name: @index0 - } - CONSTANT [8] { value: "l" } - } - } - CALL [9] { - function: _+_ - args: { - IDENT [10] { - name: @index1 - } - CONSTANT [11] { value: "l" } - } - } - CALL [12] { - function: _+_ - args: { - IDENT [13] { - name: @index2 + CALL [4] { + function: _+_ + args: { + CONSTANT [5] { value: "h" } + CONSTANT [6] { value: "e" } + } } - CONSTANT [14] { value: "o" } + CONSTANT [7] { value: "l" } } } - CALL [15] { + CALL [8] { function: _+_ args: { - IDENT [16] { - name: @index3 + CALL [9] { + function: _+_ + args: { + IDENT [10] { + name: @index0 + } + CONSTANT [11] { value: "l" } + } } - CONSTANT [17] { value: " world" } + CONSTANT [12] { value: "o" } } } } } - CALL [18] { + CALL [13] { function: matches target: { - IDENT [19] { - name: @index4 + CALL [14] { + function: _+_ + args: { + IDENT [15] { + name: @index1 + } + CONSTANT [16] { value: " world" } + } } } args: { - IDENT [20] { - name: @index3 + IDENT [17] { + name: @index1 } } } @@ -3453,26 +3317,23 @@ CALL [1] { CONSTANT [12] { value: "o" } } } - CALL [13] { + } + } + CALL [13] { + function: matches + target: { + CALL [14] { function: _+_ args: { - IDENT [14] { + IDENT [15] { name: @index1 } - CONSTANT [15] { value: " world" } + CONSTANT [16] { value: " world" } } } } - } - CALL [16] { - function: matches - target: { - IDENT [17] { - name: @index2 - } - } args: { - CONSTANT [18] { value: "hello" } + CONSTANT [17] { value: "hello" } } } } @@ -3491,11 +3352,11 @@ CALL [1] { CALL [4] { function: _+_ args: { - CONSTANT [5] { value: "w" } - CONSTANT [6] { value: "o" } + CONSTANT [5] { value: "h" } + CONSTANT [6] { value: "e" } } } - CONSTANT [7] { value: "r" } + CONSTANT [7] { value: "l" } } } CALL [8] { @@ -3510,7 +3371,7 @@ CALL [1] { CONSTANT [11] { value: "l" } } } - CONSTANT [12] { value: "d" } + CONSTANT [12] { value: "o" } } } CALL [13] { @@ -3519,11 +3380,11 @@ CALL [1] { CALL [14] { function: _+_ args: { - CONSTANT [15] { value: "h" } - CONSTANT [16] { value: "e" } + CONSTANT [15] { value: "w" } + CONSTANT [16] { value: "o" } } } - CONSTANT [17] { value: "l" } + CONSTANT [17] { value: "r" } } } CALL [18] { @@ -3538,30 +3399,27 @@ CALL [1] { CONSTANT [21] { value: "l" } } } - CONSTANT [22] { value: "o" } - } - } - CALL [23] { - function: _+_ - args: { - IDENT [24] { - name: @index3 - } - CONSTANT [25] { value: " world" } + CONSTANT [22] { value: "d" } } } } } - CALL [26] { + CALL [23] { function: matches target: { - IDENT [27] { - name: @index4 + CALL [24] { + function: _+_ + args: { + IDENT [25] { + name: @index1 + } + CONSTANT [26] { value: " world" } + } } } args: { - IDENT [28] { - name: @index1 + IDENT [27] { + name: @index3 } } } @@ -3576,74 +3434,65 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 + SELECT [4] { + IDENT [5] { + name: msg + }.oneof_type }.payload } - SELECT [7] { - IDENT [8] { - name: @index1 - }.single_int64 - } - SELECT [9] { - IDENT [10] { - name: msg + SELECT [6] { + IDENT [7] { + name: @index0 }.single_int64 } - SELECT [11] { - IDENT [12] { - name: @index1 - }.single_int32 - } } } - CALL [13] { + CALL [8] { function: _+_ args: { - CALL [14] { + CALL [9] { function: _+_ args: { - CALL [15] { + CALL [10] { function: _+_ args: { - CALL [16] { + CALL [11] { function: non_pure_custom_func args: { - IDENT [17] { - name: @index2 + IDENT [12] { + name: @index1 } } } - CALL [18] { + CALL [13] { function: non_pure_custom_func args: { - IDENT [19] { - name: @index4 + SELECT [14] { + IDENT [15] { + name: @index0 + }.single_int32 } } } } } - CALL [20] { + CALL [16] { function: non_pure_custom_func args: { - IDENT [21] { - name: @index2 + IDENT [17] { + name: @index1 } } } } } - CALL [22] { + CALL [18] { function: non_pure_custom_func args: { - IDENT [23] { - name: @index3 + SELECT [19] { + IDENT [20] { + name: msg + }.single_int64 } } } @@ -3660,76 +3509,70 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 + SELECT [4] { + IDENT [5] { + name: msg + }.oneof_type }.payload } - SELECT [7] { - IDENT [8] { - name: @index1 - }.single_int64 - } - CALL [9] { - function: pure_custom_func - args: { - IDENT [10] { - name: @index2 - } - } - } - CALL [11] { + CALL [6] { function: pure_custom_func args: { - SELECT [12] { - IDENT [13] { - name: msg + SELECT [7] { + IDENT [8] { + name: @index0 }.single_int64 } } } - CALL [14] { + CALL [9] { function: pure_custom_func args: { - SELECT [15] { - IDENT [16] { - name: @index1 + SELECT [10] { + IDENT [11] { + name: @index0 }.single_int32 } } } - CALL [17] { + CALL [12] { function: _+_ args: { - CALL [18] { + CALL [13] { function: _+_ args: { - IDENT [19] { - name: @index3 + IDENT [14] { + name: @index1 } - IDENT [20] { - name: @index5 + IDENT [15] { + name: @index2 } } } - IDENT [21] { - name: @index3 + IDENT [16] { + name: @index1 + } + } + } + CALL [17] { + function: pure_custom_func + args: { + SELECT [18] { + IDENT [19] { + name: msg + }.single_int64 } } } } } - CALL [22] { + CALL [20] { function: _+_ args: { - IDENT [23] { - name: @index6 + IDENT [21] { + name: @index3 } - IDENT [24] { + IDENT [22] { name: @index4 } } diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_3.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_3.baseline index a0ff868b1..6e9a08799 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_3.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_3.baseline @@ -6,20 +6,22 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_LIST [3] { - elements: { - CONSTANT [4] { value: 1 } - CONSTANT [5] { value: 2 } - } - } - CALL [6] { + CALL [3] { function: size args: { - IDENT [7] { - name: @index0 + CREATE_LIST [4] { + elements: { + CONSTANT [5] { value: 1 } + CONSTANT [6] { value: 2 } + } } } } + } + } + CALL [7] { + function: _==_ + args: { CALL [8] { function: _+_ args: { @@ -27,25 +29,17 @@ CALL [1] { function: _+_ args: { IDENT [10] { - name: @index1 + name: @index0 } IDENT [11] { - name: @index1 + name: @index0 } } } CONSTANT [12] { value: 1 } } } - } - } - CALL [13] { - function: _==_ - args: { - IDENT [14] { - name: @index2 - } - CONSTANT [15] { value: 5 } + CONSTANT [13] { value: 5 } } } } @@ -58,52 +52,49 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_LIST [3] { - elements: { - CONSTANT [4] { value: 1 } - CONSTANT [5] { value: 2 } - } - } - CALL [6] { + CALL [3] { function: size args: { - IDENT [7] { - name: @index0 + CREATE_LIST [4] { + elements: { + CONSTANT [5] { value: 1 } + CONSTANT [6] { value: 2 } + } } } } - CALL [8] { + CALL [7] { function: _+_ args: { - CALL [9] { + CALL [8] { function: _+_ args: { - CALL [10] { + CALL [9] { function: _+_ args: { - CONSTANT [11] { value: 2 } - IDENT [12] { - name: @index1 + CONSTANT [10] { value: 2 } + IDENT [11] { + name: @index0 } } } - IDENT [13] { - name: @index1 + IDENT [12] { + name: @index0 } } } - CONSTANT [14] { value: 1 } + CONSTANT [13] { value: 1 } } } } } - CALL [15] { + CALL [14] { function: _==_ args: { - IDENT [16] { - name: @index2 + IDENT [15] { + name: @index1 } - CONSTANT [17] { value: 7 } + CONSTANT [16] { value: 7 } } } } @@ -116,69 +107,63 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_LIST [3] { - elements: { - CONSTANT [4] { value: 0 } - } - } - CALL [5] { + CALL [3] { function: size args: { - IDENT [6] { - name: @index0 + CREATE_LIST [4] { + elements: { + CONSTANT [5] { value: 0 } + } } } } - CREATE_LIST [7] { - elements: { - CONSTANT [8] { value: 1 } - CONSTANT [9] { value: 2 } - } - } - CALL [10] { + CALL [6] { function: size args: { - IDENT [11] { - name: @index2 + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 1 } + CONSTANT [9] { value: 2 } + } } } } - CALL [12] { + CALL [10] { function: _+_ args: { - CALL [13] { + CALL [11] { function: _+_ args: { - CALL [14] { + CALL [12] { function: _+_ args: { - IDENT [15] { - name: @index1 + IDENT [13] { + name: @index0 } - IDENT [16] { - name: @index1 + IDENT [14] { + name: @index0 } } } - IDENT [17] { - name: @index3 + IDENT [15] { + name: @index1 } } } - IDENT [18] { - name: @index3 + IDENT [16] { + name: @index1 } } } } } - CALL [19] { + CALL [17] { function: _==_ args: { - IDENT [20] { - name: @index4 + IDENT [18] { + name: @index2 } - CONSTANT [21] { value: 6 } + CONSTANT [19] { value: 6 } } } } @@ -191,109 +176,100 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_LIST [3] { - elements: { - CONSTANT [4] { value: 0 } - } - } - CALL [5] { + CALL [3] { function: size args: { - IDENT [6] { - name: @index0 + CREATE_LIST [4] { + elements: { + CONSTANT [5] { value: 0 } + } } } } - CREATE_LIST [7] { - elements: { - CONSTANT [8] { value: 1 } - CONSTANT [9] { value: 2 } - } - } - CALL [10] { + CALL [6] { function: size args: { - IDENT [11] { - name: @index2 + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 1 } + CONSTANT [9] { value: 2 } + } } } } - CREATE_LIST [12] { - elements: { - CONSTANT [13] { value: 1 } - CONSTANT [14] { value: 2 } - CONSTANT [15] { value: 3 } - } - } - CALL [16] { + CALL [10] { function: size args: { - IDENT [17] { - name: @index4 + CREATE_LIST [11] { + elements: { + CONSTANT [12] { value: 1 } + CONSTANT [13] { value: 2 } + CONSTANT [14] { value: 3 } + } } } } - CALL [18] { + CALL [15] { function: _+_ args: { - CALL [19] { + CALL [16] { function: _+_ args: { - CALL [20] { + CALL [17] { function: _+_ args: { - CONSTANT [21] { value: 5 } - IDENT [22] { - name: @index1 + CONSTANT [18] { value: 5 } + IDENT [19] { + name: @index0 } } } - IDENT [23] { - name: @index1 + IDENT [20] { + name: @index0 } } } - IDENT [24] { - name: @index3 + IDENT [21] { + name: @index1 } } } - CALL [25] { + CALL [22] { function: _+_ args: { - CALL [26] { + CALL [23] { function: _+_ args: { - CALL [27] { + CALL [24] { function: _+_ args: { - IDENT [28] { - name: @index6 - } - IDENT [29] { + IDENT [25] { name: @index3 } + IDENT [26] { + name: @index1 + } } } - IDENT [30] { - name: @index5 + IDENT [27] { + name: @index2 } } } - IDENT [31] { - name: @index5 + IDENT [28] { + name: @index2 } } } } } - CALL [32] { + CALL [29] { function: _==_ args: { - IDENT [33] { - name: @index7 + IDENT [30] { + name: @index4 } - CONSTANT [34] { value: 17 } + CONSTANT [31] { value: 17 } } } } @@ -309,145 +285,101 @@ CALL [1] { CALL [3] { function: timestamp args: { - CONSTANT [4] { value: 1000000000 } - } - } - CALL [5] { - function: int - args: { - IDENT [6] { - name: @index0 + CALL [4] { + function: int + args: { + CALL [5] { + function: timestamp + args: { + CONSTANT [6] { value: 1000000000 } + } + } + } } } } CALL [7] { function: timestamp args: { - IDENT [8] { - name: @index1 - } - } - } - CALL [9] { - function: getFullYear - target: { - IDENT [10] { - name: @index2 + CALL [8] { + function: int + args: { + CALL [9] { + function: timestamp + args: { + CONSTANT [10] { value: 50 } + } + } + } } } - args: { - } } CALL [11] { function: timestamp args: { - CONSTANT [12] { value: 50 } - } - } - CALL [13] { - function: int - args: { - IDENT [14] { - name: @index4 + CALL [12] { + function: int + args: { + CALL [13] { + function: timestamp + args: { + CONSTANT [14] { value: 200 } + } + } + } } } } CALL [15] { function: timestamp args: { - IDENT [16] { - name: @index5 + CALL [16] { + function: int + args: { + CALL [17] { + function: timestamp + args: { + CONSTANT [18] { value: 75 } + } + } + } } } } - CALL [17] { - function: timestamp - args: { - CONSTANT [18] { value: 200 } - } - } CALL [19] { - function: int - args: { + function: getFullYear + target: { IDENT [20] { - name: @index7 + name: @index0 } } - } - CALL [21] { - function: timestamp args: { - IDENT [22] { - name: @index8 - } } } - CALL [23] { + CALL [21] { function: getFullYear target: { - IDENT [24] { - name: @index9 + IDENT [22] { + name: @index2 } } args: { } } - CALL [25] { - function: timestamp - args: { - CONSTANT [26] { value: 75 } - } - } - CALL [27] { - function: int - args: { - IDENT [28] { - name: @index11 - } - } - } - CALL [29] { - function: timestamp + CALL [23] { + function: _+_ args: { - IDENT [30] { - name: @index12 - } - } - } - CALL [31] { - function: getMinutes - target: { - IDENT [32] { - name: @index13 - } - } - args: { - } - } - CALL [33] { - function: getSeconds - target: { - IDENT [34] { - name: @index6 - } - } - args: { - } - } - CALL [35] { - function: _+_ - args: { - CALL [36] { + CALL [24] { function: _+_ args: { - IDENT [37] { - name: @index3 + IDENT [25] { + name: @index4 } - CALL [38] { + CALL [26] { function: getFullYear target: { - IDENT [39] { - name: @index13 + IDENT [27] { + name: @index3 } } args: { @@ -455,11 +387,11 @@ CALL [1] { } } } - CALL [40] { + CALL [28] { function: getFullYear target: { - IDENT [41] { - name: @index6 + IDENT [29] { + name: @index1 } } args: { @@ -467,69 +399,83 @@ CALL [1] { } } } - CALL [42] { + CALL [30] { function: _+_ args: { - CALL [43] { + CALL [31] { function: _+_ args: { - CALL [44] { + CALL [32] { function: _+_ args: { - IDENT [45] { - name: @index16 + IDENT [33] { + name: @index6 } - IDENT [46] { - name: @index3 + IDENT [34] { + name: @index4 } } } - IDENT [47] { - name: @index15 + CALL [35] { + function: getSeconds + target: { + IDENT [36] { + name: @index1 + } + } + args: { + } } } } - IDENT [48] { - name: @index10 + IDENT [37] { + name: @index5 } } } - CALL [49] { + CALL [38] { function: _+_ args: { - CALL [50] { + CALL [39] { function: _+_ args: { - CALL [51] { + CALL [40] { function: _+_ args: { - IDENT [52] { - name: @index17 + IDENT [41] { + name: @index7 } - IDENT [53] { - name: @index10 + IDENT [42] { + name: @index5 } } } - IDENT [54] { - name: @index14 + CALL [43] { + function: getMinutes + target: { + IDENT [44] { + name: @index3 + } + } + args: { + } } } } - IDENT [55] { - name: @index3 + IDENT [45] { + name: @index4 } } } } } - CALL [56] { + CALL [46] { function: _==_ args: { - IDENT [57] { - name: @index18 + IDENT [47] { + name: @index8 } - CONSTANT [58] { value: 13934 } + CONSTANT [48] { value: 13934 } } } } @@ -542,53 +488,47 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_MAP [3] { - MAP_ENTRY [4] { - key: { - CONSTANT [5] { value: "a" } - } - value: { - CONSTANT [6] { value: 2 } - } - } - } - CALL [7] { + CALL [3] { function: _[_] args: { - IDENT [8] { - name: @index0 + CREATE_MAP [4] { + MAP_ENTRY [5] { + key: { + CONSTANT [6] { value: "a" } + } + value: { + CONSTANT [7] { value: 2 } + } + } } - CONSTANT [9] { value: "a" } + CONSTANT [8] { value: "a" } } } + } + } + CALL [9] { + function: _==_ + args: { CALL [10] { function: _+_ args: { IDENT [11] { - name: @index1 + name: @index0 } CALL [12] { function: _*_ args: { IDENT [13] { - name: @index1 + name: @index0 } IDENT [14] { - name: @index1 + name: @index0 } } } } } - } - } - CALL [15] { - function: _==_ - args: { - IDENT [16] { - name: @index2 - } - CONSTANT [17] { value: 6 } + CONSTANT [15] { value: 6 } } } } @@ -604,51 +544,48 @@ CALL [1] { CREATE_MAP [3] { MAP_ENTRY [4] { key: { - CONSTANT [5] { value: "b" } + CONSTANT [5] { value: "e" } } value: { - CONSTANT [6] { value: 1 } + CREATE_MAP [6] { + MAP_ENTRY [7] { + key: { + CONSTANT [8] { value: "b" } + } + value: { + CONSTANT [9] { value: 1 } + } + } + } } } } - CREATE_MAP [7] { - MAP_ENTRY [8] { + CREATE_MAP [10] { + MAP_ENTRY [11] { key: { - CONSTANT [9] { value: "e" } + CONSTANT [12] { value: "b" } } value: { - IDENT [10] { - name: @index0 - } + CONSTANT [13] { value: 1 } } } } } } - CREATE_MAP [11] { - MAP_ENTRY [12] { - key: { - CONSTANT [13] { value: "a" } - } - value: { - IDENT [14] { - name: @index0 - } - } - } + CREATE_MAP [14] { MAP_ENTRY [15] { key: { - CONSTANT [16] { value: "c" } + CONSTANT [16] { value: "a" } } value: { IDENT [17] { - name: @index0 + name: @index1 } } } MAP_ENTRY [18] { key: { - CONSTANT [19] { value: "d" } + CONSTANT [19] { value: "c" } } value: { IDENT [20] { @@ -658,11 +595,21 @@ CALL [1] { } MAP_ENTRY [21] { key: { - CONSTANT [22] { value: "e" } + CONSTANT [22] { value: "d" } } value: { IDENT [23] { - name: @index1 + name: @index0 + } + } + } + MAP_ENTRY [24] { + key: { + CONSTANT [25] { value: "e" } + } + value: { + IDENT [26] { + name: @index0 } } } @@ -691,37 +638,34 @@ CALL [1] { CONSTANT [10] { value: 2 } } } - CREATE_LIST [11] { - elements: { - IDENT [12] { - name: @index1 - } - IDENT [13] { - name: @index0 - } - } - } } } - CREATE_LIST [14] { + CREATE_LIST [11] { elements: { - CONSTANT [15] { value: 1 } - IDENT [16] { + CONSTANT [12] { value: 1 } + IDENT [13] { name: @index0 } - CONSTANT [17] { value: 2 } - IDENT [18] { + CONSTANT [14] { value: 2 } + IDENT [15] { name: @index0 } - CONSTANT [19] { value: 5 } - IDENT [20] { + CONSTANT [16] { value: 5 } + IDENT [17] { name: @index0 } - CONSTANT [21] { value: 7 } - IDENT [22] { - name: @index2 + CONSTANT [18] { value: 7 } + CREATE_LIST [19] { + elements: { + IDENT [20] { + name: @index1 + } + IDENT [21] { + name: @index0 + } + } } - IDENT [23] { + IDENT [22] { name: @index1 } } @@ -741,26 +685,23 @@ CALL [1] { name: msg }.single_int64 } - CALL [5] { + } + } + CALL [5] { + function: _==_ + args: { + CALL [6] { function: _+_ args: { - IDENT [6] { + IDENT [7] { name: @index0 } - IDENT [7] { + IDENT [8] { name: @index0 } } } - } - } - CALL [8] { - function: _==_ - args: { - IDENT [9] { - name: @index1 - } - CONSTANT [10] { value: 6 } + CONSTANT [9] { value: 6 } } } } @@ -774,66 +715,64 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload - } - SELECT [7] { - IDENT [8] { - name: @index1 - }.single_int64 - } - SELECT [9] { - SELECT [10] { - SELECT [11] { - IDENT [12] { - name: @index1 + SELECT [4] { + SELECT [5] { + IDENT [6] { + name: msg }.oneof_type }.payload }.single_int64 } - SELECT [13] { - IDENT [14] { - name: msg - }.single_int64 + SELECT [7] { + SELECT [8] { + IDENT [9] { + name: msg + }.oneof_type + }.payload } - CALL [15] { + CALL [10] { function: _+_ args: { - CALL [16] { + CALL [11] { function: _+_ args: { - IDENT [17] { - name: @index2 + IDENT [12] { + name: @index0 } - SELECT [18] { - IDENT [19] { + SELECT [13] { + IDENT [14] { name: @index1 }.single_int32 } } } - IDENT [20] { - name: @index2 + IDENT [15] { + name: @index0 } } } - CALL [21] { + SELECT [16] { + SELECT [17] { + SELECT [18] { + IDENT [19] { + name: @index1 + }.oneof_type + }.payload + }.single_int64 + } + CALL [20] { function: _+_ args: { - CALL [22] { + CALL [21] { function: _+_ args: { - IDENT [23] { - name: @index5 + IDENT [22] { + name: @index2 } - IDENT [24] { - name: @index4 + SELECT [23] { + IDENT [24] { + name: msg + }.single_int64 } } } @@ -848,7 +787,7 @@ CALL [1] { function: _==_ args: { IDENT [27] { - name: @index6 + name: @index4 } CONSTANT [28] { value: 31 } } @@ -864,74 +803,59 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg + SELECT [4] { + SELECT [5] { + IDENT [6] { + name: msg + }.oneof_type + }.payload }.oneof_type } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload - } SELECT [7] { - IDENT [8] { - name: @index1 + SELECT [8] { + IDENT [9] { + name: @index0 + }.payload }.oneof_type } - SELECT [9] { - IDENT [10] { - name: @index2 + SELECT [10] { + SELECT [11] { + SELECT [12] { + IDENT [13] { + name: @index1 + }.payload + }.oneof_type }.payload } - SELECT [11] { - IDENT [12] { - name: @index3 - }.oneof_type - } - SELECT [13] { - SELECT [14] { - SELECT [15] { - IDENT [16] { - name: @index4 + SELECT [14] { + SELECT [15] { + SELECT [16] { + IDENT [17] { + name: @index1 }.child }.child }.payload } - SELECT [17] { - IDENT [18] { - name: @index5 - }.single_bool - } - SELECT [19] { - SELECT [20] { - SELECT [21] { - IDENT [22] { - name: @index4 - }.payload - }.oneof_type - }.payload - } - CALL [23] { + } + } + CALL [18] { + function: _||_ + args: { + CALL [19] { function: _||_ args: { - CONSTANT [24] { value: true } - SELECT [25] { - IDENT [26] { - name: @index7 + CONSTANT [20] { value: true } + SELECT [21] { + IDENT [22] { + name: @index2 }.single_bool } } } - } - } - CALL [27] { - function: _||_ - args: { - IDENT [28] { - name: @index8 - } - IDENT [29] { - name: @index6 + SELECT [23] { + IDENT [24] { + name: @index3 + }.single_bool } } } @@ -946,57 +870,48 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload - } - SELECT [7] { - IDENT [8] { - name: @index1 + SELECT [4] { + SELECT [5] { + IDENT [6] { + name: msg + }.oneof_type + }.payload }.map_int32_int64 } - CALL [9] { + CALL [7] { function: _[_] args: { - IDENT [10] { - name: @index2 + IDENT [8] { + name: @index0 } - CONSTANT [11] { value: 1 } + CONSTANT [9] { value: 1 } } } - CALL [12] { + } + } + CALL [10] { + function: _==_ + args: { + CALL [11] { function: _+_ args: { - CALL [13] { + CALL [12] { function: _+_ args: { - IDENT [14] { - name: @index3 + IDENT [13] { + name: @index1 } - IDENT [15] { - name: @index3 + IDENT [14] { + name: @index1 } } } - IDENT [16] { - name: @index3 + IDENT [15] { + name: @index1 } } } - } - } - CALL [17] { - function: _==_ - args: { - IDENT [18] { - name: @index4 - } - CONSTANT [19] { value: 15 } + CONSTANT [16] { value: 15 } } } } @@ -1010,66 +925,60 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload - } - SELECT [7] { - IDENT [8] { - name: @index1 + SELECT [4] { + SELECT [5] { + IDENT [6] { + name: msg + }.oneof_type + }.payload }.map_int32_int64 } - CALL [9] { + CALL [7] { function: _+_ args: { - CALL [10] { + CALL [8] { function: _+_ args: { - CALL [11] { + CALL [9] { function: _[_] args: { - IDENT [12] { - name: @index2 + IDENT [10] { + name: @index0 } - CONSTANT [13] { value: 0 } + CONSTANT [11] { value: 0 } } } - CALL [14] { + CALL [12] { function: _[_] args: { - IDENT [15] { - name: @index2 + IDENT [13] { + name: @index0 } - CONSTANT [16] { value: 1 } + CONSTANT [14] { value: 1 } } } } } - CALL [17] { + CALL [15] { function: _[_] args: { - IDENT [18] { - name: @index2 + IDENT [16] { + name: @index0 } - CONSTANT [19] { value: 2 } + CONSTANT [17] { value: 2 } } } } } } } - CALL [20] { + CALL [18] { function: _==_ args: { - IDENT [21] { - name: @index3 + IDENT [19] { + name: @index1 } - CONSTANT [22] { value: 8 } + CONSTANT [20] { value: 8 } } } } @@ -1100,18 +1009,15 @@ CALL [1] { }.oneof_type }.payload } - SELECT [11] { - SELECT [12] { - IDENT [13] { - name: @index1 - }.oneof_type - }.payload - } } } - SELECT [14] { - IDENT [15] { - name: @index2 + SELECT [11] { + SELECT [12] { + SELECT [13] { + IDENT [14] { + name: @index1 + }.oneof_type + }.payload }.single_int64 } } @@ -1129,33 +1035,30 @@ CALL [1] { name: msg }.single_int64 } - CALL [5] { + } + } + CALL [5] { + function: _==_ + args: { + CALL [6] { function: _?_:_ args: { - CALL [6] { + CALL [7] { function: _>_ args: { - IDENT [7] { + IDENT [8] { name: @index0 } - CONSTANT [8] { value: 0 } + CONSTANT [9] { value: 0 } } } - IDENT [9] { + IDENT [10] { name: @index0 } - CONSTANT [10] { value: 0 } + CONSTANT [11] { value: 0 } } } - } - } - CALL [11] { - function: _==_ - args: { - IDENT [12] { - name: @index1 - } - CONSTANT [13] { value: 3 } + CONSTANT [12] { value: 3 } } } } @@ -1196,27 +1099,24 @@ CALL [1] { } } } - CALL [12] { + } + } + CALL [12] { + function: _?_:_ + args: { + CONSTANT [13] { value: false } + CONSTANT [14] { value: false } + CALL [15] { function: _==_ args: { - IDENT [13] { + IDENT [16] { name: @index1 } - CONSTANT [14] { value: 11 } + CONSTANT [17] { value: 11 } } } } } - CALL [15] { - function: _?_:_ - args: { - CONSTANT [16] { value: false } - CONSTANT [17] { value: false } - IDENT [18] { - name: @index2 - } - } - } } } Test case: NESTED_TERNARY @@ -1299,50 +1199,80 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_LIST [3] { - elements: { - CONSTANT [4] { value: 1 } + COMPREHENSION [3] { + iter_var: @c0:0 + iter_range: { + CREATE_LIST [4] { + elements: { + CONSTANT [5] { value: 1 } + } + } } - } - CALL [5] { - function: _>_ - args: { - IDENT [6] { - name: @c0:0 + accu_var: @x0:0 + accu_init: { + CONSTANT [6] { value: false } + } + loop_condition: { + CALL [7] { + function: @not_strictly_false + args: { + CALL [8] { + function: !_ + args: { + IDENT [9] { + name: @x0:0 + } + } + } + } } - CONSTANT [7] { value: 0 } } - } - CALL [8] { - function: _||_ - args: { - IDENT [9] { - name: @x0:0 + loop_step: { + CALL [10] { + function: _||_ + args: { + IDENT [11] { + name: @x0:0 + } + CALL [12] { + function: _>_ + args: { + IDENT [13] { + name: @c0:0 + } + CONSTANT [14] { value: 0 } + } + } + } } - IDENT [10] { - name: @index1 + } + result: { + IDENT [15] { + name: @x0:0 } } } - COMPREHENSION [11] { + COMPREHENSION [16] { iter_var: @c0:0 iter_range: { - IDENT [12] { - name: @index0 + CREATE_LIST [17] { + elements: { + CONSTANT [18] { value: 2 } + } } } accu_var: @x0:0 accu_init: { - CONSTANT [13] { value: false } + CONSTANT [19] { value: false } } loop_condition: { - CALL [14] { + CALL [20] { function: @not_strictly_false args: { - CALL [15] { + CALL [21] { function: !_ args: { - IDENT [16] { + IDENT [22] { name: @x0:0 } } @@ -1351,144 +1281,90 @@ CALL [1] { } } loop_step: { - IDENT [17] { - name: @index2 + CALL [23] { + function: _||_ + args: { + IDENT [24] { + name: @x0:0 + } + CALL [25] { + function: _>_ + args: { + IDENT [26] { + name: @c0:0 + } + CONSTANT [27] { value: 1 } + } + } + } } } result: { - IDENT [18] { + IDENT [28] { name: @x0:0 } } } - CREATE_LIST [19] { - elements: { - IDENT [20] { - name: @index3 - } - } - } - CALL [21] { + CALL [29] { function: size args: { - IDENT [22] { - name: @index4 - } - } - } - CREATE_LIST [23] { - elements: { - CONSTANT [24] { value: 2 } - } - } - CALL [25] { - function: _>_ - args: { - IDENT [26] { - name: @c0:0 - } - CONSTANT [27] { value: 1 } - } - } - CALL [28] { - function: _||_ - args: { - IDENT [29] { - name: @x0:0 - } - IDENT [30] { - name: @index7 - } - } - } - COMPREHENSION [31] { - iter_var: @c0:0 - iter_range: { - IDENT [32] { - name: @index6 - } - } - accu_var: @x0:0 - accu_init: { - CONSTANT [33] { value: false } - } - loop_condition: { - CALL [34] { - function: @not_strictly_false - args: { - CALL [35] { - function: !_ - args: { - IDENT [36] { - name: @x0:0 - } - } + CREATE_LIST [30] { + elements: { + IDENT [31] { + name: @index0 } } } } - loop_step: { - IDENT [37] { - name: @index8 - } - } - result: { - IDENT [38] { - name: @x0:0 - } - } - } - CREATE_LIST [39] { - elements: { - IDENT [40] { - name: @index9 - } - } } - CALL [41] { + CALL [32] { function: size args: { - IDENT [42] { - name: @index10 + CREATE_LIST [33] { + elements: { + IDENT [34] { + name: @index1 + } + } } } } - CALL [43] { + CALL [35] { function: _+_ args: { - CALL [44] { + CALL [36] { function: _+_ args: { - CALL [45] { + CALL [37] { function: _+_ args: { - IDENT [46] { - name: @index5 + IDENT [38] { + name: @index2 } - IDENT [47] { - name: @index5 + IDENT [39] { + name: @index2 } } } - IDENT [48] { - name: @index11 + IDENT [40] { + name: @index3 } } } - IDENT [49] { - name: @index11 + IDENT [41] { + name: @index3 } } } } } - CALL [50] { + CALL [42] { function: _==_ args: { - IDENT [51] { - name: @index12 + IDENT [43] { + name: @index4 } - CONSTANT [52] { value: 4 } + CONSTANT [44] { value: 4 } } } } @@ -1501,50 +1377,27 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_LIST [3] { - elements: { - CONSTANT [4] { value: 1 } - } - } - CALL [5] { - function: _>_ - args: { - IDENT [6] { - name: @c0:0 - } - CONSTANT [7] { value: 0 } - } - } - CALL [8] { - function: _||_ - args: { - IDENT [9] { - name: @x0:0 - } - IDENT [10] { - name: @index1 - } - } - } - COMPREHENSION [11] { + COMPREHENSION [3] { iter_var: @c0:0 iter_range: { - IDENT [12] { - name: @index0 + CREATE_LIST [4] { + elements: { + CONSTANT [5] { value: 1 } + } } } accu_var: @x0:0 accu_init: { - CONSTANT [13] { value: false } + CONSTANT [6] { value: false } } loop_condition: { - CALL [14] { + CALL [7] { function: @not_strictly_false args: { - CALL [15] { + CALL [8] { function: !_ args: { - IDENT [16] { + IDENT [9] { name: @x0:0 } } @@ -1553,67 +1406,51 @@ CALL [1] { } } loop_step: { - IDENT [17] { - name: @index2 + CALL [10] { + function: _||_ + args: { + IDENT [11] { + name: @x0:0 + } + CALL [12] { + function: _>_ + args: { + IDENT [13] { + name: @c0:0 + } + CONSTANT [14] { value: 0 } + } + } + } } } result: { - IDENT [18] { + IDENT [15] { name: @x0:0 } } } - CREATE_LIST [19] { - elements: { - IDENT [20] { - name: @index3 - } - } - } - CREATE_LIST [21] { - elements: { - CONSTANT [22] { value: "a" } - } - } - CALL [23] { - function: _==_ - args: { - IDENT [24] { - name: @c0:1 - } - CONSTANT [25] { value: "a" } - } - } - CALL [26] { - function: _||_ - args: { - IDENT [27] { - name: @x0:1 - } - IDENT [28] { - name: @index6 - } - } - } - COMPREHENSION [29] { + COMPREHENSION [16] { iter_var: @c0:1 iter_range: { - IDENT [30] { - name: @index5 + CREATE_LIST [17] { + elements: { + CONSTANT [18] { value: "a" } + } } } accu_var: @x0:1 accu_init: { - CONSTANT [31] { value: false } + CONSTANT [19] { value: false } } loop_condition: { - CALL [32] { + CALL [20] { function: @not_strictly_false args: { - CALL [33] { + CALL [21] { function: !_ args: { - IDENT [34] { + IDENT [22] { name: @x0:1 } } @@ -1622,68 +1459,86 @@ CALL [1] { } } loop_step: { - IDENT [35] { - name: @index7 + CALL [23] { + function: _||_ + args: { + IDENT [24] { + name: @x0:1 + } + CALL [25] { + function: _==_ + args: { + IDENT [26] { + name: @c0:1 + } + CONSTANT [27] { value: "a" } + } + } + } } } result: { - IDENT [36] { + IDENT [28] { name: @x0:1 } } } - CREATE_LIST [37] { + CREATE_LIST [29] { elements: { - IDENT [38] { - name: @index8 + IDENT [30] { + name: @index0 } } } - CREATE_LIST [39] { + CREATE_LIST [31] { elements: { - CONSTANT [40] { value: true } - CONSTANT [41] { value: true } - CONSTANT [42] { value: true } - CONSTANT [43] { value: true } + IDENT [32] { + name: @index1 + } } } - CALL [44] { + CALL [33] { function: _+_ args: { - CALL [45] { + CALL [34] { function: _+_ args: { - CALL [46] { + CALL [35] { function: _+_ args: { - IDENT [47] { - name: @index4 + IDENT [36] { + name: @index2 } - IDENT [48] { - name: @index4 + IDENT [37] { + name: @index2 } } } - IDENT [49] { - name: @index9 + IDENT [38] { + name: @index3 } } } - IDENT [50] { - name: @index9 + IDENT [39] { + name: @index3 } } } } } - CALL [51] { + CALL [40] { function: _==_ args: { - IDENT [52] { - name: @index11 + IDENT [41] { + name: @index4 } - IDENT [53] { - name: @index10 + CREATE_LIST [42] { + elements: { + CONSTANT [43] { value: true } + CONSTANT [44] { value: true } + CONSTANT [45] { value: true } + CONSTANT [46] { value: true } + } } } } @@ -1711,121 +1566,115 @@ CALL [1] { CONSTANT [10] { value: 4 } } } - CREATE_LIST [11] { - elements: { - IDENT [12] { - name: @index1 - } - IDENT [13] { - name: @index1 - } - IDENT [14] { - name: @index1 - } - } - } - CALL [15] { + CALL [11] { function: _+_ args: { - IDENT [16] { + IDENT [12] { name: @x1:0 } - CREATE_LIST [17] { + CREATE_LIST [13] { elements: { - CALL [18] { + CALL [14] { function: _+_ args: { - IDENT [19] { + IDENT [15] { name: @c1:0 } - CONSTANT [20] { value: 1 } + CONSTANT [16] { value: 1 } } } } } } } - CREATE_LIST [21] { + CREATE_LIST [17] { elements: { - COMPREHENSION [22] { + COMPREHENSION [18] { iter_var: @c1:0 iter_range: { - IDENT [23] { + IDENT [19] { name: @index0 } } accu_var: @x1:0 accu_init: { - CREATE_LIST [24] { + CREATE_LIST [20] { elements: { } } } loop_condition: { - CONSTANT [25] { value: true } + CONSTANT [21] { value: true } } loop_step: { - IDENT [26] { - name: @index3 + IDENT [22] { + name: @index2 } } result: { - IDENT [27] { + IDENT [23] { name: @x1:0 } } } } } - COMPREHENSION [28] { + } + } + CALL [24] { + function: _==_ + args: { + COMPREHENSION [25] { iter_var: @c0:0 iter_range: { - IDENT [29] { + IDENT [26] { name: @index0 } } accu_var: @x0:0 accu_init: { - CREATE_LIST [30] { + CREATE_LIST [27] { elements: { } } } loop_condition: { - CONSTANT [31] { value: true } + CONSTANT [28] { value: true } } loop_step: { - CALL [32] { + CALL [29] { function: _+_ args: { - IDENT [33] { + IDENT [30] { name: @x0:0 } - IDENT [34] { - name: @index4 + IDENT [31] { + name: @index3 } } } } result: { - IDENT [35] { + IDENT [32] { name: @x0:0 } } } - } - } - CALL [36] { - function: _==_ - args: { - IDENT [37] { - name: @index5 - } - IDENT [38] { - name: @index2 - } - } - } + CREATE_LIST [33] { + elements: { + IDENT [34] { + name: @index1 + } + IDENT [35] { + name: @index1 + } + IDENT [36] { + name: @index1 + } + } + } + } + } } } Test case: NESTED_MACROS_2 @@ -1836,139 +1685,133 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_LIST [3] { - elements: { - CREATE_LIST [4] { - elements: { - CONSTANT [5] { value: 1 } - } - } - CREATE_LIST [6] { - elements: { - CONSTANT [7] { value: 2 } - } - } - } - } - CALL [8] { + CALL [3] { function: _?_:_ args: { - CALL [9] { + CALL [4] { function: _==_ args: { - IDENT [10] { + IDENT [5] { name: @c1:0 } - IDENT [11] { + IDENT [6] { name: @c0:0 } } } - CALL [12] { + CALL [7] { function: _+_ args: { - IDENT [13] { + IDENT [8] { name: @x1:0 } - CREATE_LIST [14] { + CREATE_LIST [9] { elements: { - IDENT [15] { + IDENT [10] { name: @c1:0 } } } } } - IDENT [16] { + IDENT [11] { name: @x1:0 } } } - CREATE_LIST [17] { + CREATE_LIST [12] { elements: { - COMPREHENSION [18] { + COMPREHENSION [13] { iter_var: @c1:0 iter_range: { - CREATE_LIST [19] { + CREATE_LIST [14] { elements: { - CONSTANT [20] { value: 1 } - CONSTANT [21] { value: 2 } - CONSTANT [22] { value: 3 } + CONSTANT [15] { value: 1 } + CONSTANT [16] { value: 2 } + CONSTANT [17] { value: 3 } } } } accu_var: @x1:0 accu_init: { - CREATE_LIST [23] { + CREATE_LIST [18] { elements: { } } } loop_condition: { - CONSTANT [24] { value: true } + CONSTANT [19] { value: true } } loop_step: { - IDENT [25] { - name: @index1 + IDENT [20] { + name: @index0 } } result: { - IDENT [26] { + IDENT [21] { name: @x1:0 } } } } } - COMPREHENSION [27] { + } + } + CALL [22] { + function: _==_ + args: { + COMPREHENSION [23] { iter_var: @c0:0 iter_range: { - CREATE_LIST [28] { + CREATE_LIST [24] { elements: { - CONSTANT [29] { value: 1 } - CONSTANT [30] { value: 2 } + CONSTANT [25] { value: 1 } + CONSTANT [26] { value: 2 } } } } accu_var: @x0:0 accu_init: { - CREATE_LIST [31] { + CREATE_LIST [27] { elements: { } } } loop_condition: { - CONSTANT [32] { value: true } + CONSTANT [28] { value: true } } loop_step: { - CALL [33] { + CALL [29] { function: _+_ args: { - IDENT [34] { + IDENT [30] { name: @x0:0 } - IDENT [35] { - name: @index2 + IDENT [31] { + name: @index1 } } } } result: { - IDENT [36] { + IDENT [32] { name: @x0:0 } } } - } - } - CALL [37] { - function: _==_ - args: { - IDENT [38] { - name: @index3 - } - IDENT [39] { - name: @index0 + CREATE_LIST [33] { + elements: { + CREATE_LIST [34] { + elements: { + CONSTANT [35] { value: 1 } + } + } + CREATE_LIST [36] { + elements: { + CONSTANT [37] { value: 2 } + } + } + } } } } @@ -1982,70 +1825,71 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_LIST [3] { - elements: { - CONSTANT [4] { value: 1 } - CONSTANT [5] { value: 2 } - CONSTANT [6] { value: 3 } - } - } - CALL [7] { + CALL [3] { function: @in args: { - CONSTANT [8] { value: 1 } - IDENT [9] { - name: @index0 + CONSTANT [4] { value: 1 } + CREATE_LIST [5] { + elements: { + CONSTANT [6] { value: 1 } + CONSTANT [7] { value: 2 } + CONSTANT [8] { value: 3 } + } } } } - CALL [10] { + CREATE_LIST [9] { + elements: { + CONSTANT [10] { value: 1 } + CONSTANT [11] { value: 2 } + CONSTANT [12] { value: 3 } + } + } + CALL [13] { function: _&&_ args: { - CALL [11] { + CALL [14] { function: @in args: { - CONSTANT [12] { value: 3 } - CREATE_LIST [13] { + CONSTANT [15] { value: 3 } + CREATE_LIST [16] { elements: { - CONSTANT [14] { value: 3 } - IDENT [15] { - name: @index0 + CONSTANT [17] { value: 3 } + IDENT [18] { + name: @index1 } } } } } - IDENT [16] { - name: @index1 + IDENT [19] { + name: @index0 } } } - CALL [17] { + } + } + CALL [20] { + function: _&&_ + args: { + CALL [21] { function: _&&_ args: { - IDENT [18] { - name: @index1 + IDENT [22] { + name: @index0 } - CALL [19] { + CALL [23] { function: @in args: { - CONSTANT [20] { value: 2 } - IDENT [21] { - name: @index0 + CONSTANT [24] { value: 2 } + IDENT [25] { + name: @index1 } } } } } - } - } - CALL [22] { - function: _&&_ - args: { - IDENT [23] { - name: @index3 - } - IDENT [24] { + IDENT [26] { name: @index2 } } @@ -2070,31 +1914,37 @@ CALL [1] { } } } - CREATE_MAP [7] { - MAP_ENTRY [8] { + } + } + CALL [7] { + function: @in + args: { + CONSTANT [8] { value: 2 } + CREATE_MAP [9] { + MAP_ENTRY [10] { key: { - CONSTANT [9] { value: "a" } + CONSTANT [11] { value: "a" } } value: { - CONSTANT [10] { value: 1 } + CONSTANT [12] { value: 1 } } } - MAP_ENTRY [11] { + MAP_ENTRY [13] { key: { - CONSTANT [12] { value: 2 } + CONSTANT [14] { value: 2 } } value: { - IDENT [13] { + IDENT [15] { name: @index0 } } } - MAP_ENTRY [14] { + MAP_ENTRY [16] { key: { - CONSTANT [15] { value: 3 } + CONSTANT [17] { value: 3 } } value: { - IDENT [16] { + IDENT [18] { name: @index0 } } @@ -2102,15 +1952,6 @@ CALL [1] { } } } - CALL [17] { - function: @in - args: { - CONSTANT [18] { value: 2 } - IDENT [19] { - name: @index1 - } - } - } } } Test case: MACRO_ITER_VAR_NOT_REFERENCED @@ -2123,126 +1964,126 @@ CALL [1] { elements: { CREATE_LIST [3] { elements: { - CONSTANT [4] { value: 1 } - CONSTANT [5] { value: 2 } - } - } - CREATE_LIST [6] { - elements: { - CONSTANT [7] { value: 3 } - CONSTANT [8] { value: 4 } - } - } - CREATE_LIST [9] { - elements: { - IDENT [10] { - name: @index1 + CREATE_LIST [4] { + elements: { + CONSTANT [5] { value: 3 } + CONSTANT [6] { value: 4 } + } } - IDENT [11] { - name: @index1 + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 3 } + CONSTANT [9] { value: 4 } + } } } } - CREATE_LIST [12] { + CREATE_LIST [10] { elements: { - IDENT [13] { - name: @index2 - } - IDENT [14] { - name: @index2 - } + CONSTANT [11] { value: 1 } + CONSTANT [12] { value: 2 } } } - COMPREHENSION [15] { - iter_var: @c1:0 - iter_range: { - IDENT [16] { - name: @index0 + CALL [13] { + function: _+_ + args: { + IDENT [14] { + name: @x1:0 } - } - accu_var: @x1:0 - accu_init: { - CREATE_LIST [17] { + CREATE_LIST [15] { elements: { + CREATE_LIST [16] { + elements: { + CONSTANT [17] { value: 3 } + CONSTANT [18] { value: 4 } + } + } } } } - loop_condition: { - CONSTANT [18] { value: true } - } - loop_step: { - CALL [19] { - function: _+_ - args: { - IDENT [20] { - name: @x1:0 + } + CREATE_LIST [19] { + elements: { + COMPREHENSION [20] { + iter_var: @c1:0 + iter_range: { + IDENT [21] { + name: @index1 } - CREATE_LIST [21] { + } + accu_var: @x1:0 + accu_init: { + CREATE_LIST [22] { elements: { - IDENT [22] { - name: @index1 - } } } } - } - } - result: { - IDENT [23] { - name: @x1:0 + loop_condition: { + CONSTANT [23] { value: true } + } + loop_step: { + IDENT [24] { + name: @index2 + } + } + result: { + IDENT [25] { + name: @x1:0 + } + } } } } - COMPREHENSION [24] { + } + } + CALL [26] { + function: _==_ + args: { + COMPREHENSION [27] { iter_var: @c0:0 iter_range: { - IDENT [25] { - name: @index0 + IDENT [28] { + name: @index1 } } accu_var: @x0:0 accu_init: { - CREATE_LIST [26] { + CREATE_LIST [29] { elements: { } } } loop_condition: { - CONSTANT [27] { value: true } + CONSTANT [30] { value: true } } loop_step: { - CALL [28] { + CALL [31] { function: _+_ args: { - IDENT [29] { + IDENT [32] { name: @x0:0 } - CREATE_LIST [30] { - elements: { - IDENT [31] { - name: @index4 - } - } + IDENT [33] { + name: @index3 } } } } result: { - IDENT [32] { + IDENT [34] { name: @x0:0 } } } - } - } - CALL [33] { - function: _==_ - args: { - IDENT [34] { - name: @index5 - } - IDENT [35] { - name: @index3 + CREATE_LIST [35] { + elements: { + IDENT [36] { + name: @index0 + } + IDENT [37] { + name: @index0 + } + } } } } @@ -2257,78 +2098,84 @@ CALL [1] { CREATE_LIST [2] { elements: { CALL [3] { - function: _-_ + function: _>_ args: { - IDENT [4] { - name: x + CALL [4] { + function: _-_ + args: { + IDENT [5] { + name: x + } + CONSTANT [6] { value: 1 } + } } - CONSTANT [5] { value: 1 } + CONSTANT [7] { value: 3 } } } - CALL [6] { - function: _>_ - args: { - IDENT [7] { - name: @index0 + CREATE_LIST [8] { + elements: { + CALL [9] { + function: _?_:_ + args: { + IDENT [10] { + name: @index0 + } + CALL [11] { + function: _-_ + args: { + IDENT [12] { + name: x + } + CONSTANT [13] { value: 1 } + } + } + CONSTANT [14] { value: 5 } + } } - CONSTANT [8] { value: 3 } } } - CALL [9] { + CALL [15] { function: _||_ args: { - IDENT [10] { + IDENT [16] { name: @x0:0 } - CALL [11] { + CALL [17] { function: _>_ args: { - CALL [12] { + CALL [18] { function: _-_ args: { - IDENT [13] { + IDENT [19] { name: @c0:0 } - CONSTANT [14] { value: 1 } + CONSTANT [20] { value: 1 } } } - CONSTANT [15] { value: 3 } + CONSTANT [21] { value: 3 } } } } } - COMPREHENSION [16] { + COMPREHENSION [22] { iter_var: @c0:0 iter_range: { - CREATE_LIST [17] { - elements: { - CALL [18] { - function: _?_:_ - args: { - IDENT [19] { - name: @index1 - } - IDENT [20] { - name: @index0 - } - CONSTANT [21] { value: 5 } - } - } - } + IDENT [23] { + name: @index1 } } accu_var: @x0:0 accu_init: { - CONSTANT [22] { value: false } + CONSTANT [24] { value: false } } loop_condition: { - CALL [23] { + CALL [25] { function: @not_strictly_false args: { - CALL [24] { + CALL [26] { function: !_ args: { - IDENT [25] { + IDENT [27] { name: @x0:0 } } @@ -2337,26 +2184,26 @@ CALL [1] { } } loop_step: { - IDENT [26] { + IDENT [28] { name: @index2 } } result: { - IDENT [27] { + IDENT [29] { name: @x0:0 } } } } } - CALL [28] { + CALL [30] { function: _||_ args: { - IDENT [29] { + IDENT [31] { name: @index3 } - IDENT [30] { - name: @index1 + IDENT [32] { + name: @index0 } } } @@ -2396,17 +2243,17 @@ CALL [1] { function: _+_ args: { IDENT [10] { - name: @x0:0 + name: @x1:0 } CREATE_LIST [11] { elements: { CREATE_LIST [12] { elements: { IDENT [13] { - name: @index1 + name: @index0 } IDENT [14] { - name: @index1 + name: @index0 } } } @@ -2418,17 +2265,17 @@ CALL [1] { function: _+_ args: { IDENT [16] { - name: @x1:0 + name: @x0:0 } CREATE_LIST [17] { elements: { CREATE_LIST [18] { elements: { IDENT [19] { - name: @index0 + name: @index1 } IDENT [20] { - name: @index0 + name: @index1 } } } @@ -2436,63 +2283,60 @@ CALL [1] { } } } - COMPREHENSION [21] { + } + } + COMPREHENSION [21] { + iter_var: @c0:0 + iter_range: { + COMPREHENSION [22] { iter_var: @c1:0 iter_range: { - CREATE_LIST [22] { + CREATE_LIST [23] { elements: { - CONSTANT [23] { value: "foo" } - CONSTANT [24] { value: "bar" } + CONSTANT [24] { value: "foo" } + CONSTANT [25] { value: "bar" } } } } accu_var: @x1:0 accu_init: { - CREATE_LIST [25] { + CREATE_LIST [26] { elements: { } } } loop_condition: { - CONSTANT [26] { value: true } + CONSTANT [27] { value: true } } loop_step: { - IDENT [27] { - name: @index3 + IDENT [28] { + name: @index2 } } result: { - IDENT [28] { + IDENT [29] { name: @x1:0 } } } } - } - COMPREHENSION [29] { - iter_var: @c0:0 - iter_range: { - IDENT [30] { - name: @index4 - } - } accu_var: @x0:0 accu_init: { - CREATE_LIST [31] { + CREATE_LIST [30] { elements: { } } } loop_condition: { - CONSTANT [32] { value: true } + CONSTANT [31] { value: true } } loop_step: { - IDENT [33] { - name: @index2 + IDENT [32] { + name: @index3 } } result: { - IDENT [34] { + IDENT [33] { name: @x0:0 } } @@ -2517,27 +2361,24 @@ CALL [1] { } } } - CALL [7] { - function: _[_] - args: { - IDENT [8] { - name: @index0 - } - CONSTANT [9] { value: "a" } - } - } } } - CALL [10] { + CALL [7] { function: _&&_ args: { - SELECT [11] { - IDENT [12] { + SELECT [8] { + IDENT [9] { name: @index0 }.a~presence_test } - IDENT [13] { - name: @index1 + CALL [10] { + function: _[_] + args: { + IDENT [11] { + name: @index0 + } + CONSTANT [12] { value: "a" } + } } } } @@ -2596,51 +2437,47 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload - } - SELECT [7] { - IDENT [8] { - name: @index1 + SELECT [4] { + SELECT [5] { + IDENT [6] { + name: msg + }.oneof_type + }.payload }.single_int64 } - CALL [9] { + CALL [7] { function: _?_:_ args: { - SELECT [10] { - IDENT [11] { - name: @index0 + SELECT [8] { + SELECT [9] { + IDENT [10] { + name: msg + }.oneof_type }.payload~presence_test } - IDENT [12] { - name: @index2 + IDENT [11] { + name: @index0 } - CALL [13] { + CALL [12] { function: _*_ args: { - IDENT [14] { - name: @index2 + IDENT [13] { + name: @index0 } - CONSTANT [15] { value: 0 } + CONSTANT [14] { value: 0 } } } } } } } - CALL [16] { + CALL [15] { function: _==_ args: { - IDENT [17] { - name: @index3 + IDENT [16] { + name: @index1 } - CONSTANT [18] { value: 10 } + CONSTANT [17] { value: 10 } } } } @@ -2654,50 +2491,48 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload + SELECT [4] { + SELECT [5] { + IDENT [6] { + name: msg + }.oneof_type + }.payload + }.single_int64 } SELECT [7] { - IDENT [8] { - name: @index1 - }.single_int64 + SELECT [8] { + IDENT [9] { + name: msg + }.oneof_type + }.payload } - CALL [9] { + } + } + CALL [10] { + function: _==_ + args: { + CALL [11] { function: _?_:_ args: { - SELECT [10] { - IDENT [11] { + SELECT [12] { + IDENT [13] { name: @index1 }.single_int64~presence_test } - IDENT [12] { - name: @index2 + IDENT [14] { + name: @index0 } - CALL [13] { + CALL [15] { function: _*_ args: { - IDENT [14] { - name: @index2 + IDENT [16] { + name: @index0 } - CONSTANT [15] { value: 0 } + CONSTANT [17] { value: 0 } } } } } - } - } - CALL [16] { - function: _==_ - args: { - IDENT [17] { - name: @index3 - } CONSTANT [18] { value: 10 } } } @@ -2712,89 +2547,92 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type + SELECT [4] { + SELECT [5] { + IDENT [6] { + name: msg + }.oneof_type + }.payload + }.map_string_string } - SELECT [5] { - IDENT [6] { - name: @index0 + SELECT [7] { + SELECT [8] { + IDENT [9] { + name: msg + }.oneof_type }.payload } - SELECT [7] { - IDENT [8] { - name: @index1 - }.map_string_string + CALL [10] { + function: _&&_ + args: { + SELECT [11] { + IDENT [12] { + name: msg + }.oneof_type~presence_test + } + SELECT [13] { + SELECT [14] { + IDENT [15] { + name: msg + }.oneof_type + }.payload~presence_test + } + } } - CALL [9] { + CALL [16] { function: _?_:_ args: { - CALL [10] { + CALL [17] { function: _&&_ args: { - SELECT [11] { - IDENT [12] { + SELECT [18] { + IDENT [19] { name: @index1 }.map_string_string~presence_test } - SELECT [13] { - IDENT [14] { - name: @index2 + SELECT [20] { + IDENT [21] { + name: @index0 }.key~presence_test } } } - CALL [15] { + CALL [22] { function: _==_ args: { - SELECT [16] { - IDENT [17] { - name: @index2 + SELECT [23] { + IDENT [24] { + name: @index0 }.key } - CONSTANT [18] { value: "A" } + CONSTANT [25] { value: "A" } } } - CONSTANT [19] { value: false } + CONSTANT [26] { value: false } } } - CALL [20] { + } + } + CALL [27] { + function: _?_:_ + args: { + CALL [28] { function: _&&_ args: { - CALL [21] { - function: _&&_ - args: { - SELECT [22] { - IDENT [23] { - name: msg - }.oneof_type~presence_test - } - SELECT [24] { - IDENT [25] { - name: @index0 - }.payload~presence_test - } - } + IDENT [29] { + name: @index2 } - SELECT [26] { - IDENT [27] { + SELECT [30] { + IDENT [31] { name: @index1 }.single_int64~presence_test } } } - } - } - CALL [28] { - function: _?_:_ - args: { - IDENT [29] { - name: @index4 - } - IDENT [30] { + IDENT [32] { name: @index3 } - CONSTANT [31] { value: false } + CONSTANT [33] { value: false } } } } @@ -2807,44 +2645,49 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CALL [3] { - function: optional.none - args: { - } - } - CREATE_LIST [4] { + CREATE_LIST [3] { elements: { - IDENT [5] { - name: @index0 + CALL [4] { + function: optional.none + args: { + } } - IDENT [6] { + IDENT [5] { name: opt_x } } optional_indices: [0, 1] } - CREATE_LIST [7] { + CREATE_LIST [6] { elements: { - CONSTANT [8] { value: 5 } + CONSTANT [7] { value: 5 } } } + } + } + CALL [8] { + function: _==_ + args: { CREATE_LIST [9] { elements: { CONSTANT [10] { value: 10 } - IDENT [11] { - name: @index2 + CALL [11] { + function: optional.none + args: { + } } IDENT [12] { - name: @index2 + name: @index0 + } + IDENT [13] { + name: @index0 } } + optional_indices: [0] } - CREATE_LIST [13] { + CREATE_LIST [14] { elements: { - CONSTANT [14] { value: 10 } - IDENT [15] { - name: @index0 - } + CONSTANT [15] { value: 10 } IDENT [16] { name: @index1 } @@ -2852,18 +2695,6 @@ CALL [1] { name: @index1 } } - optional_indices: [0] - } - } - } - CALL [18] { - function: _==_ - args: { - IDENT [19] { - name: @index4 - } - IDENT [20] { - name: @index3 } } } @@ -2878,53 +2709,44 @@ CALL [1] { CREATE_LIST [2] { elements: { CALL [3] { - function: optional.of - args: { - CONSTANT [4] { value: "hello" } - } - } - CREATE_MAP [5] { - MAP_ENTRY [6] { - key: { - CONSTANT [7] { value: "hello" } - } - optional_entry: true - value: { - IDENT [8] { - name: @index0 - } - } - } - } - CALL [9] { function: _[_] args: { - IDENT [10] { - name: @index1 + CREATE_MAP [4] { + MAP_ENTRY [5] { + key: { + CONSTANT [6] { value: "hello" } + } + optional_entry: true + value: { + CALL [7] { + function: optional.of + args: { + CONSTANT [8] { value: "hello" } + } + } + } + } } - CONSTANT [11] { value: "hello" } + CONSTANT [9] { value: "hello" } } } - CALL [12] { + } + } + CALL [10] { + function: _==_ + args: { + CALL [11] { function: _+_ args: { - IDENT [13] { - name: @index2 + IDENT [12] { + name: @index0 } - IDENT [14] { - name: @index2 + IDENT [13] { + name: @index0 } } } - } - } - CALL [15] { - function: _==_ - args: { - IDENT [16] { - name: @index3 - } - CONSTANT [17] { value: "hellohello" } + CONSTANT [14] { value: "hellohello" } } } } @@ -2948,77 +2770,71 @@ CALL [1] { } } CALL [7] { - function: _[_] - args: { - IDENT [8] { - name: @index0 - } - CONSTANT [9] { value: "key" } - } - } - CALL [10] { function: _[?_] args: { - IDENT [11] { - name: @index0 - } - CONSTANT [12] { value: "bogus" } - } - } - CALL [13] { - function: _[?_] - args: { - CREATE_MAP [14] { - MAP_ENTRY [15] { + CREATE_MAP [8] { + MAP_ENTRY [9] { key: { - CONSTANT [16] { value: "key" } + CONSTANT [10] { value: "key" } } optional_entry: true value: { - CALL [17] { + CALL [11] { function: optional.of args: { - CONSTANT [18] { value: "test" } + CONSTANT [12] { value: "test" } } } } } } - CONSTANT [19] { value: "bogus" } + CONSTANT [13] { value: "bogus" } } } - CALL [20] { + CALL [14] { function: orValue target: { - CALL [21] { + CALL [15] { function: or target: { - IDENT [22] { - name: @index3 + IDENT [16] { + name: @index1 } } args: { - IDENT [23] { - name: @index2 + CALL [17] { + function: _[?_] + args: { + IDENT [18] { + name: @index0 + } + CONSTANT [19] { value: "bogus" } + } } } } } args: { - IDENT [24] { - name: @index1 + CALL [20] { + function: _[_] + args: { + IDENT [21] { + name: @index0 + } + CONSTANT [22] { value: "key" } + } } } } } } - CALL [25] { + CALL [23] { function: _==_ args: { - IDENT [26] { - name: @index4 + IDENT [24] { + name: @index2 } - CONSTANT [27] { value: "test" } + CONSTANT [25] { value: "test" } } } } @@ -3031,65 +2847,56 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CALL [3] { - function: optional.ofNonZeroValue - args: { - CONSTANT [4] { value: 1 } - } - } - CALL [5] { - function: optional.of - args: { - CONSTANT [6] { value: 4 } - } - } - CREATE_STRUCT [7] { + CREATE_STRUCT [3] { name: TestAllTypes entries: { - ENTRY [8] { + ENTRY [4] { field_key: single_int64 optional_entry: true value: { - IDENT [9] { - name: @index0 + CALL [5] { + function: optional.ofNonZeroValue + args: { + CONSTANT [6] { value: 1 } + } } } } - ENTRY [10] { + ENTRY [7] { field_key: single_int32 optional_entry: true value: { - IDENT [11] { - name: @index1 + CALL [8] { + function: optional.of + args: { + CONSTANT [9] { value: 4 } + } } } } } } - CALL [12] { + } + } + CALL [10] { + function: _==_ + args: { + CALL [11] { function: _+_ args: { - SELECT [13] { - IDENT [14] { - name: @index2 + SELECT [12] { + IDENT [13] { + name: @index0 }.single_int32 } - SELECT [15] { - IDENT [16] { - name: @index2 + SELECT [14] { + IDENT [15] { + name: @index0 }.single_int64 } } } - } - } - CALL [17] { - function: _==_ - args: { - IDENT [18] { - name: @index3 - } - CONSTANT [19] { value: 5 } + CONSTANT [16] { value: 5 } } } } @@ -3101,62 +2908,53 @@ CALL [1] { function: cel.@block args: { CREATE_LIST [2] { - elements: { - CALL [3] { - function: _+_ - args: { - CONSTANT [4] { value: "h" } - CONSTANT [5] { value: "e" } - } - } - CALL [6] { - function: _+_ - args: { - IDENT [7] { - name: @index0 - } - CONSTANT [8] { value: "l" } - } - } - CALL [9] { - function: _+_ - args: { - IDENT [10] { - name: @index1 - } - CONSTANT [11] { value: "l" } - } - } - CALL [12] { + elements: { + CALL [3] { function: _+_ args: { - IDENT [13] { - name: @index2 + CALL [4] { + function: _+_ + args: { + CALL [5] { + function: _+_ + args: { + CONSTANT [6] { value: "h" } + CONSTANT [7] { value: "e" } + } + } + CONSTANT [8] { value: "l" } + } } - CONSTANT [14] { value: "o" } + CONSTANT [9] { value: "l" } } } - CALL [15] { + CALL [10] { function: _+_ args: { - IDENT [16] { - name: @index3 + IDENT [11] { + name: @index0 } - CONSTANT [17] { value: " world" } + CONSTANT [12] { value: "o" } } } } } - CALL [18] { + CALL [13] { function: matches target: { - IDENT [19] { - name: @index4 + CALL [14] { + function: _+_ + args: { + IDENT [15] { + name: @index1 + } + CONSTANT [16] { value: " world" } + } } } args: { - IDENT [20] { - name: @index3 + IDENT [17] { + name: @index1 } } } @@ -3189,25 +2987,22 @@ CALL [1] { CONSTANT [9] { value: "l" } } } - CALL [10] { - function: _+_ - args: { - IDENT [11] { - name: @index0 - } - CONSTANT [12] { value: "o" } - } - } } } - CALL [13] { + CALL [10] { function: matches target: { - CONSTANT [14] { value: "hello world" } + CONSTANT [11] { value: "hello world" } } args: { - IDENT [15] { - name: @index1 + CALL [12] { + function: _+_ + args: { + IDENT [13] { + name: @index0 + } + CONSTANT [14] { value: "o" } + } } } } @@ -3240,32 +3035,29 @@ CALL [1] { CONSTANT [9] { value: "l" } } } - CALL [10] { + } + } + CALL [10] { + function: matches + target: { + CALL [11] { function: _+_ args: { - CALL [11] { + CALL [12] { function: _+_ args: { - IDENT [12] { + IDENT [13] { name: @index0 } - CONSTANT [13] { value: "o" } + CONSTANT [14] { value: "o" } } } - CONSTANT [14] { value: " world" } + CONSTANT [15] { value: " world" } } } } - } - CALL [15] { - function: matches - target: { - IDENT [16] { - name: @index1 - } - } args: { - CONSTANT [17] { value: "hello" } + CONSTANT [16] { value: "hello" } } } } @@ -3287,11 +3079,11 @@ CALL [1] { CALL [5] { function: _+_ args: { - CONSTANT [6] { value: "w" } - CONSTANT [7] { value: "o" } + CONSTANT [6] { value: "h" } + CONSTANT [7] { value: "e" } } } - CONSTANT [8] { value: "r" } + CONSTANT [8] { value: "l" } } } CONSTANT [9] { value: "l" } @@ -3300,58 +3092,52 @@ CALL [1] { CALL [10] { function: _+_ args: { - IDENT [11] { - name: @index0 - } - CONSTANT [12] { value: "d" } - } - } - CALL [13] { - function: _+_ - args: { - CALL [14] { + CALL [11] { function: _+_ args: { - CALL [15] { + CALL [12] { function: _+_ args: { - CONSTANT [16] { value: "h" } - CONSTANT [17] { value: "e" } + CONSTANT [13] { value: "w" } + CONSTANT [14] { value: "o" } } } - CONSTANT [18] { value: "l" } + CONSTANT [15] { value: "r" } } } - CONSTANT [19] { value: "l" } + CONSTANT [16] { value: "l" } } } - CALL [20] { + } + } + CALL [17] { + function: matches + target: { + CALL [18] { function: _+_ args: { - CALL [21] { + CALL [19] { function: _+_ args: { - IDENT [22] { - name: @index2 + IDENT [20] { + name: @index0 } - CONSTANT [23] { value: "o" } + CONSTANT [21] { value: "o" } } } - CONSTANT [24] { value: " world" } + CONSTANT [22] { value: " world" } } } } - } - CALL [25] { - function: matches - target: { - IDENT [26] { - name: @index3 - } - } args: { - IDENT [27] { - name: @index1 + CALL [23] { + function: _+_ + args: { + IDENT [24] { + name: @index1 + } + CONSTANT [25] { value: "d" } + } } } } @@ -3366,74 +3152,66 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload - } - SELECT [7] { - IDENT [8] { - name: @index1 - }.single_int64 - } - SELECT [9] { - IDENT [10] { - name: msg + SELECT [4] { + SELECT [5] { + IDENT [6] { + name: msg + }.oneof_type + }.payload }.single_int64 } - SELECT [11] { - IDENT [12] { - name: @index1 - }.single_int32 - } } } - CALL [13] { + CALL [7] { function: _+_ args: { - CALL [14] { + CALL [8] { function: _+_ args: { - CALL [15] { + CALL [9] { function: _+_ args: { - CALL [16] { + CALL [10] { function: non_pure_custom_func args: { - IDENT [17] { - name: @index2 + IDENT [11] { + name: @index0 } } } - CALL [18] { + CALL [12] { function: non_pure_custom_func args: { - IDENT [19] { - name: @index4 + SELECT [13] { + SELECT [14] { + SELECT [15] { + IDENT [16] { + name: msg + }.oneof_type + }.payload + }.single_int32 } } } } } - CALL [20] { + CALL [17] { function: non_pure_custom_func args: { - IDENT [21] { - name: @index2 + IDENT [18] { + name: @index0 } } } } } - CALL [22] { + CALL [19] { function: non_pure_custom_func args: { - IDENT [23] { - name: @index3 + SELECT [20] { + IDENT [21] { + name: msg + }.single_int64 } } } @@ -3450,77 +3228,72 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload - } - SELECT [7] { - IDENT [8] { - name: @index1 + SELECT [4] { + SELECT [5] { + IDENT [6] { + name: msg + }.oneof_type + }.payload }.single_int64 } - CALL [9] { + CALL [7] { function: pure_custom_func args: { - IDENT [10] { - name: @index2 + IDENT [8] { + name: @index0 } } } - CALL [11] { - function: pure_custom_func - args: { - SELECT [12] { - IDENT [13] { + SELECT [9] { + SELECT [10] { + SELECT [11] { + IDENT [12] { name: msg - }.single_int64 - } - } + }.oneof_type + }.payload + }.single_int32 } - CALL [14] { + CALL [13] { function: _+_ args: { - IDENT [15] { - name: @index3 - } - CALL [16] { - function: pure_custom_func + CALL [14] { + function: _+_ args: { - SELECT [17] { - IDENT [18] { - name: @index1 - }.single_int32 + IDENT [15] { + name: @index1 + } + CALL [16] { + function: pure_custom_func + args: { + IDENT [17] { + name: @index2 + } + } } } } - } - } - CALL [19] { - function: _+_ - args: { - IDENT [20] { - name: @index5 - } - IDENT [21] { - name: @index3 + IDENT [18] { + name: @index1 } } } } } - CALL [22] { + CALL [19] { function: _+_ args: { - IDENT [23] { - name: @index6 + IDENT [20] { + name: @index3 } - IDENT [24] { - name: @index4 + CALL [21] { + function: pure_custom_func + args: { + SELECT [22] { + IDENT [23] { + name: msg + }.single_int64 + } + } } } } diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_4.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_4.baseline index 71a440692..9b7787c5a 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_4.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_4.baseline @@ -6,20 +6,22 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_LIST [3] { - elements: { - CONSTANT [4] { value: 1 } - CONSTANT [5] { value: 2 } - } - } - CALL [6] { + CALL [3] { function: size args: { - IDENT [7] { - name: @index0 + CREATE_LIST [4] { + elements: { + CONSTANT [5] { value: 1 } + CONSTANT [6] { value: 2 } + } } } } + } + } + CALL [7] { + function: _==_ + args: { CALL [8] { function: _+_ args: { @@ -27,25 +29,17 @@ CALL [1] { function: _+_ args: { IDENT [10] { - name: @index1 + name: @index0 } IDENT [11] { - name: @index1 + name: @index0 } } } CONSTANT [12] { value: 1 } } } - } - } - CALL [13] { - function: _==_ - args: { - IDENT [14] { - name: @index2 - } - CONSTANT [15] { value: 5 } + CONSTANT [13] { value: 5 } } } } @@ -58,20 +52,22 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_LIST [3] { - elements: { - CONSTANT [4] { value: 1 } - CONSTANT [5] { value: 2 } - } - } - CALL [6] { + CALL [3] { function: size args: { - IDENT [7] { - name: @index0 + CREATE_LIST [4] { + elements: { + CONSTANT [5] { value: 1 } + CONSTANT [6] { value: 2 } + } } } } + } + } + CALL [7] { + function: _==_ + args: { CALL [8] { function: _+_ args: { @@ -83,27 +79,19 @@ CALL [1] { args: { CONSTANT [11] { value: 2 } IDENT [12] { - name: @index1 + name: @index0 } } } IDENT [13] { - name: @index1 + name: @index0 } } } CONSTANT [14] { value: 1 } } } - } - } - CALL [15] { - function: _==_ - args: { - IDENT [16] { - name: @index2 - } - CONSTANT [17] { value: 7 } + CONSTANT [15] { value: 7 } } } } @@ -116,69 +104,60 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_LIST [3] { - elements: { - CONSTANT [4] { value: 0 } - } - } - CALL [5] { + CALL [3] { function: size args: { - IDENT [6] { - name: @index0 + CREATE_LIST [4] { + elements: { + CONSTANT [5] { value: 0 } + } } } } - CREATE_LIST [7] { - elements: { - CONSTANT [8] { value: 1 } - CONSTANT [9] { value: 2 } - } - } - CALL [10] { + CALL [6] { function: size args: { - IDENT [11] { - name: @index2 + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 1 } + CONSTANT [9] { value: 2 } + } } } } - CALL [12] { + } + } + CALL [10] { + function: _==_ + args: { + CALL [11] { function: _+_ args: { - CALL [13] { + CALL [12] { function: _+_ args: { - CALL [14] { + CALL [13] { function: _+_ args: { - IDENT [15] { - name: @index1 + IDENT [14] { + name: @index0 } - IDENT [16] { - name: @index1 + IDENT [15] { + name: @index0 } } } - IDENT [17] { - name: @index3 + IDENT [16] { + name: @index1 } } } - IDENT [18] { - name: @index3 + IDENT [17] { + name: @index1 } } } - } - } - CALL [19] { - function: _==_ - args: { - IDENT [20] { - name: @index4 - } - CONSTANT [21] { value: 6 } + CONSTANT [18] { value: 6 } } } } @@ -191,109 +170,97 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_LIST [3] { - elements: { - CONSTANT [4] { value: 0 } - } - } - CALL [5] { + CALL [3] { function: size args: { - IDENT [6] { - name: @index0 + CREATE_LIST [4] { + elements: { + CONSTANT [5] { value: 0 } + } } } } - CREATE_LIST [7] { - elements: { - CONSTANT [8] { value: 1 } - CONSTANT [9] { value: 2 } - } - } - CALL [10] { + CALL [6] { function: size args: { - IDENT [11] { - name: @index2 + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 1 } + CONSTANT [9] { value: 2 } + } } } } - CREATE_LIST [12] { - elements: { - CONSTANT [13] { value: 1 } - CONSTANT [14] { value: 2 } - CONSTANT [15] { value: 3 } - } - } - CALL [16] { + CALL [10] { function: size args: { - IDENT [17] { - name: @index4 + CREATE_LIST [11] { + elements: { + CONSTANT [12] { value: 1 } + CONSTANT [13] { value: 2 } + CONSTANT [14] { value: 3 } + } } } } - CALL [18] { + CALL [15] { function: _+_ args: { - CALL [19] { + CALL [16] { function: _+_ args: { - CALL [20] { + CALL [17] { function: _+_ args: { - CALL [21] { + CALL [18] { function: _+_ args: { - CONSTANT [22] { value: 5 } - IDENT [23] { - name: @index1 + CONSTANT [19] { value: 5 } + IDENT [20] { + name: @index0 } } } - IDENT [24] { - name: @index1 + IDENT [21] { + name: @index0 } } } - IDENT [25] { - name: @index3 + IDENT [22] { + name: @index1 } } } - IDENT [26] { - name: @index3 + IDENT [23] { + name: @index1 } } } - CALL [27] { + } + } + CALL [24] { + function: _==_ + args: { + CALL [25] { function: _+_ args: { - CALL [28] { + CALL [26] { function: _+_ args: { - IDENT [29] { - name: @index6 + IDENT [27] { + name: @index3 } - IDENT [30] { - name: @index5 + IDENT [28] { + name: @index2 } } } - IDENT [31] { - name: @index5 + IDENT [29] { + name: @index2 } } } - } - } - CALL [32] { - function: _==_ - args: { - IDENT [33] { - name: @index7 - } - CONSTANT [34] { value: 17 } + CONSTANT [30] { value: 17 } } } } @@ -307,150 +274,100 @@ CALL [1] { CREATE_LIST [2] { elements: { CALL [3] { - function: timestamp - args: { - CONSTANT [4] { value: 1000000000 } - } - } - CALL [5] { - function: int - args: { - IDENT [6] { - name: @index0 + function: getFullYear + target: { + CALL [4] { + function: timestamp + args: { + CALL [5] { + function: int + args: { + CALL [6] { + function: timestamp + args: { + CONSTANT [7] { value: 1000000000 } + } + } + } + } + } } } - } - CALL [7] { - function: timestamp args: { - IDENT [8] { - name: @index1 - } } } - CALL [9] { + CALL [8] { function: getFullYear target: { - IDENT [10] { - name: @index2 + CALL [9] { + function: timestamp + args: { + CALL [10] { + function: int + args: { + CALL [11] { + function: timestamp + args: { + CONSTANT [12] { value: 200 } + } + } + } + } + } } } args: { } } - CALL [11] { - function: timestamp - args: { - CONSTANT [12] { value: 50 } - } - } CALL [13] { - function: int - args: { - IDENT [14] { - name: @index4 - } - } - } - CALL [15] { function: timestamp args: { - IDENT [16] { - name: @index5 + CALL [14] { + function: int + args: { + CALL [15] { + function: timestamp + args: { + CONSTANT [16] { value: 50 } + } + } + } } } } CALL [17] { function: timestamp args: { - CONSTANT [18] { value: 200 } - } - } - CALL [19] { - function: int - args: { - IDENT [20] { - name: @index7 + CALL [18] { + function: int + args: { + CALL [19] { + function: timestamp + args: { + CONSTANT [20] { value: 75 } + } + } + } } } } CALL [21] { - function: timestamp - args: { - IDENT [22] { - name: @index8 - } - } - } - CALL [23] { - function: getFullYear - target: { - IDENT [24] { - name: @index9 - } - } + function: _+_ args: { - } - } - CALL [25] { - function: timestamp - args: { - CONSTANT [26] { value: 75 } - } - } - CALL [27] { - function: int - args: { - IDENT [28] { - name: @index11 - } - } - } - CALL [29] { - function: timestamp - args: { - IDENT [30] { - name: @index12 - } - } - } - CALL [31] { - function: getMinutes - target: { - IDENT [32] { - name: @index13 - } - } - args: { - } - } - CALL [33] { - function: getSeconds - target: { - IDENT [34] { - name: @index6 - } - } - args: { - } - } - CALL [35] { - function: _+_ - args: { - CALL [36] { + CALL [22] { function: _+_ args: { - CALL [37] { + CALL [23] { function: _+_ args: { - IDENT [38] { - name: @index3 + IDENT [24] { + name: @index0 } - CALL [39] { + CALL [25] { function: getFullYear target: { - IDENT [40] { - name: @index13 + IDENT [26] { + name: @index3 } } args: { @@ -458,11 +375,11 @@ CALL [1] { } } } - CALL [41] { + CALL [27] { function: getFullYear target: { - IDENT [42] { - name: @index6 + IDENT [28] { + name: @index2 } } args: { @@ -470,66 +387,77 @@ CALL [1] { } } } - IDENT [43] { - name: @index3 + IDENT [29] { + name: @index0 } } } - CALL [44] { + CALL [30] { function: _+_ args: { - CALL [45] { + CALL [31] { function: _+_ args: { - CALL [46] { + CALL [32] { function: _+_ args: { - CALL [47] { - function: _+_ - args: { - IDENT [48] { - name: @index16 - } - IDENT [49] { - name: @index15 + IDENT [33] { + name: @index4 + } + CALL [34] { + function: getSeconds + target: { + IDENT [35] { + name: @index2 } } - } - IDENT [50] { - name: @index10 + args: { + } } } } - IDENT [51] { - name: @index10 + IDENT [36] { + name: @index1 } } } - IDENT [52] { - name: @index14 + IDENT [37] { + name: @index1 } } } - CALL [53] { + } + } + CALL [38] { + function: _==_ + args: { + CALL [39] { function: _+_ args: { - IDENT [54] { - name: @index17 + CALL [40] { + function: _+_ + args: { + IDENT [41] { + name: @index5 + } + CALL [42] { + function: getMinutes + target: { + IDENT [43] { + name: @index3 + } + } + args: { + } + } + } } - IDENT [55] { - name: @index3 + IDENT [44] { + name: @index0 } } } - } - } - CALL [56] { - function: _==_ - args: { - IDENT [57] { - name: @index18 - } - CONSTANT [58] { value: 13934 } + CONSTANT [45] { value: 13934 } } } } @@ -542,53 +470,47 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_MAP [3] { - MAP_ENTRY [4] { - key: { - CONSTANT [5] { value: "a" } - } - value: { - CONSTANT [6] { value: 2 } - } - } - } - CALL [7] { + CALL [3] { function: _[_] args: { - IDENT [8] { - name: @index0 + CREATE_MAP [4] { + MAP_ENTRY [5] { + key: { + CONSTANT [6] { value: "a" } + } + value: { + CONSTANT [7] { value: 2 } + } + } } - CONSTANT [9] { value: "a" } + CONSTANT [8] { value: "a" } } } + } + } + CALL [9] { + function: _==_ + args: { CALL [10] { function: _+_ args: { IDENT [11] { - name: @index1 + name: @index0 } CALL [12] { function: _*_ args: { IDENT [13] { - name: @index1 + name: @index0 } IDENT [14] { - name: @index1 + name: @index0 } } } } } - } - } - CALL [15] { - function: _==_ - args: { - IDENT [16] { - name: @index2 - } - CONSTANT [17] { value: 6 } + CONSTANT [15] { value: 6 } } } } @@ -604,51 +526,48 @@ CALL [1] { CREATE_MAP [3] { MAP_ENTRY [4] { key: { - CONSTANT [5] { value: "b" } + CONSTANT [5] { value: "e" } } value: { - CONSTANT [6] { value: 1 } + CREATE_MAP [6] { + MAP_ENTRY [7] { + key: { + CONSTANT [8] { value: "b" } + } + value: { + CONSTANT [9] { value: 1 } + } + } + } } } } - CREATE_MAP [7] { - MAP_ENTRY [8] { + CREATE_MAP [10] { + MAP_ENTRY [11] { key: { - CONSTANT [9] { value: "e" } + CONSTANT [12] { value: "b" } } value: { - IDENT [10] { - name: @index0 - } + CONSTANT [13] { value: 1 } } } } } } - CREATE_MAP [11] { - MAP_ENTRY [12] { - key: { - CONSTANT [13] { value: "a" } - } - value: { - IDENT [14] { - name: @index0 - } - } - } + CREATE_MAP [14] { MAP_ENTRY [15] { key: { - CONSTANT [16] { value: "c" } + CONSTANT [16] { value: "a" } } value: { IDENT [17] { - name: @index0 + name: @index1 } } } MAP_ENTRY [18] { key: { - CONSTANT [19] { value: "d" } + CONSTANT [19] { value: "c" } } value: { IDENT [20] { @@ -658,11 +577,21 @@ CALL [1] { } MAP_ENTRY [21] { key: { - CONSTANT [22] { value: "e" } + CONSTANT [22] { value: "d" } } value: { IDENT [23] { - name: @index1 + name: @index0 + } + } + } + MAP_ENTRY [24] { + key: { + CONSTANT [25] { value: "e" } + } + value: { + IDENT [26] { + name: @index0 } } } @@ -691,37 +620,34 @@ CALL [1] { CONSTANT [10] { value: 2 } } } - CREATE_LIST [11] { - elements: { - IDENT [12] { - name: @index1 - } - IDENT [13] { - name: @index0 - } - } - } } } - CREATE_LIST [14] { + CREATE_LIST [11] { elements: { - CONSTANT [15] { value: 1 } - IDENT [16] { + CONSTANT [12] { value: 1 } + IDENT [13] { name: @index0 } - CONSTANT [17] { value: 2 } - IDENT [18] { + CONSTANT [14] { value: 2 } + IDENT [15] { name: @index0 } - CONSTANT [19] { value: 5 } - IDENT [20] { + CONSTANT [16] { value: 5 } + IDENT [17] { name: @index0 } - CONSTANT [21] { value: 7 } - IDENT [22] { - name: @index2 + CONSTANT [18] { value: 7 } + CREATE_LIST [19] { + elements: { + IDENT [20] { + name: @index1 + } + IDENT [21] { + name: @index0 + } + } } - IDENT [23] { + IDENT [22] { name: @index1 } } @@ -741,26 +667,23 @@ CALL [1] { name: msg }.single_int64 } - CALL [5] { + } + } + CALL [5] { + function: _==_ + args: { + CALL [6] { function: _+_ args: { - IDENT [6] { + IDENT [7] { name: @index0 } - IDENT [7] { + IDENT [8] { name: @index0 } } } - } - } - CALL [8] { - function: _==_ - args: { - IDENT [9] { - name: @index1 - } - CONSTANT [10] { value: 6 } + CONSTANT [9] { value: 6 } } } } @@ -774,68 +697,66 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload - } - SELECT [7] { - IDENT [8] { - name: @index1 - }.single_int64 - } - SELECT [9] { - SELECT [10] { - SELECT [11] { - IDENT [12] { - name: @index1 + SELECT [4] { + SELECT [5] { + IDENT [6] { + name: msg }.oneof_type }.payload }.single_int64 } - CALL [13] { + SELECT [7] { + SELECT [8] { + IDENT [9] { + name: msg + }.oneof_type + }.payload + } + CALL [10] { function: _+_ args: { - CALL [14] { + CALL [11] { function: _+_ args: { - CALL [15] { + CALL [12] { function: _+_ args: { - IDENT [16] { - name: @index2 + IDENT [13] { + name: @index0 } - SELECT [17] { - IDENT [18] { + SELECT [14] { + IDENT [15] { name: @index1 }.single_int32 } } } - IDENT [19] { - name: @index2 + IDENT [16] { + name: @index0 } } } - SELECT [20] { - IDENT [21] { + SELECT [17] { + IDENT [18] { name: msg }.single_int64 } } } - CALL [22] { + CALL [19] { function: _+_ args: { - IDENT [23] { - name: @index4 + IDENT [20] { + name: @index2 } - IDENT [24] { - name: @index3 + SELECT [21] { + SELECT [22] { + SELECT [23] { + IDENT [24] { + name: @index1 + }.oneof_type + }.payload + }.single_int64 } } } @@ -845,7 +766,7 @@ CALL [1] { function: _==_ args: { IDENT [26] { - name: @index5 + name: @index3 } CONSTANT [27] { value: 31 } } @@ -861,71 +782,59 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 + SELECT [4] { + SELECT [5] { + SELECT [6] { + IDENT [7] { + name: msg + }.oneof_type + }.payload + }.oneof_type }.payload } - SELECT [7] { - IDENT [8] { - name: @index1 + SELECT [8] { + IDENT [9] { + name: @index0 }.oneof_type } - SELECT [9] { - IDENT [10] { - name: @index2 - }.payload - } - SELECT [11] { - IDENT [12] { - name: @index3 - }.oneof_type + SELECT [10] { + SELECT [11] { + SELECT [12] { + SELECT [13] { + IDENT [14] { + name: @index1 + }.payload + }.oneof_type + }.payload + }.single_bool } - SELECT [13] { - SELECT [14] { - SELECT [15] { - SELECT [16] { - IDENT [17] { - name: @index4 + SELECT [15] { + SELECT [16] { + SELECT [17] { + SELECT [18] { + IDENT [19] { + name: @index1 }.child }.child }.payload }.single_bool } - SELECT [18] { - SELECT [19] { - SELECT [20] { - SELECT [21] { - IDENT [22] { - name: @index4 - }.payload - }.oneof_type - }.payload - }.single_bool - } - CALL [23] { - function: _||_ - args: { - CONSTANT [24] { value: true } - IDENT [25] { - name: @index6 - } - } - } } } - CALL [26] { + CALL [20] { function: _||_ args: { - IDENT [27] { - name: @index7 + CALL [21] { + function: _||_ + args: { + CONSTANT [22] { value: true } + IDENT [23] { + name: @index2 + } + } } - IDENT [28] { - name: @index5 + IDENT [24] { + name: @index3 } } } @@ -939,58 +848,46 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload - } - SELECT [7] { - IDENT [8] { - name: @index1 - }.map_int32_int64 - } - CALL [9] { + CALL [3] { function: _[_] args: { - IDENT [10] { - name: @index2 + SELECT [4] { + SELECT [5] { + SELECT [6] { + IDENT [7] { + name: msg + }.oneof_type + }.payload + }.map_int32_int64 } - CONSTANT [11] { value: 1 } + CONSTANT [8] { value: 1 } } } - CALL [12] { + } + } + CALL [9] { + function: _==_ + args: { + CALL [10] { function: _+_ args: { - CALL [13] { + CALL [11] { function: _+_ args: { - IDENT [14] { - name: @index3 + IDENT [12] { + name: @index0 } - IDENT [15] { - name: @index3 + IDENT [13] { + name: @index0 } } } - IDENT [16] { - name: @index3 + IDENT [14] { + name: @index0 } } } - } - } - CALL [17] { - function: _==_ - args: { - IDENT [18] { - name: @index4 - } - CONSTANT [19] { value: 15 } + CONSTANT [15] { value: 15 } } } } @@ -1004,66 +901,57 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload - } - SELECT [7] { - IDENT [8] { - name: @index1 + SELECT [4] { + SELECT [5] { + IDENT [6] { + name: msg + }.oneof_type + }.payload }.map_int32_int64 } - CALL [9] { + } + } + CALL [7] { + function: _==_ + args: { + CALL [8] { function: _+_ args: { - CALL [10] { + CALL [9] { function: _+_ args: { - CALL [11] { + CALL [10] { function: _[_] args: { - IDENT [12] { - name: @index2 + IDENT [11] { + name: @index0 } - CONSTANT [13] { value: 0 } + CONSTANT [12] { value: 0 } } } - CALL [14] { + CALL [13] { function: _[_] args: { - IDENT [15] { - name: @index2 + IDENT [14] { + name: @index0 } - CONSTANT [16] { value: 1 } + CONSTANT [15] { value: 1 } } } } } - CALL [17] { + CALL [16] { function: _[_] args: { - IDENT [18] { - name: @index2 + IDENT [17] { + name: @index0 } - CONSTANT [19] { value: 2 } + CONSTANT [18] { value: 2 } } } } } - } - } - CALL [20] { - function: _==_ - args: { - IDENT [21] { - name: @index3 - } - CONSTANT [22] { value: 8 } + CONSTANT [19] { value: 8 } } } } @@ -1120,33 +1008,30 @@ CALL [1] { name: msg }.single_int64 } - CALL [5] { + } + } + CALL [5] { + function: _==_ + args: { + CALL [6] { function: _?_:_ args: { - CALL [6] { + CALL [7] { function: _>_ args: { - IDENT [7] { + IDENT [8] { name: @index0 } - CONSTANT [8] { value: 0 } + CONSTANT [9] { value: 0 } } } - IDENT [9] { + IDENT [10] { name: @index0 } - CONSTANT [10] { value: 0 } + CONSTANT [11] { value: 0 } } } - } - } - CALL [11] { - function: _==_ - args: { - IDENT [12] { - name: @index1 - } - CONSTANT [13] { value: 3 } + CONSTANT [12] { value: 3 } } } } @@ -1225,56 +1110,53 @@ CALL [1] { name: msg }.single_int32 } - CALL [7] { + } + } + CALL [7] { + function: _==_ + args: { + CALL [8] { function: _?_:_ args: { - CALL [8] { + CALL [9] { function: _>_ args: { - IDENT [9] { + IDENT [10] { name: @index0 } - CONSTANT [10] { value: 0 } + CONSTANT [11] { value: 0 } } } - CALL [11] { + CALL [12] { function: _?_:_ args: { - CALL [12] { + CALL [13] { function: _>_ args: { - IDENT [13] { + IDENT [14] { name: @index1 } - CONSTANT [14] { value: 0 } + CONSTANT [15] { value: 0 } } } - CALL [15] { + CALL [16] { function: _+_ args: { - IDENT [16] { + IDENT [17] { name: @index0 } - IDENT [17] { + IDENT [18] { name: @index1 } } } - CONSTANT [18] { value: 0 } + CONSTANT [19] { value: 0 } } } - CONSTANT [19] { value: 0 } + CONSTANT [20] { value: 0 } } } - } - } - CALL [20] { - function: _==_ - args: { - IDENT [21] { - name: @index2 - } - CONSTANT [22] { value: 8 } + CONSTANT [21] { value: 8 } } } } @@ -1289,194 +1171,167 @@ CALL [1] { elements: { CREATE_LIST [3] { elements: { - CONSTANT [4] { value: 1 } - } - } - CALL [5] { - function: _>_ - args: { - IDENT [6] { - name: @c0:0 - } - CONSTANT [7] { value: 0 } - } - } - CALL [8] { - function: _||_ - args: { - IDENT [9] { - name: @x0:0 - } - IDENT [10] { - name: @index1 - } - } - } - COMPREHENSION [11] { - iter_var: @c0:0 - iter_range: { - IDENT [12] { - name: @index0 - } - } - accu_var: @x0:0 - accu_init: { - CONSTANT [13] { value: false } - } - loop_condition: { - CALL [14] { - function: @not_strictly_false - args: { - CALL [15] { - function: !_ + COMPREHENSION [4] { + iter_var: @c0:0 + iter_range: { + CREATE_LIST [5] { + elements: { + CONSTANT [6] { value: 1 } + } + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [7] { value: false } + } + loop_condition: { + CALL [8] { + function: @not_strictly_false args: { - IDENT [16] { + CALL [9] { + function: !_ + args: { + IDENT [10] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + CALL [11] { + function: _||_ + args: { + IDENT [12] { name: @x0:0 } + CALL [13] { + function: _>_ + args: { + IDENT [14] { + name: @c0:0 + } + CONSTANT [15] { value: 0 } + } + } } } } - } - } - loop_step: { - IDENT [17] { - name: @index2 - } - } - result: { - IDENT [18] { - name: @x0:0 - } - } - } - CREATE_LIST [19] { - elements: { - IDENT [20] { - name: @index3 - } - } - } - CALL [21] { - function: size - args: { - IDENT [22] { - name: @index4 + result: { + IDENT [16] { + name: @x0:0 + } + } } } } - CREATE_LIST [23] { + CREATE_LIST [17] { elements: { - CONSTANT [24] { value: 2 } - } - } - CALL [25] { - function: _>_ - args: { - IDENT [26] { - name: @c0:0 - } - CONSTANT [27] { value: 1 } - } - } - CALL [28] { - function: _||_ - args: { - IDENT [29] { - name: @x0:0 - } - IDENT [30] { - name: @index7 - } - } - } - COMPREHENSION [31] { - iter_var: @c0:0 - iter_range: { - IDENT [32] { - name: @index6 - } - } - accu_var: @x0:0 - accu_init: { - CONSTANT [33] { value: false } - } - loop_condition: { - CALL [34] { - function: @not_strictly_false - args: { - CALL [35] { - function: !_ + COMPREHENSION [18] { + iter_var: @c0:0 + iter_range: { + CREATE_LIST [19] { + elements: { + CONSTANT [20] { value: 2 } + } + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [21] { value: false } + } + loop_condition: { + CALL [22] { + function: @not_strictly_false args: { - IDENT [36] { + CALL [23] { + function: !_ + args: { + IDENT [24] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + CALL [25] { + function: _||_ + args: { + IDENT [26] { name: @x0:0 } + CALL [27] { + function: _>_ + args: { + IDENT [28] { + name: @c0:0 + } + CONSTANT [29] { value: 1 } + } + } } } } - } - } - loop_step: { - IDENT [37] { - name: @index8 - } - } - result: { - IDENT [38] { - name: @x0:0 + result: { + IDENT [30] { + name: @x0:0 + } + } } } } - CREATE_LIST [39] { - elements: { - IDENT [40] { - name: @index9 + CALL [31] { + function: size + args: { + IDENT [32] { + name: @index0 } } } - CALL [41] { + CALL [33] { function: size args: { - IDENT [42] { - name: @index10 + IDENT [34] { + name: @index1 } } } - CALL [43] { + } + } + CALL [35] { + function: _==_ + args: { + CALL [36] { function: _+_ args: { - CALL [44] { + CALL [37] { function: _+_ args: { - CALL [45] { + CALL [38] { function: _+_ args: { - IDENT [46] { - name: @index5 + IDENT [39] { + name: @index2 } - IDENT [47] { - name: @index5 + IDENT [40] { + name: @index2 } } } - IDENT [48] { - name: @index11 + IDENT [41] { + name: @index3 } } } - IDENT [49] { - name: @index11 + IDENT [42] { + name: @index3 } } } - } - } - CALL [50] { - function: _==_ - args: { - IDENT [51] { - name: @index12 - } - CONSTANT [52] { value: 4 } + CONSTANT [43] { value: 4 } } } } @@ -1491,187 +1346,157 @@ CALL [1] { elements: { CREATE_LIST [3] { elements: { - CONSTANT [4] { value: 1 } - } - } - CALL [5] { - function: _>_ - args: { - IDENT [6] { - name: @c0:0 - } - CONSTANT [7] { value: 0 } - } - } - CALL [8] { - function: _||_ - args: { - IDENT [9] { - name: @x0:0 - } - IDENT [10] { - name: @index1 - } - } - } - COMPREHENSION [11] { - iter_var: @c0:0 - iter_range: { - IDENT [12] { - name: @index0 - } - } - accu_var: @x0:0 - accu_init: { - CONSTANT [13] { value: false } - } - loop_condition: { - CALL [14] { - function: @not_strictly_false - args: { - CALL [15] { - function: !_ + COMPREHENSION [4] { + iter_var: @c0:0 + iter_range: { + CREATE_LIST [5] { + elements: { + CONSTANT [6] { value: 1 } + } + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [7] { value: false } + } + loop_condition: { + CALL [8] { + function: @not_strictly_false args: { - IDENT [16] { + CALL [9] { + function: !_ + args: { + IDENT [10] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + CALL [11] { + function: _||_ + args: { + IDENT [12] { name: @x0:0 } + CALL [13] { + function: _>_ + args: { + IDENT [14] { + name: @c0:0 + } + CONSTANT [15] { value: 0 } + } + } } } } - } - } - loop_step: { - IDENT [17] { - name: @index2 - } - } - result: { - IDENT [18] { - name: @x0:0 - } - } - } - CREATE_LIST [19] { - elements: { - IDENT [20] { - name: @index3 + result: { + IDENT [16] { + name: @x0:0 + } + } } } } - CREATE_LIST [21] { + CREATE_LIST [17] { elements: { - CONSTANT [22] { value: "a" } - } - } - CALL [23] { - function: _==_ - args: { - IDENT [24] { - name: @c0:1 - } - CONSTANT [25] { value: "a" } - } - } - CALL [26] { - function: _||_ - args: { - IDENT [27] { - name: @x0:1 - } - IDENT [28] { - name: @index6 - } - } - } - COMPREHENSION [29] { - iter_var: @c0:1 - iter_range: { - IDENT [30] { - name: @index5 - } - } - accu_var: @x0:1 - accu_init: { - CONSTANT [31] { value: false } - } - loop_condition: { - CALL [32] { - function: @not_strictly_false - args: { - CALL [33] { - function: !_ + COMPREHENSION [18] { + iter_var: @c0:1 + iter_range: { + CREATE_LIST [19] { + elements: { + CONSTANT [20] { value: "a" } + } + } + } + accu_var: @x0:1 + accu_init: { + CONSTANT [21] { value: false } + } + loop_condition: { + CALL [22] { + function: @not_strictly_false + args: { + CALL [23] { + function: !_ + args: { + IDENT [24] { + name: @x0:1 + } + } + } + } + } + } + loop_step: { + CALL [25] { + function: _||_ args: { - IDENT [34] { + IDENT [26] { name: @x0:1 } + CALL [27] { + function: _==_ + args: { + IDENT [28] { + name: @c0:1 + } + CONSTANT [29] { value: "a" } + } + } } } } + result: { + IDENT [30] { + name: @x0:1 + } + } } } - loop_step: { - IDENT [35] { - name: @index7 - } - } - result: { - IDENT [36] { - name: @x0:1 - } - } - } - CREATE_LIST [37] { - elements: { - IDENT [38] { - name: @index8 - } - } - } - CREATE_LIST [39] { - elements: { - CONSTANT [40] { value: true } - CONSTANT [41] { value: true } - CONSTANT [42] { value: true } - CONSTANT [43] { value: true } - } } - CALL [44] { + } + } + CALL [31] { + function: _==_ + args: { + CALL [32] { function: _+_ args: { - CALL [45] { + CALL [33] { function: _+_ args: { - CALL [46] { + CALL [34] { function: _+_ args: { - IDENT [47] { - name: @index4 + IDENT [35] { + name: @index0 } - IDENT [48] { - name: @index4 + IDENT [36] { + name: @index0 } } } - IDENT [49] { - name: @index9 + IDENT [37] { + name: @index1 } } } - IDENT [50] { - name: @index9 + IDENT [38] { + name: @index1 } } } - } - } - CALL [51] { - function: _==_ - args: { - IDENT [52] { - name: @index11 - } - IDENT [53] { - name: @index10 + CREATE_LIST [39] { + elements: { + CONSTANT [40] { value: true } + CONSTANT [41] { value: true } + CONSTANT [42] { value: true } + CONSTANT [43] { value: true } + } } } } @@ -1699,52 +1524,39 @@ CALL [1] { CONSTANT [10] { value: 4 } } } - CREATE_LIST [11] { - elements: { - IDENT [12] { - name: @index1 - } - IDENT [13] { - name: @index1 - } - IDENT [14] { - name: @index1 - } - } - } - COMPREHENSION [15] { + COMPREHENSION [11] { iter_var: @c1:0 iter_range: { - IDENT [16] { + IDENT [12] { name: @index0 } } accu_var: @x1:0 accu_init: { - CREATE_LIST [17] { + CREATE_LIST [13] { elements: { } } } loop_condition: { - CONSTANT [18] { value: true } + CONSTANT [14] { value: true } } loop_step: { - CALL [19] { + CALL [15] { function: _+_ args: { - IDENT [20] { + IDENT [16] { name: @x1:0 } - CREATE_LIST [21] { + CREATE_LIST [17] { elements: { - CALL [22] { + CALL [18] { function: _+_ args: { - IDENT [23] { + IDENT [19] { name: @c1:0 } - CONSTANT [24] { value: 1 } + CONSTANT [20] { value: 1 } } } } @@ -1753,39 +1565,44 @@ CALL [1] { } } result: { - IDENT [25] { + IDENT [21] { name: @x1:0 } } } - COMPREHENSION [26] { + } + } + CALL [22] { + function: _==_ + args: { + COMPREHENSION [23] { iter_var: @c0:0 iter_range: { - IDENT [27] { + IDENT [24] { name: @index0 } } accu_var: @x0:0 accu_init: { - CREATE_LIST [28] { + CREATE_LIST [25] { elements: { } } } loop_condition: { - CONSTANT [29] { value: true } + CONSTANT [26] { value: true } } loop_step: { - CALL [30] { + CALL [27] { function: _+_ args: { - IDENT [31] { + IDENT [28] { name: @x0:0 } - CREATE_LIST [32] { + CREATE_LIST [29] { elements: { - IDENT [33] { - name: @index3 + IDENT [30] { + name: @index2 } } } @@ -1793,21 +1610,23 @@ CALL [1] { } } result: { - IDENT [34] { + IDENT [31] { name: @x0:0 } } } - } - } - CALL [35] { - function: _==_ - args: { - IDENT [36] { - name: @index4 - } - IDENT [37] { - name: @index2 + CREATE_LIST [32] { + elements: { + IDENT [33] { + name: @index1 + } + IDENT [34] { + name: @index1 + } + IDENT [35] { + name: @index1 + } + } } } } @@ -1821,114 +1640,105 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_LIST [3] { - elements: { - CREATE_LIST [4] { - elements: { - CONSTANT [5] { value: 1 } - } - } - CREATE_LIST [6] { - elements: { - CONSTANT [7] { value: 2 } - } - } - } - } - COMPREHENSION [8] { + COMPREHENSION [3] { iter_var: @c1:0 iter_range: { - CREATE_LIST [9] { + CREATE_LIST [4] { elements: { - CONSTANT [10] { value: 1 } - CONSTANT [11] { value: 2 } - CONSTANT [12] { value: 3 } + CONSTANT [5] { value: 1 } + CONSTANT [6] { value: 2 } + CONSTANT [7] { value: 3 } } } } accu_var: @x1:0 accu_init: { - CREATE_LIST [13] { + CREATE_LIST [8] { elements: { } } } loop_condition: { - CONSTANT [14] { value: true } + CONSTANT [9] { value: true } } loop_step: { - CALL [15] { + CALL [10] { function: _?_:_ args: { - CALL [16] { + CALL [11] { function: _==_ args: { - IDENT [17] { + IDENT [12] { name: @c1:0 } - IDENT [18] { + IDENT [13] { name: @c0:0 } } } - CALL [19] { + CALL [14] { function: _+_ args: { - IDENT [20] { + IDENT [15] { name: @x1:0 } - CREATE_LIST [21] { + CREATE_LIST [16] { elements: { - IDENT [22] { + IDENT [17] { name: @c1:0 } } } } } - IDENT [23] { + IDENT [18] { name: @x1:0 } } } } result: { - IDENT [24] { + IDENT [19] { name: @x1:0 } } } - COMPREHENSION [25] { + } + } + CALL [20] { + function: _==_ + args: { + COMPREHENSION [21] { iter_var: @c0:0 iter_range: { - CREATE_LIST [26] { + CREATE_LIST [22] { elements: { - CONSTANT [27] { value: 1 } - CONSTANT [28] { value: 2 } + CONSTANT [23] { value: 1 } + CONSTANT [24] { value: 2 } } } } accu_var: @x0:0 accu_init: { - CREATE_LIST [29] { + CREATE_LIST [25] { elements: { } } } loop_condition: { - CONSTANT [30] { value: true } + CONSTANT [26] { value: true } } loop_step: { - CALL [31] { + CALL [27] { function: _+_ args: { - IDENT [32] { + IDENT [28] { name: @x0:0 } - CREATE_LIST [33] { + CREATE_LIST [29] { elements: { - IDENT [34] { - name: @index1 + IDENT [30] { + name: @index0 } } } @@ -1936,21 +1746,24 @@ CALL [1] { } } result: { - IDENT [35] { + IDENT [31] { name: @x0:0 } } } - } - } - CALL [36] { - function: _==_ - args: { - IDENT [37] { - name: @index2 - } - IDENT [38] { - name: @index0 + CREATE_LIST [32] { + elements: { + CREATE_LIST [33] { + elements: { + CONSTANT [34] { value: 1 } + } + } + CREATE_LIST [35] { + elements: { + CONSTANT [36] { value: 2 } + } + } + } } } } @@ -1964,74 +1777,72 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_LIST [3] { - elements: { - CONSTANT [4] { value: 1 } - CONSTANT [5] { value: 2 } - CONSTANT [6] { value: 3 } - } - } - CALL [7] { + CALL [3] { function: @in args: { - CONSTANT [8] { value: 1 } - IDENT [9] { - name: @index0 + CONSTANT [4] { value: 1 } + CREATE_LIST [5] { + elements: { + CONSTANT [6] { value: 1 } + CONSTANT [7] { value: 2 } + CONSTANT [8] { value: 3 } + } } } } - CALL [10] { + CREATE_LIST [9] { + elements: { + CONSTANT [10] { value: 1 } + CONSTANT [11] { value: 2 } + CONSTANT [12] { value: 3 } + } + } + } + } + CALL [13] { + function: _&&_ + args: { + CALL [14] { function: _&&_ args: { - CALL [11] { + IDENT [15] { + name: @index0 + } + CALL [16] { function: @in args: { - CONSTANT [12] { value: 3 } - CREATE_LIST [13] { - elements: { - CONSTANT [14] { value: 3 } - IDENT [15] { - name: @index0 - } - } + CONSTANT [17] { value: 2 } + IDENT [18] { + name: @index1 } } } - IDENT [16] { - name: @index1 - } } } - CALL [17] { + CALL [19] { function: _&&_ args: { - IDENT [18] { - name: @index1 - } - CALL [19] { + CALL [20] { function: @in args: { - CONSTANT [20] { value: 2 } - IDENT [21] { - name: @index0 + CONSTANT [21] { value: 3 } + CREATE_LIST [22] { + elements: { + CONSTANT [23] { value: 3 } + IDENT [24] { + name: @index1 + } + } } } } + IDENT [25] { + name: @index0 + } } } } } - CALL [22] { - function: _&&_ - args: { - IDENT [23] { - name: @index3 - } - IDENT [24] { - name: @index2 - } - } - } } } Test case: INCLUSION_MAP @@ -2052,31 +1863,37 @@ CALL [1] { } } } - CREATE_MAP [7] { - MAP_ENTRY [8] { + } + } + CALL [7] { + function: @in + args: { + CONSTANT [8] { value: 2 } + CREATE_MAP [9] { + MAP_ENTRY [10] { key: { - CONSTANT [9] { value: "a" } + CONSTANT [11] { value: "a" } } value: { - CONSTANT [10] { value: 1 } + CONSTANT [12] { value: 1 } } } - MAP_ENTRY [11] { + MAP_ENTRY [13] { key: { - CONSTANT [12] { value: 2 } + CONSTANT [14] { value: 2 } } value: { - IDENT [13] { + IDENT [15] { name: @index0 } } } - MAP_ENTRY [14] { + MAP_ENTRY [16] { key: { - CONSTANT [15] { value: 3 } + CONSTANT [17] { value: 3 } } value: { - IDENT [16] { + IDENT [18] { name: @index0 } } @@ -2084,15 +1901,6 @@ CALL [1] { } } } - CALL [17] { - function: @in - args: { - CONSTANT [18] { value: 2 } - IDENT [19] { - name: @index1 - } - } - } } } Test case: MACRO_ITER_VAR_NOT_REFERENCED @@ -2105,85 +1913,79 @@ CALL [1] { elements: { CREATE_LIST [3] { elements: { - CONSTANT [4] { value: 1 } - CONSTANT [5] { value: 2 } + CREATE_LIST [4] { + elements: { + CONSTANT [5] { value: 3 } + CONSTANT [6] { value: 4 } + } + } + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 3 } + CONSTANT [9] { value: 4 } + } + } } } - CREATE_LIST [6] { + CREATE_LIST [10] { elements: { - CONSTANT [7] { value: 3 } - CONSTANT [8] { value: 4 } + CONSTANT [11] { value: 1 } + CONSTANT [12] { value: 2 } } } - CREATE_LIST [9] { - elements: { - IDENT [10] { - name: @index1 - } - IDENT [11] { + COMPREHENSION [13] { + iter_var: @c1:0 + iter_range: { + IDENT [14] { name: @index1 } } - } - CREATE_LIST [12] { - elements: { - IDENT [13] { - name: @index2 - } - IDENT [14] { - name: @index2 + accu_var: @x1:0 + accu_init: { + CREATE_LIST [15] { + elements: { + } } } - } - CREATE_LIST [15] { - elements: { - COMPREHENSION [16] { - iter_var: @c1:0 - iter_range: { - IDENT [17] { - name: @index0 + loop_condition: { + CONSTANT [16] { value: true } + } + loop_step: { + CALL [17] { + function: _+_ + args: { + IDENT [18] { + name: @x1:0 } - } - accu_var: @x1:0 - accu_init: { - CREATE_LIST [18] { + CREATE_LIST [19] { elements: { - } - } - } - loop_condition: { - CONSTANT [19] { value: true } - } - loop_step: { - CALL [20] { - function: _+_ - args: { - IDENT [21] { - name: @x1:0 - } - CREATE_LIST [22] { + CREATE_LIST [20] { elements: { - IDENT [23] { - name: @index1 - } + CONSTANT [21] { value: 3 } + CONSTANT [22] { value: 4 } } } } } } - result: { - IDENT [24] { - name: @x1:0 - } - } + } + } + result: { + IDENT [23] { + name: @x1:0 } } } + } + } + CALL [24] { + function: _==_ + args: { COMPREHENSION [25] { iter_var: @c0:0 iter_range: { IDENT [26] { - name: @index0 + name: @index1 } } accu_var: @x0:0 @@ -2203,28 +2005,31 @@ CALL [1] { IDENT [30] { name: @x0:0 } - IDENT [31] { - name: @index4 + CREATE_LIST [31] { + elements: { + IDENT [32] { + name: @index2 + } + } } } } } result: { - IDENT [32] { + IDENT [33] { name: @x0:0 } } } - } - } - CALL [33] { - function: _==_ - args: { - IDENT [34] { - name: @index5 - } - IDENT [35] { - name: @index3 + CREATE_LIST [34] { + elements: { + IDENT [35] { + name: @index0 + } + IDENT [36] { + name: @index0 + } + } } } } @@ -2239,38 +2044,41 @@ CALL [1] { CREATE_LIST [2] { elements: { CALL [3] { - function: _-_ - args: { - IDENT [4] { - name: x - } - CONSTANT [5] { value: 1 } - } - } - CALL [6] { function: _>_ args: { - IDENT [7] { - name: @index0 + CALL [4] { + function: _-_ + args: { + IDENT [5] { + name: x + } + CONSTANT [6] { value: 1 } + } } - CONSTANT [8] { value: 3 } + CONSTANT [7] { value: 3 } } } - COMPREHENSION [9] { + COMPREHENSION [8] { iter_var: @c0:0 iter_range: { - CREATE_LIST [10] { + CREATE_LIST [9] { elements: { - CALL [11] { + CALL [10] { function: _?_:_ args: { - IDENT [12] { - name: @index1 - } - IDENT [13] { + IDENT [11] { name: @index0 } - CONSTANT [14] { value: 5 } + CALL [12] { + function: _-_ + args: { + IDENT [13] { + name: x + } + CONSTANT [14] { value: 1 } + } + } + CONSTANT [15] { value: 5 } } } } @@ -2278,16 +2086,16 @@ CALL [1] { } accu_var: @x0:0 accu_init: { - CONSTANT [15] { value: false } + CONSTANT [16] { value: false } } loop_condition: { - CALL [16] { + CALL [17] { function: @not_strictly_false args: { - CALL [17] { + CALL [18] { function: !_ args: { - IDENT [18] { + IDENT [19] { name: @x0:0 } } @@ -2296,47 +2104,47 @@ CALL [1] { } } loop_step: { - CALL [19] { + CALL [20] { function: _||_ args: { - IDENT [20] { + IDENT [21] { name: @x0:0 } - CALL [21] { + CALL [22] { function: _>_ args: { - CALL [22] { + CALL [23] { function: _-_ args: { - IDENT [23] { + IDENT [24] { name: @c0:0 } - CONSTANT [24] { value: 1 } + CONSTANT [25] { value: 1 } } } - CONSTANT [25] { value: 3 } + CONSTANT [26] { value: 3 } } } } } } result: { - IDENT [26] { + IDENT [27] { name: @x0:0 } } } } } - CALL [27] { + CALL [28] { function: _||_ args: { - IDENT [28] { - name: @index2 - } IDENT [29] { name: @index1 } + IDENT [30] { + name: @index0 + } } } } @@ -2371,63 +2179,41 @@ CALL [1] { } } } - CALL [9] { - function: _+_ - args: { - IDENT [10] { - name: @x0:0 - } - CREATE_LIST [11] { - elements: { - CREATE_LIST [12] { - elements: { - IDENT [13] { - name: @index1 - } - IDENT [14] { - name: @index1 - } - } - } - } - } - } - } - COMPREHENSION [15] { + COMPREHENSION [9] { iter_var: @c1:0 iter_range: { - CREATE_LIST [16] { + CREATE_LIST [10] { elements: { - CONSTANT [17] { value: "foo" } - CONSTANT [18] { value: "bar" } + CONSTANT [11] { value: "foo" } + CONSTANT [12] { value: "bar" } } } } accu_var: @x1:0 accu_init: { - CREATE_LIST [19] { + CREATE_LIST [13] { elements: { } } } loop_condition: { - CONSTANT [20] { value: true } + CONSTANT [14] { value: true } } loop_step: { - CALL [21] { + CALL [15] { function: _+_ args: { - IDENT [22] { + IDENT [16] { name: @x1:0 } - CREATE_LIST [23] { + CREATE_LIST [17] { elements: { - CREATE_LIST [24] { + CREATE_LIST [18] { elements: { - IDENT [25] { + IDENT [19] { name: @index0 } - IDENT [26] { + IDENT [20] { name: @index0 } } @@ -2438,37 +2224,56 @@ CALL [1] { } } result: { - IDENT [27] { + IDENT [21] { name: @x1:0 } } } } } - COMPREHENSION [28] { + COMPREHENSION [22] { iter_var: @c0:0 iter_range: { - IDENT [29] { - name: @index3 + IDENT [23] { + name: @index2 } } accu_var: @x0:0 accu_init: { - CREATE_LIST [30] { + CREATE_LIST [24] { elements: { } } } loop_condition: { - CONSTANT [31] { value: true } + CONSTANT [25] { value: true } } loop_step: { - IDENT [32] { - name: @index2 + CALL [26] { + function: _+_ + args: { + IDENT [27] { + name: @x0:0 + } + CREATE_LIST [28] { + elements: { + CREATE_LIST [29] { + elements: { + IDENT [30] { + name: @index1 + } + IDENT [31] { + name: @index1 + } + } + } + } + } + } } } result: { - IDENT [33] { + IDENT [32] { name: @x0:0 } } @@ -2493,27 +2298,24 @@ CALL [1] { } } } - CALL [7] { - function: _[_] - args: { - IDENT [8] { - name: @index0 - } - CONSTANT [9] { value: "a" } - } - } } } - CALL [10] { + CALL [7] { function: _&&_ args: { - SELECT [11] { - IDENT [12] { + SELECT [8] { + IDENT [9] { name: @index0 }.a~presence_test } - IDENT [13] { - name: @index1 + CALL [10] { + function: _[_] + args: { + IDENT [11] { + name: @index0 + } + CONSTANT [12] { value: "a" } + } } } } @@ -2532,33 +2334,30 @@ CALL [1] { name: msg }.oneof_type } - CALL [5] { + } + } + CALL [5] { + function: _==_ + args: { + CALL [6] { function: _?_:_ args: { - SELECT [6] { - IDENT [7] { + SELECT [7] { + IDENT [8] { name: @index0 }.payload~presence_test } - SELECT [8] { - SELECT [9] { - IDENT [10] { + SELECT [9] { + SELECT [10] { + IDENT [11] { name: @index0 }.payload }.single_int64 } - CONSTANT [11] { value: 0 } + CONSTANT [12] { value: 0 } } } - } - } - CALL [12] { - function: _==_ - args: { - IDENT [13] { - name: @index1 - } - CONSTANT [14] { value: 10 } + CONSTANT [13] { value: 10 } } } } @@ -2572,51 +2371,44 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload - } - SELECT [7] { - IDENT [8] { - name: @index1 + SELECT [4] { + SELECT [5] { + IDENT [6] { + name: msg + }.oneof_type + }.payload }.single_int64 } - CALL [9] { + } + } + CALL [7] { + function: _==_ + args: { + CALL [8] { function: _?_:_ args: { - SELECT [10] { - IDENT [11] { - name: @index0 + SELECT [9] { + SELECT [10] { + IDENT [11] { + name: msg + }.oneof_type }.payload~presence_test } IDENT [12] { - name: @index2 + name: @index0 } CALL [13] { function: _*_ args: { IDENT [14] { - name: @index2 + name: @index0 } CONSTANT [15] { value: 0 } } } } } - } - } - CALL [16] { - function: _==_ - args: { - IDENT [17] { - name: @index3 - } - CONSTANT [18] { value: 10 } + CONSTANT [16] { value: 10 } } } } @@ -2630,36 +2422,34 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload - } - SELECT [7] { - IDENT [8] { - name: @index1 + SELECT [4] { + SELECT [5] { + IDENT [6] { + name: msg + }.oneof_type + }.payload }.single_int64 } - CALL [9] { + CALL [7] { function: _?_:_ args: { - SELECT [10] { - IDENT [11] { - name: @index1 + SELECT [8] { + SELECT [9] { + SELECT [10] { + IDENT [11] { + name: msg + }.oneof_type + }.payload }.single_int64~presence_test } IDENT [12] { - name: @index2 + name: @index0 } CALL [13] { function: _*_ args: { IDENT [14] { - name: @index2 + name: @index0 } CONSTANT [15] { value: 0 } } @@ -2672,7 +2462,7 @@ CALL [1] { function: _==_ args: { IDENT [17] { - name: @index3 + name: @index1 } CONSTANT [18] { value: 10 } } @@ -2688,72 +2478,43 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload - } - SELECT [7] { - IDENT [8] { - name: @index1 + SELECT [4] { + SELECT [5] { + IDENT [6] { + name: msg + }.oneof_type + }.payload }.map_string_string } - CALL [9] { - function: _?_:_ - args: { - CALL [10] { - function: _&&_ - args: { - SELECT [11] { - IDENT [12] { - name: @index1 - }.map_string_string~presence_test - } - SELECT [13] { - IDENT [14] { - name: @index2 - }.key~presence_test - } - } - } - CALL [15] { - function: _==_ - args: { - SELECT [16] { - IDENT [17] { - name: @index2 - }.key - } - CONSTANT [18] { value: "A" } - } - } - CONSTANT [19] { value: false } - } + SELECT [7] { + SELECT [8] { + IDENT [9] { + name: msg + }.oneof_type + }.payload } - CALL [20] { + CALL [10] { function: _&&_ args: { - CALL [21] { + CALL [11] { function: _&&_ args: { - SELECT [22] { - IDENT [23] { + SELECT [12] { + IDENT [13] { name: msg }.oneof_type~presence_test } - SELECT [24] { - IDENT [25] { - name: @index0 + SELECT [14] { + SELECT [15] { + IDENT [16] { + name: msg + }.oneof_type }.payload~presence_test } } } - SELECT [26] { - IDENT [27] { + SELECT [17] { + IDENT [18] { name: @index1 }.single_int64~presence_test } @@ -2761,16 +2522,45 @@ CALL [1] { } } } - CALL [28] { + CALL [19] { function: _?_:_ args: { - IDENT [29] { - name: @index4 + IDENT [20] { + name: @index2 } - IDENT [30] { - name: @index3 + CALL [21] { + function: _?_:_ + args: { + CALL [22] { + function: _&&_ + args: { + SELECT [23] { + IDENT [24] { + name: @index1 + }.map_string_string~presence_test + } + SELECT [25] { + IDENT [26] { + name: @index0 + }.key~presence_test + } + } + } + CALL [27] { + function: _==_ + args: { + SELECT [28] { + IDENT [29] { + name: @index0 + }.key + } + CONSTANT [30] { value: "A" } + } + } + CONSTANT [31] { value: false } + } } - CONSTANT [31] { value: false } + CONSTANT [32] { value: false } } } } @@ -2783,44 +2573,49 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CALL [3] { - function: optional.none - args: { - } - } - CREATE_LIST [4] { + CREATE_LIST [3] { elements: { - IDENT [5] { - name: @index0 + CALL [4] { + function: optional.none + args: { + } } - IDENT [6] { + IDENT [5] { name: opt_x } } optional_indices: [0, 1] } - CREATE_LIST [7] { + CREATE_LIST [6] { elements: { - CONSTANT [8] { value: 5 } + CONSTANT [7] { value: 5 } } } + } + } + CALL [8] { + function: _==_ + args: { CREATE_LIST [9] { elements: { CONSTANT [10] { value: 10 } - IDENT [11] { - name: @index2 + CALL [11] { + function: optional.none + args: { + } } IDENT [12] { - name: @index2 + name: @index0 + } + IDENT [13] { + name: @index0 } } + optional_indices: [0] } - CREATE_LIST [13] { + CREATE_LIST [14] { elements: { - CONSTANT [14] { value: 10 } - IDENT [15] { - name: @index0 - } + CONSTANT [15] { value: 10 } IDENT [16] { name: @index1 } @@ -2828,18 +2623,6 @@ CALL [1] { name: @index1 } } - optional_indices: [0] - } - } - } - CALL [18] { - function: _==_ - args: { - IDENT [19] { - name: @index4 - } - IDENT [20] { - name: @index3 } } } @@ -2854,53 +2637,44 @@ CALL [1] { CREATE_LIST [2] { elements: { CALL [3] { - function: optional.of - args: { - CONSTANT [4] { value: "hello" } - } - } - CREATE_MAP [5] { - MAP_ENTRY [6] { - key: { - CONSTANT [7] { value: "hello" } - } - optional_entry: true - value: { - IDENT [8] { - name: @index0 - } - } - } - } - CALL [9] { function: _[_] args: { - IDENT [10] { - name: @index1 + CREATE_MAP [4] { + MAP_ENTRY [5] { + key: { + CONSTANT [6] { value: "hello" } + } + optional_entry: true + value: { + CALL [7] { + function: optional.of + args: { + CONSTANT [8] { value: "hello" } + } + } + } + } } - CONSTANT [11] { value: "hello" } + CONSTANT [9] { value: "hello" } } } - CALL [12] { + } + } + CALL [10] { + function: _==_ + args: { + CALL [11] { function: _+_ args: { - IDENT [13] { - name: @index2 + IDENT [12] { + name: @index0 } - IDENT [14] { - name: @index2 + IDENT [13] { + name: @index0 } } } - } - } - CALL [15] { - function: _==_ - args: { - IDENT [16] { - name: @index3 - } - CONSTANT [17] { value: "hellohello" } + CONSTANT [14] { value: "hellohello" } } } } @@ -2924,145 +2698,130 @@ CALL [1] { } } CALL [7] { - function: _[_] - args: { - IDENT [8] { - name: @index0 - } - CONSTANT [9] { value: "key" } - } - } - CALL [10] { function: or target: { - CALL [11] { + CALL [8] { function: _[?_] args: { - CREATE_MAP [12] { - MAP_ENTRY [13] { + CREATE_MAP [9] { + MAP_ENTRY [10] { key: { - CONSTANT [14] { value: "key" } + CONSTANT [11] { value: "key" } } optional_entry: true value: { - CALL [15] { + CALL [12] { function: optional.of args: { - CONSTANT [16] { value: "test" } + CONSTANT [13] { value: "test" } } } } } } - CONSTANT [17] { value: "bogus" } + CONSTANT [14] { value: "bogus" } } } } args: { - CALL [18] { + CALL [15] { function: _[?_] args: { - IDENT [19] { + IDENT [16] { name: @index0 } - CONSTANT [20] { value: "bogus" } + CONSTANT [17] { value: "bogus" } } } } } - CALL [21] { + } + } + CALL [18] { + function: _==_ + args: { + CALL [19] { function: orValue target: { - IDENT [22] { - name: @index2 + IDENT [20] { + name: @index1 } } args: { - IDENT [23] { - name: @index1 + CALL [21] { + function: _[_] + args: { + IDENT [22] { + name: @index0 + } + CONSTANT [23] { value: "key" } + } } } } - } - } - CALL [24] { - function: _==_ - args: { - IDENT [25] { - name: @index3 - } - CONSTANT [26] { value: "test" } + CONSTANT [24] { value: "test" } } } } } -Test case: OPTIONAL_MESSAGE -Source: TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}.single_int32 + TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}.single_int64 == 5 -=====> -CALL [1] { - function: cel.@block - args: { - CREATE_LIST [2] { - elements: { - CALL [3] { - function: optional.ofNonZeroValue - args: { - CONSTANT [4] { value: 1 } - } - } - CALL [5] { - function: optional.of - args: { - CONSTANT [6] { value: 4 } - } - } - CREATE_STRUCT [7] { +Test case: OPTIONAL_MESSAGE +Source: TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}.single_int32 + TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}.single_int64 == 5 +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_STRUCT [3] { name: TestAllTypes entries: { - ENTRY [8] { + ENTRY [4] { field_key: single_int64 optional_entry: true value: { - IDENT [9] { - name: @index0 + CALL [5] { + function: optional.ofNonZeroValue + args: { + CONSTANT [6] { value: 1 } + } } } } - ENTRY [10] { + ENTRY [7] { field_key: single_int32 optional_entry: true value: { - IDENT [11] { - name: @index1 + CALL [8] { + function: optional.of + args: { + CONSTANT [9] { value: 4 } + } } } } } } - CALL [12] { + } + } + CALL [10] { + function: _==_ + args: { + CALL [11] { function: _+_ args: { - SELECT [13] { - IDENT [14] { - name: @index2 + SELECT [12] { + IDENT [13] { + name: @index0 }.single_int32 } - SELECT [15] { - IDENT [16] { - name: @index2 + SELECT [14] { + IDENT [15] { + name: @index0 }.single_int64 } } } - } - } - CALL [17] { - function: _==_ - args: { - IDENT [18] { - name: @index3 - } - CONSTANT [19] { value: 5 } + CONSTANT [16] { value: 5 } } } } @@ -3078,58 +2837,46 @@ CALL [1] { CALL [3] { function: _+_ args: { - CONSTANT [4] { value: "h" } - CONSTANT [5] { value: "e" } - } - } - CALL [6] { - function: _+_ - args: { - IDENT [7] { - name: @index0 - } - CONSTANT [8] { value: "l" } - } - } - CALL [9] { - function: _+_ - args: { - IDENT [10] { - name: @index1 - } - CONSTANT [11] { value: "l" } - } - } - CALL [12] { - function: _+_ - args: { - IDENT [13] { - name: @index2 - } - CONSTANT [14] { value: "o" } - } - } - CALL [15] { - function: _+_ - args: { - IDENT [16] { - name: @index3 + CALL [4] { + function: _+_ + args: { + CALL [5] { + function: _+_ + args: { + CALL [6] { + function: _+_ + args: { + CONSTANT [7] { value: "h" } + CONSTANT [8] { value: "e" } + } + } + CONSTANT [9] { value: "l" } + } + } + CONSTANT [10] { value: "l" } + } } - CONSTANT [17] { value: " world" } + CONSTANT [11] { value: "o" } } } } } - CALL [18] { + CALL [12] { function: matches target: { - IDENT [19] { - name: @index4 + CALL [13] { + function: _+_ + args: { + IDENT [14] { + name: @index0 + } + CONSTANT [15] { value: " world" } + } } } args: { - IDENT [20] { - name: @index3 + IDENT [16] { + name: @index0 } } } @@ -3216,26 +2963,23 @@ CALL [1] { CONSTANT [11] { value: "o" } } } - CALL [12] { + } + } + CALL [12] { + function: matches + target: { + CALL [13] { function: _+_ args: { - IDENT [13] { + IDENT [14] { name: @index0 } - CONSTANT [14] { value: " world" } + CONSTANT [15] { value: " world" } } } } - } - CALL [15] { - function: matches - target: { - IDENT [16] { - name: @index1 - } - } args: { - CONSTANT [17] { value: "hello" } + CONSTANT [16] { value: "hello" } } } } @@ -3260,17 +3004,17 @@ CALL [1] { CALL [6] { function: _+_ args: { - CONSTANT [7] { value: "w" } - CONSTANT [8] { value: "o" } + CONSTANT [7] { value: "h" } + CONSTANT [8] { value: "e" } } } - CONSTANT [9] { value: "r" } + CONSTANT [9] { value: "l" } } } CONSTANT [10] { value: "l" } } } - CONSTANT [11] { value: "d" } + CONSTANT [11] { value: "o" } } } CALL [12] { @@ -3285,40 +3029,37 @@ CALL [1] { CALL [15] { function: _+_ args: { - CONSTANT [16] { value: "h" } - CONSTANT [17] { value: "e" } + CONSTANT [16] { value: "w" } + CONSTANT [17] { value: "o" } } } - CONSTANT [18] { value: "l" } + CONSTANT [18] { value: "r" } } } CONSTANT [19] { value: "l" } } } - CONSTANT [20] { value: "o" } - } - } - CALL [21] { - function: _+_ - args: { - IDENT [22] { - name: @index1 - } - CONSTANT [23] { value: " world" } + CONSTANT [20] { value: "d" } } } } } - CALL [24] { + CALL [21] { function: matches target: { - IDENT [25] { - name: @index2 + CALL [22] { + function: _+_ + args: { + IDENT [23] { + name: @index0 + } + CONSTANT [24] { value: " world" } + } } } args: { - IDENT [26] { - name: @index0 + IDENT [25] { + name: @index1 } } } @@ -3333,74 +3074,66 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload - } - SELECT [7] { - IDENT [8] { - name: @index1 - }.single_int64 - } - SELECT [9] { - IDENT [10] { - name: msg + SELECT [4] { + SELECT [5] { + IDENT [6] { + name: msg + }.oneof_type + }.payload }.single_int64 } - SELECT [11] { - IDENT [12] { - name: @index1 - }.single_int32 - } } } - CALL [13] { + CALL [7] { function: _+_ args: { - CALL [14] { + CALL [8] { function: _+_ args: { - CALL [15] { + CALL [9] { function: _+_ args: { - CALL [16] { + CALL [10] { function: non_pure_custom_func args: { - IDENT [17] { - name: @index2 + IDENT [11] { + name: @index0 } } } - CALL [18] { + CALL [12] { function: non_pure_custom_func args: { - IDENT [19] { - name: @index4 + SELECT [13] { + SELECT [14] { + SELECT [15] { + IDENT [16] { + name: msg + }.oneof_type + }.payload + }.single_int32 } } } } } - CALL [20] { + CALL [17] { function: non_pure_custom_func args: { - IDENT [21] { - name: @index2 + IDENT [18] { + name: @index0 } } } } } - CALL [22] { + CALL [19] { function: non_pure_custom_func args: { - IDENT [23] { - name: @index3 + SELECT [20] { + IDENT [21] { + name: msg + }.single_int64 } } } @@ -3416,39 +3149,39 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload - } - SELECT [7] { - IDENT [8] { - name: @index1 - }.single_int64 - } - CALL [9] { + CALL [3] { function: pure_custom_func args: { - IDENT [10] { - name: @index2 + SELECT [4] { + SELECT [5] { + SELECT [6] { + IDENT [7] { + name: msg + }.oneof_type + }.payload + }.single_int64 } } } - CALL [11] { + CALL [8] { function: pure_custom_func args: { - SELECT [12] { - IDENT [13] { - name: msg - }.single_int64 + SELECT [9] { + SELECT [10] { + SELECT [11] { + IDENT [12] { + name: msg + }.oneof_type + }.payload + }.single_int32 } } } + } + } + CALL [13] { + function: _+_ + args: { CALL [14] { function: _+_ args: { @@ -3456,35 +3189,27 @@ CALL [1] { function: _+_ args: { IDENT [16] { - name: @index3 + name: @index0 } - CALL [17] { - function: pure_custom_func - args: { - SELECT [18] { - IDENT [19] { - name: @index1 - }.single_int32 - } - } + IDENT [17] { + name: @index1 } } } - IDENT [20] { - name: @index3 + IDENT [18] { + name: @index0 } } } - } - } - CALL [21] { - function: _+_ - args: { - IDENT [22] { - name: @index5 - } - IDENT [23] { - name: @index4 + CALL [19] { + function: pure_custom_func + args: { + SELECT [20] { + IDENT [21] { + name: msg + }.single_int64 + } + } } } } diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_5.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_5.baseline index d5d799e1f..470c6a612 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_5.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_5.baseline @@ -6,20 +6,22 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_LIST [3] { - elements: { - CONSTANT [4] { value: 1 } - CONSTANT [5] { value: 2 } - } - } - CALL [6] { + CALL [3] { function: size args: { - IDENT [7] { - name: @index0 + CREATE_LIST [4] { + elements: { + CONSTANT [5] { value: 1 } + CONSTANT [6] { value: 2 } + } } } } + } + } + CALL [7] { + function: _==_ + args: { CALL [8] { function: _+_ args: { @@ -27,25 +29,17 @@ CALL [1] { function: _+_ args: { IDENT [10] { - name: @index1 + name: @index0 } IDENT [11] { - name: @index1 + name: @index0 } } } CONSTANT [12] { value: 1 } } } - } - } - CALL [13] { - function: _==_ - args: { - IDENT [14] { - name: @index2 - } - CONSTANT [15] { value: 5 } + CONSTANT [13] { value: 5 } } } } @@ -58,20 +52,22 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_LIST [3] { - elements: { - CONSTANT [4] { value: 1 } - CONSTANT [5] { value: 2 } - } - } - CALL [6] { + CALL [3] { function: size args: { - IDENT [7] { - name: @index0 + CREATE_LIST [4] { + elements: { + CONSTANT [5] { value: 1 } + CONSTANT [6] { value: 2 } + } } } } + } + } + CALL [7] { + function: _==_ + args: { CALL [8] { function: _+_ args: { @@ -83,27 +79,19 @@ CALL [1] { args: { CONSTANT [11] { value: 2 } IDENT [12] { - name: @index1 + name: @index0 } } } IDENT [13] { - name: @index1 + name: @index0 } } } CONSTANT [14] { value: 1 } } } - } - } - CALL [15] { - function: _==_ - args: { - IDENT [16] { - name: @index2 - } - CONSTANT [17] { value: 7 } + CONSTANT [15] { value: 7 } } } } @@ -116,69 +104,60 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_LIST [3] { - elements: { - CONSTANT [4] { value: 0 } - } - } - CALL [5] { + CALL [3] { function: size args: { - IDENT [6] { - name: @index0 + CREATE_LIST [4] { + elements: { + CONSTANT [5] { value: 0 } + } } } } - CREATE_LIST [7] { - elements: { - CONSTANT [8] { value: 1 } - CONSTANT [9] { value: 2 } - } - } - CALL [10] { + CALL [6] { function: size args: { - IDENT [11] { - name: @index2 + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 1 } + CONSTANT [9] { value: 2 } + } } } } - CALL [12] { + } + } + CALL [10] { + function: _==_ + args: { + CALL [11] { function: _+_ args: { - CALL [13] { + CALL [12] { function: _+_ args: { - CALL [14] { + CALL [13] { function: _+_ args: { - IDENT [15] { - name: @index1 + IDENT [14] { + name: @index0 } - IDENT [16] { - name: @index1 + IDENT [15] { + name: @index0 } } } - IDENT [17] { - name: @index3 + IDENT [16] { + name: @index1 } } } - IDENT [18] { - name: @index3 + IDENT [17] { + name: @index1 } } } - } - } - CALL [19] { - function: _==_ - args: { - IDENT [20] { - name: @index4 - } - CONSTANT [21] { value: 6 } + CONSTANT [18] { value: 6 } } } } @@ -191,109 +170,97 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_LIST [3] { - elements: { - CONSTANT [4] { value: 0 } - } - } - CALL [5] { + CALL [3] { function: size args: { - IDENT [6] { - name: @index0 + CREATE_LIST [4] { + elements: { + CONSTANT [5] { value: 0 } + } } } } - CREATE_LIST [7] { - elements: { - CONSTANT [8] { value: 1 } - CONSTANT [9] { value: 2 } - } - } - CALL [10] { + CALL [6] { function: size args: { - IDENT [11] { - name: @index2 + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 1 } + CONSTANT [9] { value: 2 } + } } } } - CREATE_LIST [12] { - elements: { - CONSTANT [13] { value: 1 } - CONSTANT [14] { value: 2 } - CONSTANT [15] { value: 3 } - } - } - CALL [16] { + CALL [10] { function: size args: { - IDENT [17] { - name: @index4 + CREATE_LIST [11] { + elements: { + CONSTANT [12] { value: 1 } + CONSTANT [13] { value: 2 } + CONSTANT [14] { value: 3 } + } } } } - CALL [18] { + CALL [15] { function: _+_ args: { - CALL [19] { + CALL [16] { function: _+_ args: { - CALL [20] { + CALL [17] { function: _+_ args: { - CALL [21] { + CALL [18] { function: _+_ args: { - CALL [22] { + CALL [19] { function: _+_ args: { - CONSTANT [23] { value: 5 } - IDENT [24] { - name: @index1 + CONSTANT [20] { value: 5 } + IDENT [21] { + name: @index0 } } } - IDENT [25] { - name: @index1 + IDENT [22] { + name: @index0 } } } - IDENT [26] { - name: @index3 + IDENT [23] { + name: @index1 } } } - IDENT [27] { - name: @index3 + IDENT [24] { + name: @index1 } } } - IDENT [28] { - name: @index5 + IDENT [25] { + name: @index2 } } } - CALL [29] { + } + } + CALL [26] { + function: _==_ + args: { + CALL [27] { function: _+_ args: { - IDENT [30] { - name: @index6 + IDENT [28] { + name: @index3 } - IDENT [31] { - name: @index5 + IDENT [29] { + name: @index2 } } } - } - } - CALL [32] { - function: _==_ - args: { - IDENT [33] { - name: @index7 - } - CONSTANT [34] { value: 17 } + CONSTANT [30] { value: 17 } } } } @@ -307,143 +274,103 @@ CALL [1] { CREATE_LIST [2] { elements: { CALL [3] { - function: timestamp - args: { - CONSTANT [4] { value: 1000000000 } - } - } - CALL [5] { - function: int - args: { - IDENT [6] { - name: @index0 + function: getFullYear + target: { + CALL [4] { + function: timestamp + args: { + CALL [5] { + function: int + args: { + CALL [6] { + function: timestamp + args: { + CONSTANT [7] { value: 1000000000 } + } + } + } + } + } } } - } - CALL [7] { - function: timestamp args: { - IDENT [8] { - name: @index1 - } } } - CALL [9] { + CALL [8] { function: getFullYear target: { - IDENT [10] { - name: @index2 + CALL [9] { + function: timestamp + args: { + CALL [10] { + function: int + args: { + CALL [11] { + function: timestamp + args: { + CONSTANT [12] { value: 200 } + } + } + } + } + } } } args: { } } - CALL [11] { - function: timestamp - args: { - CONSTANT [12] { value: 50 } - } - } CALL [13] { - function: int - args: { - IDENT [14] { - name: @index4 - } - } - } - CALL [15] { function: timestamp args: { - IDENT [16] { - name: @index5 + CALL [14] { + function: int + args: { + CALL [15] { + function: timestamp + args: { + CONSTANT [16] { value: 50 } + } + } + } } } } CALL [17] { function: timestamp args: { - CONSTANT [18] { value: 200 } - } - } - CALL [19] { - function: int - args: { - IDENT [20] { - name: @index7 + CALL [18] { + function: int + args: { + CALL [19] { + function: timestamp + args: { + CONSTANT [20] { value: 75 } + } + } + } } } } CALL [21] { - function: timestamp - args: { - IDENT [22] { - name: @index8 - } - } - } - CALL [23] { - function: getFullYear - target: { - IDENT [24] { - name: @index9 - } - } - args: { - } - } - CALL [25] { - function: timestamp - args: { - CONSTANT [26] { value: 75 } - } - } - CALL [27] { - function: int + function: _+_ args: { - IDENT [28] { - name: @index11 - } - } - } - CALL [29] { - function: timestamp - args: { - IDENT [30] { - name: @index12 - } - } - } - CALL [31] { - function: getMinutes - target: { - IDENT [32] { - name: @index13 - } - } - args: { - } - } - CALL [33] { - function: _+_ - args: { - CALL [34] { + CALL [22] { function: _+_ args: { - CALL [35] { + CALL [23] { function: _+_ args: { - CALL [36] { + CALL [24] { function: _+_ args: { - IDENT [37] { - name: @index3 + IDENT [25] { + name: @index0 } - CALL [38] { + CALL [26] { function: getFullYear target: { - IDENT [39] { - name: @index13 + IDENT [27] { + name: @index3 } } args: { @@ -451,11 +378,11 @@ CALL [1] { } } } - CALL [40] { + CALL [28] { function: getFullYear target: { - IDENT [41] { - name: @index6 + IDENT [29] { + name: @index2 } } args: { @@ -463,16 +390,16 @@ CALL [1] { } } } - IDENT [42] { - name: @index3 + IDENT [30] { + name: @index0 } } } - CALL [43] { + CALL [31] { function: getSeconds target: { - IDENT [44] { - name: @index6 + IDENT [32] { + name: @index2 } } args: { @@ -480,50 +407,54 @@ CALL [1] { } } } - CALL [45] { + } + } + CALL [33] { + function: _==_ + args: { + CALL [34] { function: _+_ args: { - CALL [46] { + CALL [35] { function: _+_ args: { - CALL [47] { + CALL [36] { function: _+_ args: { - CALL [48] { + CALL [37] { function: _+_ args: { - IDENT [49] { - name: @index15 + IDENT [38] { + name: @index4 } - IDENT [50] { - name: @index10 + IDENT [39] { + name: @index1 } } } - IDENT [51] { - name: @index10 + IDENT [40] { + name: @index1 } } } - IDENT [52] { - name: @index14 + CALL [41] { + function: getMinutes + target: { + IDENT [42] { + name: @index3 + } + } + args: { + } } } } - IDENT [53] { - name: @index3 + IDENT [43] { + name: @index0 } } } - } - } - CALL [54] { - function: _==_ - args: { - IDENT [55] { - name: @index16 - } - CONSTANT [56] { value: 13934 } + CONSTANT [44] { value: 13934 } } } } @@ -536,53 +467,47 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_MAP [3] { - MAP_ENTRY [4] { - key: { - CONSTANT [5] { value: "a" } - } - value: { - CONSTANT [6] { value: 2 } - } - } - } - CALL [7] { + CALL [3] { function: _[_] args: { - IDENT [8] { - name: @index0 + CREATE_MAP [4] { + MAP_ENTRY [5] { + key: { + CONSTANT [6] { value: "a" } + } + value: { + CONSTANT [7] { value: 2 } + } + } } - CONSTANT [9] { value: "a" } + CONSTANT [8] { value: "a" } } } + } + } + CALL [9] { + function: _==_ + args: { CALL [10] { function: _+_ args: { IDENT [11] { - name: @index1 + name: @index0 } CALL [12] { function: _*_ args: { IDENT [13] { - name: @index1 + name: @index0 } IDENT [14] { - name: @index1 + name: @index0 } } } } } - } - } - CALL [15] { - function: _==_ - args: { - IDENT [16] { - name: @index2 - } - CONSTANT [17] { value: 6 } + CONSTANT [15] { value: 6 } } } } @@ -598,51 +523,48 @@ CALL [1] { CREATE_MAP [3] { MAP_ENTRY [4] { key: { - CONSTANT [5] { value: "b" } + CONSTANT [5] { value: "e" } } value: { - CONSTANT [6] { value: 1 } + CREATE_MAP [6] { + MAP_ENTRY [7] { + key: { + CONSTANT [8] { value: "b" } + } + value: { + CONSTANT [9] { value: 1 } + } + } + } } } } - CREATE_MAP [7] { - MAP_ENTRY [8] { + CREATE_MAP [10] { + MAP_ENTRY [11] { key: { - CONSTANT [9] { value: "e" } + CONSTANT [12] { value: "b" } } value: { - IDENT [10] { - name: @index0 - } + CONSTANT [13] { value: 1 } } } } } } - CREATE_MAP [11] { - MAP_ENTRY [12] { - key: { - CONSTANT [13] { value: "a" } - } - value: { - IDENT [14] { - name: @index0 - } - } - } + CREATE_MAP [14] { MAP_ENTRY [15] { key: { - CONSTANT [16] { value: "c" } + CONSTANT [16] { value: "a" } } value: { IDENT [17] { - name: @index0 + name: @index1 } } } MAP_ENTRY [18] { key: { - CONSTANT [19] { value: "d" } + CONSTANT [19] { value: "c" } } value: { IDENT [20] { @@ -652,11 +574,21 @@ CALL [1] { } MAP_ENTRY [21] { key: { - CONSTANT [22] { value: "e" } + CONSTANT [22] { value: "d" } } value: { IDENT [23] { - name: @index1 + name: @index0 + } + } + } + MAP_ENTRY [24] { + key: { + CONSTANT [25] { value: "e" } + } + value: { + IDENT [26] { + name: @index0 } } } @@ -685,37 +617,34 @@ CALL [1] { CONSTANT [10] { value: 2 } } } - CREATE_LIST [11] { - elements: { - IDENT [12] { - name: @index1 - } - IDENT [13] { - name: @index0 - } - } - } } } - CREATE_LIST [14] { + CREATE_LIST [11] { elements: { - CONSTANT [15] { value: 1 } - IDENT [16] { + CONSTANT [12] { value: 1 } + IDENT [13] { name: @index0 } - CONSTANT [17] { value: 2 } - IDENT [18] { + CONSTANT [14] { value: 2 } + IDENT [15] { name: @index0 } - CONSTANT [19] { value: 5 } - IDENT [20] { + CONSTANT [16] { value: 5 } + IDENT [17] { name: @index0 } - CONSTANT [21] { value: 7 } - IDENT [22] { - name: @index2 + CONSTANT [18] { value: 7 } + CREATE_LIST [19] { + elements: { + IDENT [20] { + name: @index1 + } + IDENT [21] { + name: @index0 + } + } } - IDENT [23] { + IDENT [22] { name: @index1 } } @@ -735,26 +664,23 @@ CALL [1] { name: msg }.single_int64 } - CALL [5] { + } + } + CALL [5] { + function: _==_ + args: { + CALL [6] { function: _+_ args: { - IDENT [6] { + IDENT [7] { name: @index0 } - IDENT [7] { + IDENT [8] { name: @index0 } } } - } - } - CALL [8] { - function: _==_ - args: { - IDENT [9] { - name: @index1 - } - CONSTANT [10] { value: 6 } + CONSTANT [9] { value: 6 } } } } @@ -768,58 +694,59 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload + SELECT [4] { + SELECT [5] { + IDENT [6] { + name: msg + }.oneof_type + }.payload + }.single_int64 } SELECT [7] { - IDENT [8] { - name: @index1 - }.single_int64 + SELECT [8] { + IDENT [9] { + name: msg + }.oneof_type + }.payload } - CALL [9] { + CALL [10] { function: _+_ args: { - CALL [10] { + CALL [11] { function: _+_ args: { - CALL [11] { + CALL [12] { function: _+_ args: { - CALL [12] { + CALL [13] { function: _+_ args: { - IDENT [13] { - name: @index2 + IDENT [14] { + name: @index0 } - SELECT [14] { - IDENT [15] { + SELECT [15] { + IDENT [16] { name: @index1 }.single_int32 } } } - IDENT [16] { - name: @index2 + IDENT [17] { + name: @index0 } } } - SELECT [17] { - IDENT [18] { + SELECT [18] { + IDENT [19] { name: msg }.single_int64 } } } - SELECT [19] { - SELECT [20] { - SELECT [21] { - IDENT [22] { + SELECT [20] { + SELECT [21] { + SELECT [22] { + IDENT [23] { name: @index1 }.oneof_type }.payload @@ -829,13 +756,13 @@ CALL [1] { } } } - CALL [23] { + CALL [24] { function: _==_ args: { - IDENT [24] { - name: @index3 + IDENT [25] { + name: @index2 } - CONSTANT [25] { value: 31 } + CONSTANT [26] { value: 31 } } } } @@ -849,51 +776,28 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload - } - SELECT [7] { - IDENT [8] { - name: @index1 - }.oneof_type - } - SELECT [9] { - IDENT [10] { - name: @index2 - }.payload - } - SELECT [11] { - IDENT [12] { - name: @index3 - }.oneof_type - } - SELECT [13] { - SELECT [14] { - SELECT [15] { - SELECT [16] { - IDENT [17] { - name: @index4 - }.child - }.child + SELECT [4] { + SELECT [5] { + SELECT [6] { + SELECT [7] { + IDENT [8] { + name: msg + }.oneof_type + }.payload + }.oneof_type }.payload - }.single_bool + }.oneof_type } - CALL [18] { + CALL [9] { function: _||_ args: { - CONSTANT [19] { value: true } - SELECT [20] { - SELECT [21] { - SELECT [22] { - SELECT [23] { - IDENT [24] { - name: @index4 + CONSTANT [10] { value: true } + SELECT [11] { + SELECT [12] { + SELECT [13] { + SELECT [14] { + IDENT [15] { + name: @index0 }.payload }.oneof_type }.payload @@ -903,14 +807,22 @@ CALL [1] { } } } - CALL [25] { + CALL [16] { function: _||_ args: { - IDENT [26] { - name: @index6 + IDENT [17] { + name: @index1 } - IDENT [27] { - name: @index5 + SELECT [18] { + SELECT [19] { + SELECT [20] { + SELECT [21] { + IDENT [22] { + name: @index0 + }.child + }.child + }.payload + }.single_bool } } } @@ -924,58 +836,46 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload - } - SELECT [7] { - IDENT [8] { - name: @index1 - }.map_int32_int64 - } - CALL [9] { + CALL [3] { function: _[_] args: { - IDENT [10] { - name: @index2 + SELECT [4] { + SELECT [5] { + SELECT [6] { + IDENT [7] { + name: msg + }.oneof_type + }.payload + }.map_int32_int64 } - CONSTANT [11] { value: 1 } + CONSTANT [8] { value: 1 } } } - CALL [12] { - function: _+_ - args: { - CALL [13] { + } + } + CALL [9] { + function: _==_ + args: { + CALL [10] { + function: _+_ + args: { + CALL [11] { function: _+_ args: { - IDENT [14] { - name: @index3 + IDENT [12] { + name: @index0 } - IDENT [15] { - name: @index3 + IDENT [13] { + name: @index0 } } } - IDENT [16] { - name: @index3 + IDENT [14] { + name: @index0 } } } - } - } - CALL [17] { - function: _==_ - args: { - IDENT [18] { - name: @index4 - } - CONSTANT [19] { value: 15 } + CONSTANT [15] { value: 15 } } } } @@ -989,66 +889,57 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload - } - SELECT [7] { - IDENT [8] { - name: @index1 + SELECT [4] { + SELECT [5] { + IDENT [6] { + name: msg + }.oneof_type + }.payload }.map_int32_int64 } - CALL [9] { + } + } + CALL [7] { + function: _==_ + args: { + CALL [8] { function: _+_ args: { - CALL [10] { + CALL [9] { function: _+_ args: { - CALL [11] { + CALL [10] { function: _[_] args: { - IDENT [12] { - name: @index2 + IDENT [11] { + name: @index0 } - CONSTANT [13] { value: 0 } + CONSTANT [12] { value: 0 } } } - CALL [14] { + CALL [13] { function: _[_] args: { - IDENT [15] { - name: @index2 + IDENT [14] { + name: @index0 } - CONSTANT [16] { value: 1 } + CONSTANT [15] { value: 1 } } } } } - CALL [17] { + CALL [16] { function: _[_] args: { - IDENT [18] { - name: @index2 + IDENT [17] { + name: @index0 } - CONSTANT [19] { value: 2 } + CONSTANT [18] { value: 2 } } } } } - } - } - CALL [20] { - function: _==_ - args: { - IDENT [21] { - name: @index3 - } - CONSTANT [22] { value: 8 } + CONSTANT [19] { value: 8 } } } } @@ -1074,20 +965,17 @@ CALL [1] { }.payload }.oneof_type } - SELECT [9] { - SELECT [10] { - SELECT [11] { - IDENT [12] { - name: @index0 - }.payload - }.oneof_type - }.payload - } } } - SELECT [13] { - IDENT [14] { - name: @index1 + SELECT [9] { + SELECT [10] { + SELECT [11] { + SELECT [12] { + IDENT [13] { + name: @index0 + }.payload + }.oneof_type + }.payload }.single_int64 } } @@ -1105,33 +993,30 @@ CALL [1] { name: msg }.single_int64 } - CALL [5] { + } + } + CALL [5] { + function: _==_ + args: { + CALL [6] { function: _?_:_ args: { - CALL [6] { + CALL [7] { function: _>_ args: { - IDENT [7] { + IDENT [8] { name: @index0 } - CONSTANT [8] { value: 0 } + CONSTANT [9] { value: 0 } } } - IDENT [9] { + IDENT [10] { name: @index0 } - CONSTANT [10] { value: 0 } + CONSTANT [11] { value: 0 } } } - } - } - CALL [11] { - function: _==_ - args: { - IDENT [12] { - name: @index1 - } - CONSTANT [13] { value: 3 } + CONSTANT [12] { value: 3 } } } } @@ -1149,47 +1034,44 @@ CALL [1] { name: msg }.single_int64 } - CALL [5] { + } + } + CALL [5] { + function: _?_:_ + args: { + CONSTANT [6] { value: false } + CONSTANT [7] { value: false } + CALL [8] { function: _==_ args: { - CALL [6] { + CALL [9] { function: _+_ args: { - IDENT [7] { + IDENT [10] { name: @index0 } - CALL [8] { + CALL [11] { function: _*_ args: { - CALL [9] { + CALL [12] { function: _+_ args: { - IDENT [10] { + IDENT [13] { name: @index0 } - CONSTANT [11] { value: 1 } + CONSTANT [14] { value: 1 } } } - CONSTANT [12] { value: 2 } + CONSTANT [15] { value: 2 } } } } } - CONSTANT [13] { value: 11 } + CONSTANT [16] { value: 11 } } } } } - CALL [14] { - function: _?_:_ - args: { - CONSTANT [15] { value: false } - CONSTANT [16] { value: false } - IDENT [17] { - name: @index1 - } - } - } } } Test case: NESTED_TERNARY @@ -1210,56 +1092,53 @@ CALL [1] { name: msg }.single_int32 } - CALL [7] { + } + } + CALL [7] { + function: _==_ + args: { + CALL [8] { function: _?_:_ args: { - CALL [8] { + CALL [9] { function: _>_ args: { - IDENT [9] { + IDENT [10] { name: @index0 } - CONSTANT [10] { value: 0 } + CONSTANT [11] { value: 0 } } } - CALL [11] { + CALL [12] { function: _?_:_ args: { - CALL [12] { + CALL [13] { function: _>_ args: { - IDENT [13] { + IDENT [14] { name: @index1 } - CONSTANT [14] { value: 0 } + CONSTANT [15] { value: 0 } } } - CALL [15] { + CALL [16] { function: _+_ args: { - IDENT [16] { + IDENT [17] { name: @index0 } - IDENT [17] { + IDENT [18] { name: @index1 } } } - CONSTANT [18] { value: 0 } + CONSTANT [19] { value: 0 } } } - CONSTANT [19] { value: 0 } + CONSTANT [20] { value: 0 } } } - } - } - CALL [20] { - function: _==_ - args: { - IDENT [21] { - name: @index2 - } - CONSTANT [22] { value: 8 } + CONSTANT [21] { value: 8 } } } } @@ -1272,50 +1151,60 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_LIST [3] { - elements: { - CONSTANT [4] { value: 1 } - } - } - CALL [5] { - function: _>_ - args: { - IDENT [6] { - name: @c0:0 - } - CONSTANT [7] { value: 0 } - } - } - CALL [8] { - function: _||_ + CALL [3] { + function: size args: { - IDENT [9] { - name: @x0:0 - } - IDENT [10] { - name: @index1 - } - } - } - COMPREHENSION [11] { - iter_var: @c0:0 - iter_range: { - IDENT [12] { - name: @index0 - } - } - accu_var: @x0:0 - accu_init: { - CONSTANT [13] { value: false } - } - loop_condition: { - CALL [14] { - function: @not_strictly_false - args: { - CALL [15] { - function: !_ - args: { - IDENT [16] { + CREATE_LIST [4] { + elements: { + COMPREHENSION [5] { + iter_var: @c0:0 + iter_range: { + CREATE_LIST [6] { + elements: { + CONSTANT [7] { value: 1 } + } + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [8] { value: false } + } + loop_condition: { + CALL [9] { + function: @not_strictly_false + args: { + CALL [10] { + function: !_ + args: { + IDENT [11] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + CALL [12] { + function: _||_ + args: { + IDENT [13] { + name: @x0:0 + } + CALL [14] { + function: _>_ + args: { + IDENT [15] { + name: @c0:0 + } + CONSTANT [16] { value: 0 } + } + } + } + } + } + result: { + IDENT [17] { name: @x0:0 } } @@ -1323,76 +1212,61 @@ CALL [1] { } } } - loop_step: { - IDENT [17] { - name: @index2 - } - } - result: { - IDENT [18] { - name: @x0:0 - } - } } - CREATE_LIST [19] { - elements: { - IDENT [20] { - name: @index3 - } - } - } - CALL [21] { + CALL [18] { function: size args: { - IDENT [22] { - name: @index4 - } - } - } - CREATE_LIST [23] { - elements: { - CONSTANT [24] { value: 2 } - } - } - CALL [25] { - function: _>_ - args: { - IDENT [26] { - name: @c0:0 - } - CONSTANT [27] { value: 1 } - } - } - CALL [28] { - function: _||_ - args: { - IDENT [29] { - name: @x0:0 - } - IDENT [30] { - name: @index7 - } - } - } - COMPREHENSION [31] { - iter_var: @c0:0 - iter_range: { - IDENT [32] { - name: @index6 - } - } - accu_var: @x0:0 - accu_init: { - CONSTANT [33] { value: false } - } - loop_condition: { - CALL [34] { - function: @not_strictly_false - args: { - CALL [35] { - function: !_ - args: { - IDENT [36] { + CREATE_LIST [19] { + elements: { + COMPREHENSION [20] { + iter_var: @c0:0 + iter_range: { + CREATE_LIST [21] { + elements: { + CONSTANT [22] { value: 2 } + } + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [23] { value: false } + } + loop_condition: { + CALL [24] { + function: @not_strictly_false + args: { + CALL [25] { + function: !_ + args: { + IDENT [26] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + CALL [27] { + function: _||_ + args: { + IDENT [28] { + name: @x0:0 + } + CALL [29] { + function: _>_ + args: { + IDENT [30] { + name: @c0:0 + } + CONSTANT [31] { value: 1 } + } + } + } + } + } + result: { + IDENT [32] { name: @x0:0 } } @@ -1400,68 +1274,40 @@ CALL [1] { } } } - loop_step: { - IDENT [37] { - name: @index8 - } - } - result: { - IDENT [38] { - name: @x0:0 - } - } - } - CREATE_LIST [39] { - elements: { - IDENT [40] { - name: @index9 - } - } - } - CALL [41] { - function: size - args: { - IDENT [42] { - name: @index10 - } - } } - CALL [43] { + } + } + CALL [33] { + function: _==_ + args: { + CALL [34] { function: _+_ args: { - CALL [44] { + CALL [35] { function: _+_ args: { - CALL [45] { + CALL [36] { function: _+_ args: { - IDENT [46] { - name: @index5 + IDENT [37] { + name: @index0 } - IDENT [47] { - name: @index5 + IDENT [38] { + name: @index0 } } } - IDENT [48] { - name: @index11 + IDENT [39] { + name: @index1 } } } - IDENT [49] { - name: @index11 + IDENT [40] { + name: @index1 } } } - } - } - CALL [50] { - function: _==_ - args: { - IDENT [51] { - name: @index12 - } - CONSTANT [52] { value: 4 } + CONSTANT [41] { value: 4 } } } } @@ -1476,187 +1322,157 @@ CALL [1] { elements: { CREATE_LIST [3] { elements: { - CONSTANT [4] { value: 1 } - } - } - CALL [5] { - function: _>_ - args: { - IDENT [6] { - name: @c0:0 - } - CONSTANT [7] { value: 0 } - } - } - CALL [8] { - function: _||_ - args: { - IDENT [9] { - name: @x0:0 - } - IDENT [10] { - name: @index1 - } - } - } - COMPREHENSION [11] { - iter_var: @c0:0 - iter_range: { - IDENT [12] { - name: @index0 - } - } - accu_var: @x0:0 - accu_init: { - CONSTANT [13] { value: false } - } - loop_condition: { - CALL [14] { - function: @not_strictly_false - args: { - CALL [15] { - function: !_ + COMPREHENSION [4] { + iter_var: @c0:0 + iter_range: { + CREATE_LIST [5] { + elements: { + CONSTANT [6] { value: 1 } + } + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [7] { value: false } + } + loop_condition: { + CALL [8] { + function: @not_strictly_false args: { - IDENT [16] { + CALL [9] { + function: !_ + args: { + IDENT [10] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + CALL [11] { + function: _||_ + args: { + IDENT [12] { name: @x0:0 } + CALL [13] { + function: _>_ + args: { + IDENT [14] { + name: @c0:0 + } + CONSTANT [15] { value: 0 } + } + } } } } - } - } - loop_step: { - IDENT [17] { - name: @index2 - } - } - result: { - IDENT [18] { - name: @x0:0 - } - } - } - CREATE_LIST [19] { - elements: { - IDENT [20] { - name: @index3 + result: { + IDENT [16] { + name: @x0:0 + } + } } } } - CREATE_LIST [21] { + CREATE_LIST [17] { elements: { - CONSTANT [22] { value: "a" } - } - } - CALL [23] { - function: _==_ - args: { - IDENT [24] { - name: @c0:1 - } - CONSTANT [25] { value: "a" } - } - } - CALL [26] { - function: _||_ - args: { - IDENT [27] { - name: @x0:1 - } - IDENT [28] { - name: @index6 - } - } - } - COMPREHENSION [29] { - iter_var: @c0:1 - iter_range: { - IDENT [30] { - name: @index5 - } - } - accu_var: @x0:1 - accu_init: { - CONSTANT [31] { value: false } - } - loop_condition: { - CALL [32] { - function: @not_strictly_false - args: { - CALL [33] { - function: !_ + COMPREHENSION [18] { + iter_var: @c0:1 + iter_range: { + CREATE_LIST [19] { + elements: { + CONSTANT [20] { value: "a" } + } + } + } + accu_var: @x0:1 + accu_init: { + CONSTANT [21] { value: false } + } + loop_condition: { + CALL [22] { + function: @not_strictly_false args: { - IDENT [34] { - name: @x0:1 + CALL [23] { + function: !_ + args: { + IDENT [24] { + name: @x0:1 + } + } } } } } + loop_step: { + CALL [25] { + function: _||_ + args: { + IDENT [26] { + name: @x0:1 + } + CALL [27] { + function: _==_ + args: { + IDENT [28] { + name: @c0:1 + } + CONSTANT [29] { value: "a" } + } + } + } + } + } + result: { + IDENT [30] { + name: @x0:1 + } + } } } - loop_step: { - IDENT [35] { - name: @index7 - } - } - result: { - IDENT [36] { - name: @x0:1 - } - } - } - CREATE_LIST [37] { - elements: { - IDENT [38] { - name: @index8 - } - } - } - CREATE_LIST [39] { - elements: { - CONSTANT [40] { value: true } - CONSTANT [41] { value: true } - CONSTANT [42] { value: true } - CONSTANT [43] { value: true } - } } - CALL [44] { + } + } + CALL [31] { + function: _==_ + args: { + CALL [32] { function: _+_ args: { - CALL [45] { + CALL [33] { function: _+_ args: { - CALL [46] { + CALL [34] { function: _+_ args: { - IDENT [47] { - name: @index4 + IDENT [35] { + name: @index0 } - IDENT [48] { - name: @index4 + IDENT [36] { + name: @index0 } } } - IDENT [49] { - name: @index9 + IDENT [37] { + name: @index1 } } } - IDENT [50] { - name: @index9 + IDENT [38] { + name: @index1 } } } - } - } - CALL [51] { - function: _==_ - args: { - IDENT [52] { - name: @index11 - } - IDENT [53] { - name: @index10 + CREATE_LIST [39] { + elements: { + CONSTANT [40] { value: true } + CONSTANT [41] { value: true } + CONSTANT [42] { value: true } + CONSTANT [43] { value: true } + } } } } @@ -1686,52 +1502,39 @@ CALL [1] { } CREATE_LIST [11] { elements: { - IDENT [12] { - name: @index1 - } - IDENT [13] { - name: @index1 - } - IDENT [14] { - name: @index1 - } - } - } - CREATE_LIST [15] { - elements: { - COMPREHENSION [16] { + COMPREHENSION [12] { iter_var: @c1:0 iter_range: { - IDENT [17] { + IDENT [13] { name: @index0 } } accu_var: @x1:0 accu_init: { - CREATE_LIST [18] { + CREATE_LIST [14] { elements: { } } } loop_condition: { - CONSTANT [19] { value: true } + CONSTANT [15] { value: true } } loop_step: { - CALL [20] { + CALL [16] { function: _+_ args: { - IDENT [21] { + IDENT [17] { name: @x1:0 } - CREATE_LIST [22] { + CREATE_LIST [18] { elements: { - CALL [23] { + CALL [19] { function: _+_ args: { - IDENT [24] { + IDENT [20] { name: @c1:0 } - CONSTANT [25] { value: 1 } + CONSTANT [21] { value: 1 } } } } @@ -1740,59 +1543,66 @@ CALL [1] { } } result: { - IDENT [26] { + IDENT [22] { name: @x1:0 } } } } } - COMPREHENSION [27] { + } + } + CALL [23] { + function: _==_ + args: { + COMPREHENSION [24] { iter_var: @c0:0 iter_range: { - IDENT [28] { + IDENT [25] { name: @index0 } } accu_var: @x0:0 accu_init: { - CREATE_LIST [29] { + CREATE_LIST [26] { elements: { } } } loop_condition: { - CONSTANT [30] { value: true } + CONSTANT [27] { value: true } } loop_step: { - CALL [31] { + CALL [28] { function: _+_ args: { - IDENT [32] { + IDENT [29] { name: @x0:0 } - IDENT [33] { - name: @index3 + IDENT [30] { + name: @index2 } } } } result: { - IDENT [34] { + IDENT [31] { name: @x0:0 } } } - } - } - CALL [35] { - function: _==_ - args: { - IDENT [36] { - name: @index4 - } - IDENT [37] { - name: @index2 + CREATE_LIST [32] { + elements: { + IDENT [33] { + name: @index1 + } + IDENT [34] { + name: @index1 + } + IDENT [35] { + name: @index1 + } + } } } } @@ -1808,134 +1618,128 @@ CALL [1] { elements: { CREATE_LIST [3] { elements: { - CREATE_LIST [4] { - elements: { - CONSTANT [5] { value: 1 } - } - } - CREATE_LIST [6] { - elements: { - CONSTANT [7] { value: 2 } - } - } - } - } - CREATE_LIST [8] { - elements: { - COMPREHENSION [9] { + COMPREHENSION [4] { iter_var: @c1:0 iter_range: { - CREATE_LIST [10] { + CREATE_LIST [5] { elements: { - CONSTANT [11] { value: 1 } - CONSTANT [12] { value: 2 } - CONSTANT [13] { value: 3 } + CONSTANT [6] { value: 1 } + CONSTANT [7] { value: 2 } + CONSTANT [8] { value: 3 } } } } accu_var: @x1:0 accu_init: { - CREATE_LIST [14] { + CREATE_LIST [9] { elements: { } } } loop_condition: { - CONSTANT [15] { value: true } + CONSTANT [10] { value: true } } loop_step: { - CALL [16] { + CALL [11] { function: _?_:_ args: { - CALL [17] { + CALL [12] { function: _==_ args: { - IDENT [18] { + IDENT [13] { name: @c1:0 } - IDENT [19] { + IDENT [14] { name: @c0:0 } } } - CALL [20] { + CALL [15] { function: _+_ args: { - IDENT [21] { + IDENT [16] { name: @x1:0 } - CREATE_LIST [22] { + CREATE_LIST [17] { elements: { - IDENT [23] { + IDENT [18] { name: @c1:0 } } } } } - IDENT [24] { + IDENT [19] { name: @x1:0 } } } } result: { - IDENT [25] { + IDENT [20] { name: @x1:0 } } } } } - COMPREHENSION [26] { + } + } + CALL [21] { + function: _==_ + args: { + COMPREHENSION [22] { iter_var: @c0:0 iter_range: { - CREATE_LIST [27] { + CREATE_LIST [23] { elements: { - CONSTANT [28] { value: 1 } - CONSTANT [29] { value: 2 } + CONSTANT [24] { value: 1 } + CONSTANT [25] { value: 2 } } } } accu_var: @x0:0 accu_init: { - CREATE_LIST [30] { + CREATE_LIST [26] { elements: { } } } loop_condition: { - CONSTANT [31] { value: true } + CONSTANT [27] { value: true } } loop_step: { - CALL [32] { + CALL [28] { function: _+_ args: { - IDENT [33] { + IDENT [29] { name: @x0:0 } - IDENT [34] { - name: @index1 + IDENT [30] { + name: @index0 } } } } result: { - IDENT [35] { + IDENT [31] { name: @x0:0 } } } - } - } - CALL [36] { - function: _==_ - args: { - IDENT [37] { - name: @index2 - } - IDENT [38] { - name: @index0 + CREATE_LIST [32] { + elements: { + CREATE_LIST [33] { + elements: { + CONSTANT [34] { value: 1 } + } + } + CREATE_LIST [35] { + elements: { + CONSTANT [36] { value: 2 } + } + } + } } } } @@ -1949,74 +1753,72 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_LIST [3] { - elements: { - CONSTANT [4] { value: 1 } - CONSTANT [5] { value: 2 } - CONSTANT [6] { value: 3 } - } - } - CALL [7] { + CALL [3] { function: @in args: { - CONSTANT [8] { value: 1 } - IDENT [9] { - name: @index0 + CONSTANT [4] { value: 1 } + CREATE_LIST [5] { + elements: { + CONSTANT [6] { value: 1 } + CONSTANT [7] { value: 2 } + CONSTANT [8] { value: 3 } + } } } } - CALL [10] { + CREATE_LIST [9] { + elements: { + CONSTANT [10] { value: 1 } + CONSTANT [11] { value: 2 } + CONSTANT [12] { value: 3 } + } + } + } + } + CALL [13] { + function: _&&_ + args: { + CALL [14] { function: _&&_ args: { - CALL [11] { + IDENT [15] { + name: @index0 + } + CALL [16] { function: @in args: { - CONSTANT [12] { value: 3 } - CREATE_LIST [13] { - elements: { - CONSTANT [14] { value: 3 } - IDENT [15] { - name: @index0 - } - } + CONSTANT [17] { value: 2 } + IDENT [18] { + name: @index1 } } } - IDENT [16] { - name: @index1 - } } } - CALL [17] { + CALL [19] { function: _&&_ args: { - IDENT [18] { - name: @index1 - } - CALL [19] { + CALL [20] { function: @in args: { - CONSTANT [20] { value: 2 } - IDENT [21] { - name: @index0 + CONSTANT [21] { value: 3 } + CREATE_LIST [22] { + elements: { + CONSTANT [23] { value: 3 } + IDENT [24] { + name: @index1 + } + } } } } + IDENT [25] { + name: @index0 + } } } } } - CALL [22] { - function: _&&_ - args: { - IDENT [23] { - name: @index3 - } - IDENT [24] { - name: @index2 - } - } - } } } Test case: INCLUSION_MAP @@ -2037,31 +1839,37 @@ CALL [1] { } } } - CREATE_MAP [7] { - MAP_ENTRY [8] { + } + } + CALL [7] { + function: @in + args: { + CONSTANT [8] { value: 2 } + CREATE_MAP [9] { + MAP_ENTRY [10] { key: { - CONSTANT [9] { value: "a" } + CONSTANT [11] { value: "a" } } value: { - CONSTANT [10] { value: 1 } + CONSTANT [12] { value: 1 } } } - MAP_ENTRY [11] { + MAP_ENTRY [13] { key: { - CONSTANT [12] { value: 2 } + CONSTANT [14] { value: 2 } } value: { - IDENT [13] { + IDENT [15] { name: @index0 } } } - MAP_ENTRY [14] { + MAP_ENTRY [16] { key: { - CONSTANT [15] { value: 3 } + CONSTANT [17] { value: 3 } } value: { - IDENT [16] { + IDENT [18] { name: @index0 } } @@ -2069,15 +1877,6 @@ CALL [1] { } } } - CALL [17] { - function: @in - args: { - CONSTANT [18] { value: 2 } - IDENT [19] { - name: @index1 - } - } - } } } Test case: MACRO_ITER_VAR_NOT_REFERENCED @@ -2090,126 +1889,123 @@ CALL [1] { elements: { CREATE_LIST [3] { elements: { - CONSTANT [4] { value: 1 } - CONSTANT [5] { value: 2 } - } - } - CREATE_LIST [6] { - elements: { - CONSTANT [7] { value: 3 } - CONSTANT [8] { value: 4 } - } - } - CREATE_LIST [9] { - elements: { - IDENT [10] { - name: @index1 + CREATE_LIST [4] { + elements: { + CONSTANT [5] { value: 3 } + CONSTANT [6] { value: 4 } + } } - IDENT [11] { - name: @index1 + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 3 } + CONSTANT [9] { value: 4 } + } } } } - CREATE_LIST [12] { + CREATE_LIST [10] { elements: { - IDENT [13] { - name: @index2 - } - IDENT [14] { - name: @index2 - } + CONSTANT [11] { value: 1 } + CONSTANT [12] { value: 2 } } } - CALL [15] { - function: _+_ - args: { - IDENT [16] { - name: @x0:0 - } - CREATE_LIST [17] { - elements: { - COMPREHENSION [18] { - iter_var: @c1:0 - iter_range: { + CREATE_LIST [13] { + elements: { + COMPREHENSION [14] { + iter_var: @c1:0 + iter_range: { + IDENT [15] { + name: @index1 + } + } + accu_var: @x1:0 + accu_init: { + CREATE_LIST [16] { + elements: { + } + } + } + loop_condition: { + CONSTANT [17] { value: true } + } + loop_step: { + CALL [18] { + function: _+_ + args: { IDENT [19] { - name: @index0 + name: @x1:0 } - } - accu_var: @x1:0 - accu_init: { CREATE_LIST [20] { elements: { - } - } - } - loop_condition: { - CONSTANT [21] { value: true } - } - loop_step: { - CALL [22] { - function: _+_ - args: { - IDENT [23] { - name: @x1:0 - } - CREATE_LIST [24] { + CREATE_LIST [21] { elements: { - IDENT [25] { - name: @index1 - } + CONSTANT [22] { value: 3 } + CONSTANT [23] { value: 4 } } } } } } - result: { - IDENT [26] { - name: @x1:0 - } - } + } + } + result: { + IDENT [24] { + name: @x1:0 } } } } } - COMPREHENSION [27] { + } + } + CALL [25] { + function: _==_ + args: { + COMPREHENSION [26] { iter_var: @c0:0 iter_range: { - IDENT [28] { - name: @index0 + IDENT [27] { + name: @index1 } } accu_var: @x0:0 accu_init: { - CREATE_LIST [29] { + CREATE_LIST [28] { elements: { } } } loop_condition: { - CONSTANT [30] { value: true } + CONSTANT [29] { value: true } } loop_step: { - IDENT [31] { - name: @index4 + CALL [30] { + function: _+_ + args: { + IDENT [31] { + name: @x0:0 + } + IDENT [32] { + name: @index2 + } + } } } result: { - IDENT [32] { + IDENT [33] { name: @x0:0 } } } - } - } - CALL [33] { - function: _==_ - args: { - IDENT [34] { - name: @index5 - } - IDENT [35] { - name: @index3 + CREATE_LIST [34] { + elements: { + IDENT [35] { + name: @index0 + } + IDENT [36] { + name: @index0 + } + } } } } @@ -2224,23 +2020,25 @@ CALL [1] { CREATE_LIST [2] { elements: { CALL [3] { - function: _-_ - args: { - IDENT [4] { - name: x - } - CONSTANT [5] { value: 1 } - } - } - CALL [6] { function: _>_ args: { - IDENT [7] { - name: @index0 + CALL [4] { + function: _-_ + args: { + IDENT [5] { + name: x + } + CONSTANT [6] { value: 1 } + } } - CONSTANT [8] { value: 3 } + CONSTANT [7] { value: 3 } } } + } + } + CALL [8] { + function: _||_ + args: { COMPREHENSION [9] { iter_var: @c0:0 iter_range: { @@ -2250,12 +2048,18 @@ CALL [1] { function: _?_:_ args: { IDENT [12] { - name: @index1 - } - IDENT [13] { name: @index0 } - CONSTANT [14] { value: 5 } + CALL [13] { + function: _-_ + args: { + IDENT [14] { + name: x + } + CONSTANT [15] { value: 1 } + } + } + CONSTANT [16] { value: 5 } } } } @@ -2263,16 +2067,16 @@ CALL [1] { } accu_var: @x0:0 accu_init: { - CONSTANT [15] { value: false } + CONSTANT [17] { value: false } } loop_condition: { - CALL [16] { + CALL [18] { function: @not_strictly_false args: { - CALL [17] { + CALL [19] { function: !_ args: { - IDENT [18] { + IDENT [20] { name: @x0:0 } } @@ -2281,46 +2085,38 @@ CALL [1] { } } loop_step: { - CALL [19] { + CALL [21] { function: _||_ args: { - IDENT [20] { + IDENT [22] { name: @x0:0 } - CALL [21] { + CALL [23] { function: _>_ args: { - CALL [22] { + CALL [24] { function: _-_ args: { - IDENT [23] { + IDENT [25] { name: @c0:0 } - CONSTANT [24] { value: 1 } + CONSTANT [26] { value: 1 } } } - CONSTANT [25] { value: 3 } + CONSTANT [27] { value: 3 } } } } } } result: { - IDENT [26] { + IDENT [28] { name: @x0:0 } } } - } - } - CALL [27] { - function: _||_ - args: { - IDENT [28] { - name: @index2 - } IDENT [29] { - name: @index1 + name: @index0 } } } @@ -2356,63 +2152,46 @@ CALL [1] { } } } - CALL [9] { - function: _+_ - args: { - IDENT [10] { - name: @x0:0 - } - CREATE_LIST [11] { - elements: { - CREATE_LIST [12] { - elements: { - IDENT [13] { - name: @index1 - } - IDENT [14] { - name: @index1 - } - } - } - } - } - } - } - COMPREHENSION [15] { + } + } + COMPREHENSION [9] { + iter_var: @c0:0 + iter_range: { + COMPREHENSION [10] { iter_var: @c1:0 iter_range: { - CREATE_LIST [16] { + CREATE_LIST [11] { elements: { - CONSTANT [17] { value: "foo" } - CONSTANT [18] { value: "bar" } + CONSTANT [12] { value: "foo" } + CONSTANT [13] { value: "bar" } } } } accu_var: @x1:0 accu_init: { - CREATE_LIST [19] { + CREATE_LIST [14] { elements: { } } } loop_condition: { - CONSTANT [20] { value: true } + CONSTANT [15] { value: true } } loop_step: { - CALL [21] { + CALL [16] { function: _+_ args: { - IDENT [22] { + IDENT [17] { name: @x1:0 } - CREATE_LIST [23] { + CREATE_LIST [18] { elements: { - CREATE_LIST [24] { + CREATE_LIST [19] { elements: { - IDENT [25] { + IDENT [20] { name: @index0 } - IDENT [26] { + IDENT [21] { name: @index0 } } @@ -2423,37 +2202,48 @@ CALL [1] { } } result: { - IDENT [27] { + IDENT [22] { name: @x1:0 } } } } - } - COMPREHENSION [28] { - iter_var: @c0:0 - iter_range: { - IDENT [29] { - name: @index3 - } - } accu_var: @x0:0 accu_init: { - CREATE_LIST [30] { + CREATE_LIST [23] { elements: { } } } loop_condition: { - CONSTANT [31] { value: true } + CONSTANT [24] { value: true } } loop_step: { - IDENT [32] { - name: @index2 + CALL [25] { + function: _+_ + args: { + IDENT [26] { + name: @x0:0 + } + CREATE_LIST [27] { + elements: { + CREATE_LIST [28] { + elements: { + IDENT [29] { + name: @index1 + } + IDENT [30] { + name: @index1 + } + } + } + } + } + } } } result: { - IDENT [33] { + IDENT [31] { name: @x0:0 } } @@ -2478,27 +2268,24 @@ CALL [1] { } } } - CALL [7] { - function: _[_] - args: { - IDENT [8] { - name: @index0 - } - CONSTANT [9] { value: "a" } - } - } } } - CALL [10] { + CALL [7] { function: _&&_ args: { - SELECT [11] { - IDENT [12] { + SELECT [8] { + IDENT [9] { name: @index0 }.a~presence_test } - IDENT [13] { - name: @index1 + CALL [10] { + function: _[_] + args: { + IDENT [11] { + name: @index0 + } + CONSTANT [12] { value: "a" } + } } } } @@ -2517,33 +2304,30 @@ CALL [1] { name: msg }.oneof_type } - CALL [5] { + } + } + CALL [5] { + function: _==_ + args: { + CALL [6] { function: _?_:_ args: { - SELECT [6] { - IDENT [7] { + SELECT [7] { + IDENT [8] { name: @index0 }.payload~presence_test } - SELECT [8] { - SELECT [9] { - IDENT [10] { + SELECT [9] { + SELECT [10] { + IDENT [11] { name: @index0 }.payload }.single_int64 } - CONSTANT [11] { value: 0 } + CONSTANT [12] { value: 0 } } } - } - } - CALL [12] { - function: _==_ - args: { - IDENT [13] { - name: @index1 - } - CONSTANT [14] { value: 10 } + CONSTANT [13] { value: 10 } } } } @@ -2557,51 +2341,44 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload - } - SELECT [7] { - IDENT [8] { - name: @index1 + SELECT [4] { + SELECT [5] { + IDENT [6] { + name: msg + }.oneof_type + }.payload }.single_int64 } - CALL [9] { + } + } + CALL [7] { + function: _==_ + args: { + CALL [8] { function: _?_:_ args: { - SELECT [10] { - IDENT [11] { - name: @index0 + SELECT [9] { + SELECT [10] { + IDENT [11] { + name: msg + }.oneof_type }.payload~presence_test } IDENT [12] { - name: @index2 + name: @index0 } CALL [13] { function: _*_ args: { IDENT [14] { - name: @index2 + name: @index0 } CONSTANT [15] { value: 0 } } } } } - } - } - CALL [16] { - function: _==_ - args: { - IDENT [17] { - name: @index3 - } - CONSTANT [18] { value: 10 } + CONSTANT [16] { value: 10 } } } } @@ -2611,55 +2388,50 @@ Source: (has(msg.oneof_type.payload.single_int64) ? msg.oneof_type.payload.singl =====> CALL [1] { function: cel.@block - args: { - CREATE_LIST [2] { - elements: { - SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload - } - SELECT [7] { - IDENT [8] { - name: @index1 + args: { + CREATE_LIST [2] { + elements: { + SELECT [3] { + SELECT [4] { + SELECT [5] { + IDENT [6] { + name: msg + }.oneof_type + }.payload }.single_int64 } - CALL [9] { + } + } + CALL [7] { + function: _==_ + args: { + CALL [8] { function: _?_:_ args: { - SELECT [10] { - IDENT [11] { - name: @index1 + SELECT [9] { + SELECT [10] { + SELECT [11] { + IDENT [12] { + name: msg + }.oneof_type + }.payload }.single_int64~presence_test } - IDENT [12] { - name: @index2 + IDENT [13] { + name: @index0 } - CALL [13] { + CALL [14] { function: _*_ args: { - IDENT [14] { - name: @index2 + IDENT [15] { + name: @index0 } - CONSTANT [15] { value: 0 } + CONSTANT [16] { value: 0 } } } } } - } - } - CALL [16] { - function: _==_ - args: { - IDENT [17] { - name: @index3 - } - CONSTANT [18] { value: 10 } + CONSTANT [17] { value: 10 } } } } @@ -2673,88 +2445,85 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload + SELECT [4] { + SELECT [5] { + IDENT [6] { + name: msg + }.oneof_type + }.payload + }.map_string_string } SELECT [7] { - IDENT [8] { - name: @index1 - }.map_string_string + SELECT [8] { + IDENT [9] { + name: msg + }.oneof_type + }.payload } - CALL [9] { - function: _?_:_ + } + } + CALL [10] { + function: _?_:_ + args: { + CALL [11] { + function: _&&_ args: { - CALL [10] { + CALL [12] { function: _&&_ args: { - SELECT [11] { - IDENT [12] { - name: @index1 - }.map_string_string~presence_test - } SELECT [13] { IDENT [14] { - name: @index2 - }.key~presence_test + name: msg + }.oneof_type~presence_test } - } - } - CALL [15] { - function: _==_ - args: { - SELECT [16] { - IDENT [17] { - name: @index2 - }.key + SELECT [15] { + SELECT [16] { + IDENT [17] { + name: msg + }.oneof_type + }.payload~presence_test } - CONSTANT [18] { value: "A" } } } - CONSTANT [19] { value: false } + SELECT [18] { + IDENT [19] { + name: @index1 + }.single_int64~presence_test + } } } CALL [20] { - function: _&&_ + function: _?_:_ args: { CALL [21] { function: _&&_ args: { SELECT [22] { IDENT [23] { - name: msg - }.oneof_type~presence_test + name: @index1 + }.map_string_string~presence_test } SELECT [24] { IDENT [25] { name: @index0 - }.payload~presence_test + }.key~presence_test } } } - SELECT [26] { - IDENT [27] { - name: @index1 - }.single_int64~presence_test + CALL [26] { + function: _==_ + args: { + SELECT [27] { + IDENT [28] { + name: @index0 + }.key + } + CONSTANT [29] { value: "A" } + } } + CONSTANT [30] { value: false } } } - } - } - CALL [28] { - function: _?_:_ - args: { - IDENT [29] { - name: @index4 - } - IDENT [30] { - name: @index3 - } CONSTANT [31] { value: false } } } @@ -2768,44 +2537,49 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CALL [3] { - function: optional.none - args: { - } - } - CREATE_LIST [4] { + CREATE_LIST [3] { elements: { - IDENT [5] { - name: @index0 + CALL [4] { + function: optional.none + args: { + } } - IDENT [6] { + IDENT [5] { name: opt_x } } optional_indices: [0, 1] } - CREATE_LIST [7] { + CREATE_LIST [6] { elements: { - CONSTANT [8] { value: 5 } + CONSTANT [7] { value: 5 } } } + } + } + CALL [8] { + function: _==_ + args: { CREATE_LIST [9] { elements: { CONSTANT [10] { value: 10 } - IDENT [11] { - name: @index2 + CALL [11] { + function: optional.none + args: { + } } IDENT [12] { - name: @index2 + name: @index0 + } + IDENT [13] { + name: @index0 } } + optional_indices: [0] } - CREATE_LIST [13] { + CREATE_LIST [14] { elements: { - CONSTANT [14] { value: 10 } - IDENT [15] { - name: @index0 - } + CONSTANT [15] { value: 10 } IDENT [16] { name: @index1 } @@ -2813,18 +2587,6 @@ CALL [1] { name: @index1 } } - optional_indices: [0] - } - } - } - CALL [18] { - function: _==_ - args: { - IDENT [19] { - name: @index4 - } - IDENT [20] { - name: @index3 } } } @@ -2839,53 +2601,44 @@ CALL [1] { CREATE_LIST [2] { elements: { CALL [3] { - function: optional.of - args: { - CONSTANT [4] { value: "hello" } - } - } - CREATE_MAP [5] { - MAP_ENTRY [6] { - key: { - CONSTANT [7] { value: "hello" } - } - optional_entry: true - value: { - IDENT [8] { - name: @index0 - } - } - } - } - CALL [9] { function: _[_] args: { - IDENT [10] { - name: @index1 + CREATE_MAP [4] { + MAP_ENTRY [5] { + key: { + CONSTANT [6] { value: "hello" } + } + optional_entry: true + value: { + CALL [7] { + function: optional.of + args: { + CONSTANT [8] { value: "hello" } + } + } + } + } } - CONSTANT [11] { value: "hello" } + CONSTANT [9] { value: "hello" } } } - CALL [12] { + } + } + CALL [10] { + function: _==_ + args: { + CALL [11] { function: _+_ args: { - IDENT [13] { - name: @index2 + IDENT [12] { + name: @index0 } - IDENT [14] { - name: @index2 + IDENT [13] { + name: @index0 } } } - } - } - CALL [15] { - function: _==_ - args: { - IDENT [16] { - name: @index3 - } - CONSTANT [17] { value: "hellohello" } + CONSTANT [14] { value: "hellohello" } } } } @@ -2979,143 +2732,66 @@ Test case: OPTIONAL_MESSAGE Source: TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}.single_int32 + TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}.single_int64 == 5 =====> CALL [1] { - function: cel.@block - args: { - CREATE_LIST [2] { - elements: { - CALL [3] { - function: optional.ofNonZeroValue - args: { - CONSTANT [4] { value: 1 } - } - } - CALL [5] { - function: optional.of - args: { - CONSTANT [6] { value: 4 } - } - } - CREATE_STRUCT [7] { - name: TestAllTypes - entries: { - ENTRY [8] { - field_key: single_int64 - optional_entry: true - value: { - IDENT [9] { - name: @index0 - } - } - } - ENTRY [10] { - field_key: single_int32 - optional_entry: true - value: { - IDENT [11] { - name: @index1 - } - } - } - } - } - CALL [12] { - function: _+_ - args: { - SELECT [13] { - IDENT [14] { - name: @index2 - }.single_int32 - } - SELECT [15] { - IDENT [16] { - name: @index2 - }.single_int64 - } - } - } - } - } - CALL [17] { - function: _==_ - args: { - IDENT [18] { - name: @index3 - } - CONSTANT [19] { value: 5 } - } - } - } -} -Test case: CALL -Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('h' + 'e' + 'l' + 'l' + 'o') -=====> -CALL [1] { - function: cel.@block - args: { - CREATE_LIST [2] { - elements: { - CALL [3] { - function: _+_ - args: { - CONSTANT [4] { value: "h" } - CONSTANT [5] { value: "e" } - } - } - CALL [6] { - function: _+_ - args: { - IDENT [7] { - name: @index0 + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_STRUCT [3] { + name: TestAllTypes + entries: { + ENTRY [4] { + field_key: single_int64 + optional_entry: true + value: { + CALL [5] { + function: optional.ofNonZeroValue + args: { + CONSTANT [6] { value: 1 } + } + } + } } - CONSTANT [8] { value: "l" } - } - } - CALL [9] { - function: _+_ - args: { - IDENT [10] { - name: @index1 + ENTRY [7] { + field_key: single_int32 + optional_entry: true + value: { + CALL [8] { + function: optional.of + args: { + CONSTANT [9] { value: 4 } + } + } + } } - CONSTANT [11] { value: "l" } } } - CALL [12] { + } + } + CALL [10] { + function: _==_ + args: { + CALL [11] { function: _+_ args: { - IDENT [13] { - name: @index2 + SELECT [12] { + IDENT [13] { + name: @index0 + }.single_int32 } - CONSTANT [14] { value: "o" } - } - } - CALL [15] { - function: _+_ - args: { - IDENT [16] { - name: @index3 + SELECT [14] { + IDENT [15] { + name: @index0 + }.single_int64 } - CONSTANT [17] { value: " world" } } } - } - } - CALL [18] { - function: matches - target: { - IDENT [19] { - name: @index4 - } - } - args: { - IDENT [20] { - name: @index3 - } + CONSTANT [16] { value: 5 } } } } } -Test case: CALL_ARGUMENT_NESTED_NO_COMMON_SUBEXPR -Source: 'hello world'.matches('h' + 'e' + 'l' + 'l' + 'o') +Test case: CALL +Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('h' + 'e' + 'l' + 'l' + 'o') =====> CALL [1] { function: cel.@block @@ -3152,16 +2828,60 @@ CALL [1] { CALL [12] { function: matches target: { - CONSTANT [13] { value: "hello world" } + CALL [13] { + function: _+_ + args: { + IDENT [14] { + name: @index0 + } + CONSTANT [15] { value: " world" } + } + } } args: { - IDENT [14] { + IDENT [16] { name: @index0 } } } } } +Test case: CALL_ARGUMENT_NESTED_NO_COMMON_SUBEXPR +Source: 'hello world'.matches('h' + 'e' + 'l' + 'l' + 'o') +=====> +CALL [2] { + function: matches + target: { + CONSTANT [1] { value: "hello world" } + } + args: { + CALL [10] { + function: _+_ + args: { + CALL [8] { + function: _+_ + args: { + CALL [6] { + function: _+_ + args: { + CALL [4] { + function: _+_ + args: { + CONSTANT [3] { value: "h" } + CONSTANT [5] { value: "e" } + } + } + CONSTANT [7] { value: "l" } + } + } + CONSTANT [9] { value: "l" } + } + } + CONSTANT [11] { value: "o" } + } + } + } +} Test case: CALL_TARGET_NESTED_NO_COMMON_SUBEXPR Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('hello') =====> @@ -3236,65 +2956,62 @@ CALL [1] { CALL [6] { function: _+_ args: { - CONSTANT [7] { value: "w" } - CONSTANT [8] { value: "o" } + CALL [7] { + function: _+_ + args: { + CONSTANT [8] { value: "h" } + CONSTANT [9] { value: "e" } + } + } + CONSTANT [10] { value: "l" } } } - CONSTANT [9] { value: "r" } + CONSTANT [11] { value: "l" } } } - CONSTANT [10] { value: "l" } + CONSTANT [12] { value: "o" } } } - CONSTANT [11] { value: "d" } + CONSTANT [13] { value: " world" } } } - CALL [12] { + } + } + CALL [14] { + function: matches + target: { + IDENT [15] { + name: @index0 + } + } + args: { + CALL [16] { function: _+_ args: { - CALL [13] { + CALL [17] { function: _+_ args: { - CALL [14] { + CALL [18] { function: _+_ args: { - CALL [15] { + CALL [19] { function: _+_ args: { - CALL [16] { - function: _+_ - args: { - CONSTANT [17] { value: "h" } - CONSTANT [18] { value: "e" } - } - } - CONSTANT [19] { value: "l" } + CONSTANT [20] { value: "w" } + CONSTANT [21] { value: "o" } } } - CONSTANT [20] { value: "l" } + CONSTANT [22] { value: "r" } } } - CONSTANT [21] { value: "o" } + CONSTANT [23] { value: "l" } } } - CONSTANT [22] { value: " world" } + CONSTANT [24] { value: "d" } } } } } - CALL [23] { - function: matches - target: { - IDENT [24] { - name: @index1 - } - } - args: { - IDENT [25] { - name: @index0 - } - } - } } } Test case: CUSTOM_FUNCTION_INELIMINABLE @@ -3306,74 +3023,66 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload - } - SELECT [7] { - IDENT [8] { - name: @index1 - }.single_int64 - } - SELECT [9] { - IDENT [10] { - name: msg + SELECT [4] { + SELECT [5] { + IDENT [6] { + name: msg + }.oneof_type + }.payload }.single_int64 } - SELECT [11] { - IDENT [12] { - name: @index1 - }.single_int32 - } } } - CALL [13] { + CALL [7] { function: _+_ args: { - CALL [14] { + CALL [8] { function: _+_ args: { - CALL [15] { + CALL [9] { function: _+_ args: { - CALL [16] { + CALL [10] { function: non_pure_custom_func args: { - IDENT [17] { - name: @index2 + IDENT [11] { + name: @index0 } } } - CALL [18] { + CALL [12] { function: non_pure_custom_func args: { - IDENT [19] { - name: @index4 + SELECT [13] { + SELECT [14] { + SELECT [15] { + IDENT [16] { + name: msg + }.oneof_type + }.payload + }.single_int32 } } } } } - CALL [20] { + CALL [17] { function: non_pure_custom_func args: { - IDENT [21] { - name: @index2 + IDENT [18] { + name: @index0 } } } } } - CALL [22] { + CALL [19] { function: non_pure_custom_func args: { - IDENT [23] { - name: @index3 + SELECT [20] { + IDENT [21] { + name: msg + }.single_int64 } } } @@ -3389,75 +3098,67 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload - } - SELECT [7] { - IDENT [8] { - name: @index1 - }.single_int64 - } - CALL [9] { - function: pure_custom_func - args: { - IDENT [10] { - name: @index2 - } - } - } - CALL [11] { + CALL [3] { function: pure_custom_func args: { - SELECT [12] { - IDENT [13] { - name: msg + SELECT [4] { + SELECT [5] { + SELECT [6] { + IDENT [7] { + name: msg + }.oneof_type + }.payload }.single_int64 } } } - CALL [14] { + CALL [8] { function: _+_ args: { - CALL [15] { - function: _+_ + IDENT [9] { + name: @index0 + } + CALL [10] { + function: pure_custom_func args: { - IDENT [16] { - name: @index3 - } - CALL [17] { - function: pure_custom_func - args: { - SELECT [18] { - IDENT [19] { - name: @index1 - }.single_int32 - } - } + SELECT [11] { + SELECT [12] { + SELECT [13] { + IDENT [14] { + name: msg + }.oneof_type + }.payload + }.single_int32 } } } - IDENT [20] { - name: @index3 - } } } } } - CALL [21] { + CALL [15] { function: _+_ args: { - IDENT [22] { - name: @index5 + CALL [16] { + function: _+_ + args: { + IDENT [17] { + name: @index1 + } + IDENT [18] { + name: @index0 + } + } } - IDENT [23] { - name: @index4 + CALL [19] { + function: pure_custom_func + args: { + SELECT [20] { + IDENT [21] { + name: msg + }.single_int64 + } + } } } } diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_6.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_6.baseline index a2ecbc777..107cf04c7 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_6.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_6.baseline @@ -6,20 +6,22 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_LIST [3] { - elements: { - CONSTANT [4] { value: 1 } - CONSTANT [5] { value: 2 } - } - } - CALL [6] { + CALL [3] { function: size args: { - IDENT [7] { - name: @index0 + CREATE_LIST [4] { + elements: { + CONSTANT [5] { value: 1 } + CONSTANT [6] { value: 2 } + } } } } + } + } + CALL [7] { + function: _==_ + args: { CALL [8] { function: _+_ args: { @@ -27,25 +29,17 @@ CALL [1] { function: _+_ args: { IDENT [10] { - name: @index1 + name: @index0 } IDENT [11] { - name: @index1 + name: @index0 } } } CONSTANT [12] { value: 1 } } } - } - } - CALL [13] { - function: _==_ - args: { - IDENT [14] { - name: @index2 - } - CONSTANT [15] { value: 5 } + CONSTANT [13] { value: 5 } } } } @@ -58,20 +52,22 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_LIST [3] { - elements: { - CONSTANT [4] { value: 1 } - CONSTANT [5] { value: 2 } - } - } - CALL [6] { + CALL [3] { function: size args: { - IDENT [7] { - name: @index0 + CREATE_LIST [4] { + elements: { + CONSTANT [5] { value: 1 } + CONSTANT [6] { value: 2 } + } } } } + } + } + CALL [7] { + function: _==_ + args: { CALL [8] { function: _+_ args: { @@ -83,27 +79,19 @@ CALL [1] { args: { CONSTANT [11] { value: 2 } IDENT [12] { - name: @index1 + name: @index0 } } } IDENT [13] { - name: @index1 + name: @index0 } } } CONSTANT [14] { value: 1 } } } - } - } - CALL [15] { - function: _==_ - args: { - IDENT [16] { - name: @index2 - } - CONSTANT [17] { value: 7 } + CONSTANT [15] { value: 7 } } } } @@ -116,69 +104,60 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_LIST [3] { - elements: { - CONSTANT [4] { value: 0 } - } - } - CALL [5] { + CALL [3] { function: size args: { - IDENT [6] { - name: @index0 + CREATE_LIST [4] { + elements: { + CONSTANT [5] { value: 0 } + } } } } - CREATE_LIST [7] { - elements: { - CONSTANT [8] { value: 1 } - CONSTANT [9] { value: 2 } - } - } - CALL [10] { + CALL [6] { function: size args: { - IDENT [11] { - name: @index2 + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 1 } + CONSTANT [9] { value: 2 } + } } } } - CALL [12] { + } + } + CALL [10] { + function: _==_ + args: { + CALL [11] { function: _+_ args: { - CALL [13] { + CALL [12] { function: _+_ args: { - CALL [14] { + CALL [13] { function: _+_ args: { - IDENT [15] { - name: @index1 + IDENT [14] { + name: @index0 } - IDENT [16] { - name: @index1 + IDENT [15] { + name: @index0 } } } - IDENT [17] { - name: @index3 + IDENT [16] { + name: @index1 } } } - IDENT [18] { - name: @index3 + IDENT [17] { + name: @index1 } } } - } - } - CALL [19] { - function: _==_ - args: { - IDENT [20] { - name: @index4 - } - CONSTANT [21] { value: 6 } + CONSTANT [18] { value: 6 } } } } @@ -191,106 +170,97 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_LIST [3] { - elements: { - CONSTANT [4] { value: 0 } - } - } - CALL [5] { + CALL [3] { function: size args: { - IDENT [6] { - name: @index0 + CREATE_LIST [4] { + elements: { + CONSTANT [5] { value: 0 } + } } } } - CREATE_LIST [7] { - elements: { - CONSTANT [8] { value: 1 } - CONSTANT [9] { value: 2 } - } - } - CALL [10] { + CALL [6] { function: size args: { - IDENT [11] { - name: @index2 + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 1 } + CONSTANT [9] { value: 2 } + } } } } - CREATE_LIST [12] { - elements: { - CONSTANT [13] { value: 1 } - CONSTANT [14] { value: 2 } - CONSTANT [15] { value: 3 } - } - } - CALL [16] { + CALL [10] { function: size args: { - IDENT [17] { - name: @index4 + CREATE_LIST [11] { + elements: { + CONSTANT [12] { value: 1 } + CONSTANT [13] { value: 2 } + CONSTANT [14] { value: 3 } + } } } } - CALL [18] { + CALL [15] { function: _+_ args: { - CALL [19] { + CALL [16] { function: _+_ args: { - CALL [20] { + CALL [17] { function: _+_ args: { - CALL [21] { + CALL [18] { function: _+_ args: { - CALL [22] { + CALL [19] { function: _+_ args: { - CALL [23] { + CALL [20] { function: _+_ args: { - CONSTANT [24] { value: 5 } - IDENT [25] { - name: @index1 + CONSTANT [21] { value: 5 } + IDENT [22] { + name: @index0 } } } - IDENT [26] { - name: @index1 + IDENT [23] { + name: @index0 } } } - IDENT [27] { - name: @index3 + IDENT [24] { + name: @index1 } } } - IDENT [28] { - name: @index3 + IDENT [25] { + name: @index1 } } } - IDENT [29] { - name: @index5 + IDENT [26] { + name: @index2 } } } - IDENT [30] { - name: @index5 + IDENT [27] { + name: @index2 } } } } } - CALL [31] { + CALL [28] { function: _==_ args: { - IDENT [32] { - name: @index6 + IDENT [29] { + name: @index3 } - CONSTANT [33] { value: 17 } + CONSTANT [30] { value: 17 } } } } @@ -304,146 +274,106 @@ CALL [1] { CREATE_LIST [2] { elements: { CALL [3] { - function: timestamp - args: { - CONSTANT [4] { value: 1000000000 } - } - } - CALL [5] { - function: int - args: { - IDENT [6] { - name: @index0 + function: getFullYear + target: { + CALL [4] { + function: timestamp + args: { + CALL [5] { + function: int + args: { + CALL [6] { + function: timestamp + args: { + CONSTANT [7] { value: 1000000000 } + } + } + } + } + } } } - } - CALL [7] { - function: timestamp args: { - IDENT [8] { - name: @index1 - } } } - CALL [9] { + CALL [8] { function: getFullYear target: { - IDENT [10] { - name: @index2 + CALL [9] { + function: timestamp + args: { + CALL [10] { + function: int + args: { + CALL [11] { + function: timestamp + args: { + CONSTANT [12] { value: 200 } + } + } + } + } + } } } args: { } } - CALL [11] { - function: timestamp - args: { - CONSTANT [12] { value: 50 } - } - } CALL [13] { - function: int - args: { - IDENT [14] { - name: @index4 - } - } - } - CALL [15] { function: timestamp args: { - IDENT [16] { - name: @index5 + CALL [14] { + function: int + args: { + CALL [15] { + function: timestamp + args: { + CONSTANT [16] { value: 50 } + } + } + } } } } CALL [17] { function: timestamp args: { - CONSTANT [18] { value: 200 } - } - } - CALL [19] { - function: int - args: { - IDENT [20] { - name: @index7 + CALL [18] { + function: int + args: { + CALL [19] { + function: timestamp + args: { + CONSTANT [20] { value: 75 } + } + } + } } } } CALL [21] { - function: timestamp - args: { - IDENT [22] { - name: @index8 - } - } - } - CALL [23] { - function: getFullYear - target: { - IDENT [24] { - name: @index9 - } - } - args: { - } - } - CALL [25] { - function: timestamp - args: { - CONSTANT [26] { value: 75 } - } - } - CALL [27] { - function: int - args: { - IDENT [28] { - name: @index11 - } - } - } - CALL [29] { - function: timestamp - args: { - IDENT [30] { - name: @index12 - } - } - } - CALL [31] { - function: getMinutes - target: { - IDENT [32] { - name: @index13 - } - } - args: { - } - } - CALL [33] { function: _+_ args: { - CALL [34] { + CALL [22] { function: _+_ args: { - CALL [35] { + CALL [23] { function: _+_ args: { - CALL [36] { + CALL [24] { function: _+_ args: { - CALL [37] { + CALL [25] { function: _+_ args: { - IDENT [38] { - name: @index3 + IDENT [26] { + name: @index0 } - CALL [39] { + CALL [27] { function: getFullYear target: { - IDENT [40] { - name: @index13 + IDENT [28] { + name: @index3 } } args: { @@ -451,11 +381,11 @@ CALL [1] { } } } - CALL [41] { + CALL [29] { function: getFullYear target: { - IDENT [42] { - name: @index6 + IDENT [30] { + name: @index2 } } args: { @@ -463,16 +393,16 @@ CALL [1] { } } } - IDENT [43] { - name: @index3 + IDENT [31] { + name: @index0 } } } - CALL [44] { + CALL [32] { function: getSeconds target: { - IDENT [45] { - name: @index6 + IDENT [33] { + name: @index2 } } args: { @@ -480,47 +410,51 @@ CALL [1] { } } } - IDENT [46] { - name: @index10 - } + IDENT [34] { + name: @index1 + } } } - CALL [47] { + } + } + CALL [35] { + function: _==_ + args: { + CALL [36] { function: _+_ args: { - CALL [48] { + CALL [37] { function: _+_ args: { - CALL [49] { + CALL [38] { function: _+_ args: { - IDENT [50] { - name: @index15 + IDENT [39] { + name: @index4 } - IDENT [51] { - name: @index10 + IDENT [40] { + name: @index1 } } } - IDENT [52] { - name: @index14 + CALL [41] { + function: getMinutes + target: { + IDENT [42] { + name: @index3 + } + } + args: { + } } } } - IDENT [53] { - name: @index3 + IDENT [43] { + name: @index0 } } } - } - } - CALL [54] { - function: _==_ - args: { - IDENT [55] { - name: @index16 - } - CONSTANT [56] { value: 13934 } + CONSTANT [44] { value: 13934 } } } } @@ -533,53 +467,47 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_MAP [3] { - MAP_ENTRY [4] { - key: { - CONSTANT [5] { value: "a" } - } - value: { - CONSTANT [6] { value: 2 } - } - } - } - CALL [7] { + CALL [3] { function: _[_] args: { - IDENT [8] { - name: @index0 + CREATE_MAP [4] { + MAP_ENTRY [5] { + key: { + CONSTANT [6] { value: "a" } + } + value: { + CONSTANT [7] { value: 2 } + } + } } - CONSTANT [9] { value: "a" } + CONSTANT [8] { value: "a" } } } + } + } + CALL [9] { + function: _==_ + args: { CALL [10] { function: _+_ args: { IDENT [11] { - name: @index1 + name: @index0 } CALL [12] { function: _*_ args: { IDENT [13] { - name: @index1 + name: @index0 } IDENT [14] { - name: @index1 + name: @index0 } } } } } - } - } - CALL [15] { - function: _==_ - args: { - IDENT [16] { - name: @index2 - } - CONSTANT [17] { value: 6 } + CONSTANT [15] { value: 6 } } } } @@ -595,51 +523,48 @@ CALL [1] { CREATE_MAP [3] { MAP_ENTRY [4] { key: { - CONSTANT [5] { value: "b" } + CONSTANT [5] { value: "e" } } value: { - CONSTANT [6] { value: 1 } + CREATE_MAP [6] { + MAP_ENTRY [7] { + key: { + CONSTANT [8] { value: "b" } + } + value: { + CONSTANT [9] { value: 1 } + } + } + } } } } - CREATE_MAP [7] { - MAP_ENTRY [8] { + CREATE_MAP [10] { + MAP_ENTRY [11] { key: { - CONSTANT [9] { value: "e" } + CONSTANT [12] { value: "b" } } value: { - IDENT [10] { - name: @index0 - } + CONSTANT [13] { value: 1 } } } } } } - CREATE_MAP [11] { - MAP_ENTRY [12] { - key: { - CONSTANT [13] { value: "a" } - } - value: { - IDENT [14] { - name: @index0 - } - } - } + CREATE_MAP [14] { MAP_ENTRY [15] { key: { - CONSTANT [16] { value: "c" } + CONSTANT [16] { value: "a" } } value: { IDENT [17] { - name: @index0 + name: @index1 } } } MAP_ENTRY [18] { key: { - CONSTANT [19] { value: "d" } + CONSTANT [19] { value: "c" } } value: { IDENT [20] { @@ -649,11 +574,21 @@ CALL [1] { } MAP_ENTRY [21] { key: { - CONSTANT [22] { value: "e" } + CONSTANT [22] { value: "d" } } value: { IDENT [23] { - name: @index1 + name: @index0 + } + } + } + MAP_ENTRY [24] { + key: { + CONSTANT [25] { value: "e" } + } + value: { + IDENT [26] { + name: @index0 } } } @@ -682,37 +617,34 @@ CALL [1] { CONSTANT [10] { value: 2 } } } - CREATE_LIST [11] { - elements: { - IDENT [12] { - name: @index1 - } - IDENT [13] { - name: @index0 - } - } - } } } - CREATE_LIST [14] { + CREATE_LIST [11] { elements: { - CONSTANT [15] { value: 1 } - IDENT [16] { + CONSTANT [12] { value: 1 } + IDENT [13] { name: @index0 } - CONSTANT [17] { value: 2 } - IDENT [18] { + CONSTANT [14] { value: 2 } + IDENT [15] { name: @index0 } - CONSTANT [19] { value: 5 } - IDENT [20] { + CONSTANT [16] { value: 5 } + IDENT [17] { name: @index0 } - CONSTANT [21] { value: 7 } - IDENT [22] { - name: @index2 + CONSTANT [18] { value: 7 } + CREATE_LIST [19] { + elements: { + IDENT [20] { + name: @index1 + } + IDENT [21] { + name: @index0 + } + } } - IDENT [23] { + IDENT [22] { name: @index1 } } @@ -732,26 +664,23 @@ CALL [1] { name: msg }.single_int64 } - CALL [5] { + } + } + CALL [5] { + function: _==_ + args: { + CALL [6] { function: _+_ args: { - IDENT [6] { + IDENT [7] { name: @index0 } - IDENT [7] { + IDENT [8] { name: @index0 } } } - } - } - CALL [8] { - function: _==_ - args: { - IDENT [9] { - name: @index1 - } - CONSTANT [10] { value: 6 } + CONSTANT [9] { value: 6 } } } } @@ -765,58 +694,64 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload + SELECT [4] { + SELECT [5] { + IDENT [6] { + name: msg + }.oneof_type + }.payload + }.single_int64 } SELECT [7] { - IDENT [8] { - name: @index1 - }.single_int64 + SELECT [8] { + IDENT [9] { + name: msg + }.oneof_type + }.payload } - CALL [9] { + } + } + CALL [10] { + function: _==_ + args: { + CALL [11] { function: _+_ args: { - CALL [10] { + CALL [12] { function: _+_ args: { - CALL [11] { + CALL [13] { function: _+_ args: { - CALL [12] { + CALL [14] { function: _+_ args: { - IDENT [13] { - name: @index2 + IDENT [15] { + name: @index0 } - SELECT [14] { - IDENT [15] { + SELECT [16] { + IDENT [17] { name: @index1 }.single_int32 } } } - IDENT [16] { - name: @index2 + IDENT [18] { + name: @index0 } } } - SELECT [17] { - IDENT [18] { + SELECT [19] { + IDENT [20] { name: msg }.single_int64 } } } - SELECT [19] { - SELECT [20] { - SELECT [21] { - IDENT [22] { + SELECT [21] { + SELECT [22] { + SELECT [23] { + IDENT [24] { name: @index1 }.oneof_type }.payload @@ -824,14 +759,6 @@ CALL [1] { } } } - } - } - CALL [23] { - function: _==_ - args: { - IDENT [24] { - name: @index3 - } CONSTANT [25] { value: 31 } } } @@ -846,51 +773,33 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload - } - SELECT [7] { - IDENT [8] { - name: @index1 - }.oneof_type - } - SELECT [9] { - IDENT [10] { - name: @index2 - }.payload - } - SELECT [11] { - IDENT [12] { - name: @index3 - }.oneof_type - } - SELECT [13] { - SELECT [14] { - SELECT [15] { - SELECT [16] { - IDENT [17] { - name: @index4 - }.child - }.child + SELECT [4] { + SELECT [5] { + SELECT [6] { + SELECT [7] { + IDENT [8] { + name: msg + }.oneof_type + }.payload + }.oneof_type }.payload - }.single_bool + }.oneof_type } - CALL [18] { + } + } + CALL [9] { + function: _||_ + args: { + CALL [10] { function: _||_ args: { - CONSTANT [19] { value: true } - SELECT [20] { - SELECT [21] { - SELECT [22] { - SELECT [23] { - IDENT [24] { - name: @index4 + CONSTANT [11] { value: true } + SELECT [12] { + SELECT [13] { + SELECT [14] { + SELECT [15] { + IDENT [16] { + name: @index0 }.payload }.oneof_type }.payload @@ -898,16 +807,16 @@ CALL [1] { } } } - } - } - CALL [25] { - function: _||_ - args: { - IDENT [26] { - name: @index6 - } - IDENT [27] { - name: @index5 + SELECT [17] { + SELECT [18] { + SELECT [19] { + SELECT [20] { + IDENT [21] { + name: @index0 + }.child + }.child + }.payload + }.single_bool } } } @@ -921,58 +830,46 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload - } - SELECT [7] { - IDENT [8] { - name: @index1 - }.map_int32_int64 - } - CALL [9] { + CALL [3] { function: _[_] args: { - IDENT [10] { - name: @index2 + SELECT [4] { + SELECT [5] { + SELECT [6] { + IDENT [7] { + name: msg + }.oneof_type + }.payload + }.map_int32_int64 } - CONSTANT [11] { value: 1 } + CONSTANT [8] { value: 1 } } } - CALL [12] { + } + } + CALL [9] { + function: _==_ + args: { + CALL [10] { function: _+_ args: { - CALL [13] { + CALL [11] { function: _+_ args: { - IDENT [14] { - name: @index3 + IDENT [12] { + name: @index0 } - IDENT [15] { - name: @index3 + IDENT [13] { + name: @index0 } } } - IDENT [16] { - name: @index3 + IDENT [14] { + name: @index0 } } } - } - } - CALL [17] { - function: _==_ - args: { - IDENT [18] { - name: @index4 - } - CONSTANT [19] { value: 15 } + CONSTANT [15] { value: 15 } } } } @@ -986,66 +883,57 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload - } - SELECT [7] { - IDENT [8] { - name: @index1 + SELECT [4] { + SELECT [5] { + IDENT [6] { + name: msg + }.oneof_type + }.payload }.map_int32_int64 } - CALL [9] { + } + } + CALL [7] { + function: _==_ + args: { + CALL [8] { function: _+_ args: { - CALL [10] { + CALL [9] { function: _+_ args: { - CALL [11] { + CALL [10] { function: _[_] args: { - IDENT [12] { - name: @index2 + IDENT [11] { + name: @index0 } - CONSTANT [13] { value: 0 } + CONSTANT [12] { value: 0 } } } - CALL [14] { + CALL [13] { function: _[_] args: { - IDENT [15] { - name: @index2 + IDENT [14] { + name: @index0 } - CONSTANT [16] { value: 1 } + CONSTANT [15] { value: 1 } } } } } - CALL [17] { + CALL [16] { function: _[_] args: { - IDENT [18] { - name: @index2 + IDENT [17] { + name: @index0 } - CONSTANT [19] { value: 2 } + CONSTANT [18] { value: 2 } } } } } - } - } - CALL [20] { - function: _==_ - args: { - IDENT [21] { - name: @index3 - } - CONSTANT [22] { value: 8 } + CONSTANT [19] { value: 8 } } } } @@ -1073,18 +961,15 @@ CALL [1] { }.oneof_type }.payload } - SELECT [10] { - SELECT [11] { - IDENT [12] { - name: @index0 - }.oneof_type - }.payload - } } } - SELECT [13] { - IDENT [14] { - name: @index1 + SELECT [10] { + SELECT [11] { + SELECT [12] { + IDENT [13] { + name: @index0 + }.oneof_type + }.payload }.single_int64 } } @@ -1102,33 +987,30 @@ CALL [1] { name: msg }.single_int64 } - CALL [5] { + } + } + CALL [5] { + function: _==_ + args: { + CALL [6] { function: _?_:_ args: { - CALL [6] { + CALL [7] { function: _>_ args: { - IDENT [7] { + IDENT [8] { name: @index0 } - CONSTANT [8] { value: 0 } + CONSTANT [9] { value: 0 } } } - IDENT [9] { + IDENT [10] { name: @index0 } - CONSTANT [10] { value: 0 } + CONSTANT [11] { value: 0 } } } - } - } - CALL [11] { - function: _==_ - args: { - IDENT [12] { - name: @index1 - } - CONSTANT [13] { value: 3 } + CONSTANT [12] { value: 3 } } } } @@ -1146,47 +1028,44 @@ CALL [1] { name: msg }.single_int64 } - CALL [5] { + } + } + CALL [5] { + function: _?_:_ + args: { + CONSTANT [6] { value: false } + CONSTANT [7] { value: false } + CALL [8] { function: _==_ args: { - CALL [6] { + CALL [9] { function: _+_ args: { - IDENT [7] { + IDENT [10] { name: @index0 } - CALL [8] { + CALL [11] { function: _*_ args: { - CALL [9] { + CALL [12] { function: _+_ args: { - IDENT [10] { + IDENT [13] { name: @index0 } - CONSTANT [11] { value: 1 } + CONSTANT [14] { value: 1 } } } - CONSTANT [12] { value: 2 } + CONSTANT [15] { value: 2 } } } } } - CONSTANT [13] { value: 11 } + CONSTANT [16] { value: 11 } } } } } - CALL [14] { - function: _?_:_ - args: { - CONSTANT [15] { value: false } - CONSTANT [16] { value: false } - IDENT [17] { - name: @index1 - } - } - } } } Test case: NESTED_TERNARY @@ -1207,56 +1086,53 @@ CALL [1] { name: msg }.single_int32 } - CALL [7] { + } + } + CALL [7] { + function: _==_ + args: { + CALL [8] { function: _?_:_ args: { - CALL [8] { + CALL [9] { function: _>_ args: { - IDENT [9] { + IDENT [10] { name: @index0 } - CONSTANT [10] { value: 0 } + CONSTANT [11] { value: 0 } } } - CALL [11] { + CALL [12] { function: _?_:_ args: { - CALL [12] { + CALL [13] { function: _>_ args: { - IDENT [13] { + IDENT [14] { name: @index1 } - CONSTANT [14] { value: 0 } + CONSTANT [15] { value: 0 } } } - CALL [15] { + CALL [16] { function: _+_ args: { - IDENT [16] { + IDENT [17] { name: @index0 } - IDENT [17] { + IDENT [18] { name: @index1 } } } - CONSTANT [18] { value: 0 } + CONSTANT [19] { value: 0 } } } - CONSTANT [19] { value: 0 } + CONSTANT [20] { value: 0 } } } - } - } - CALL [20] { - function: _==_ - args: { - IDENT [21] { - name: @index2 - } - CONSTANT [22] { value: 8 } + CONSTANT [21] { value: 8 } } } } @@ -1269,196 +1145,163 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_LIST [3] { - elements: { - CONSTANT [4] { value: 1 } - } - } - CALL [5] { - function: _>_ + CALL [3] { + function: size args: { - IDENT [6] { - name: @c0:0 + CREATE_LIST [4] { + elements: { + COMPREHENSION [5] { + iter_var: @c0:0 + iter_range: { + CREATE_LIST [6] { + elements: { + CONSTANT [7] { value: 1 } + } + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [8] { value: false } + } + loop_condition: { + CALL [9] { + function: @not_strictly_false + args: { + CALL [10] { + function: !_ + args: { + IDENT [11] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + CALL [12] { + function: _||_ + args: { + IDENT [13] { + name: @x0:0 + } + CALL [14] { + function: _>_ + args: { + IDENT [15] { + name: @c0:0 + } + CONSTANT [16] { value: 0 } + } + } + } + } + } + result: { + IDENT [17] { + name: @x0:0 + } + } + } + } } - CONSTANT [7] { value: 0 } } } - CALL [8] { - function: _||_ + CALL [18] { + function: size args: { - IDENT [9] { - name: @x0:0 - } - IDENT [10] { - name: @index1 + CREATE_LIST [19] { + elements: { + COMPREHENSION [20] { + iter_var: @c0:0 + iter_range: { + CREATE_LIST [21] { + elements: { + CONSTANT [22] { value: 2 } + } + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [23] { value: false } + } + loop_condition: { + CALL [24] { + function: @not_strictly_false + args: { + CALL [25] { + function: !_ + args: { + IDENT [26] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + CALL [27] { + function: _||_ + args: { + IDENT [28] { + name: @x0:0 + } + CALL [29] { + function: _>_ + args: { + IDENT [30] { + name: @c0:0 + } + CONSTANT [31] { value: 1 } + } + } + } + } + } + result: { + IDENT [32] { + name: @x0:0 + } + } + } + } } } } - COMPREHENSION [11] { - iter_var: @c0:0 - iter_range: { - IDENT [12] { - name: @index0 - } - } - accu_var: @x0:0 - accu_init: { - CONSTANT [13] { value: false } - } - loop_condition: { - CALL [14] { - function: @not_strictly_false + } + } + CALL [33] { + function: _==_ + args: { + CALL [34] { + function: _+_ + args: { + CALL [35] { + function: _+_ args: { - CALL [15] { - function: !_ + CALL [36] { + function: _+_ args: { - IDENT [16] { - name: @x0:0 + IDENT [37] { + name: @index0 + } + IDENT [38] { + name: @index0 } } } + IDENT [39] { + name: @index1 + } } } - } - loop_step: { - IDENT [17] { - name: @index2 - } - } - result: { - IDENT [18] { - name: @x0:0 - } - } - } - CREATE_LIST [19] { - elements: { - IDENT [20] { - name: @index3 - } - } - } - CALL [21] { - function: size - args: { - IDENT [22] { - name: @index4 - } - } - } - CREATE_LIST [23] { - elements: { - CONSTANT [24] { value: 2 } - } - } - CALL [25] { - function: _>_ - args: { - IDENT [26] { - name: @c0:0 - } - CONSTANT [27] { value: 1 } - } - } - CALL [28] { - function: _||_ - args: { - IDENT [29] { - name: @x0:0 - } - IDENT [30] { - name: @index7 - } - } - } - COMPREHENSION [31] { - iter_var: @c0:0 - iter_range: { - IDENT [32] { - name: @index6 - } - } - accu_var: @x0:0 - accu_init: { - CONSTANT [33] { value: false } - } - loop_condition: { - CALL [34] { - function: @not_strictly_false - args: { - CALL [35] { - function: !_ - args: { - IDENT [36] { - name: @x0:0 - } - } - } - } - } - } - loop_step: { - IDENT [37] { - name: @index8 - } - } - result: { - IDENT [38] { - name: @x0:0 - } - } - } - CREATE_LIST [39] { - elements: { - IDENT [40] { - name: @index9 - } - } - } - CALL [41] { - function: size - args: { - IDENT [42] { - name: @index10 - } - } - } - CALL [43] { - function: _+_ - args: { - CALL [44] { - function: _+_ - args: { - CALL [45] { - function: _+_ - args: { - IDENT [46] { - name: @index5 - } - IDENT [47] { - name: @index5 - } - } - } - IDENT [48] { - name: @index11 - } - } - } - IDENT [49] { - name: @index11 + IDENT [40] { + name: @index1 } } } - } - } - CALL [50] { - function: _==_ - args: { - IDENT [51] { - name: @index12 - } - CONSTANT [52] { value: 4 } + CONSTANT [41] { value: 4 } } } } @@ -1473,187 +1316,157 @@ CALL [1] { elements: { CREATE_LIST [3] { elements: { - CONSTANT [4] { value: 1 } - } - } - CALL [5] { - function: _>_ - args: { - IDENT [6] { - name: @c0:0 - } - CONSTANT [7] { value: 0 } - } - } - CALL [8] { - function: _||_ - args: { - IDENT [9] { - name: @x0:0 - } - IDENT [10] { - name: @index1 - } - } - } - COMPREHENSION [11] { - iter_var: @c0:0 - iter_range: { - IDENT [12] { - name: @index0 - } - } - accu_var: @x0:0 - accu_init: { - CONSTANT [13] { value: false } - } - loop_condition: { - CALL [14] { - function: @not_strictly_false - args: { - CALL [15] { - function: !_ + COMPREHENSION [4] { + iter_var: @c0:0 + iter_range: { + CREATE_LIST [5] { + elements: { + CONSTANT [6] { value: 1 } + } + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [7] { value: false } + } + loop_condition: { + CALL [8] { + function: @not_strictly_false args: { - IDENT [16] { + CALL [9] { + function: !_ + args: { + IDENT [10] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + CALL [11] { + function: _||_ + args: { + IDENT [12] { name: @x0:0 } + CALL [13] { + function: _>_ + args: { + IDENT [14] { + name: @c0:0 + } + CONSTANT [15] { value: 0 } + } + } } } } - } - } - loop_step: { - IDENT [17] { - name: @index2 - } - } - result: { - IDENT [18] { - name: @x0:0 - } - } - } - CREATE_LIST [19] { - elements: { - IDENT [20] { - name: @index3 + result: { + IDENT [16] { + name: @x0:0 + } + } } } } - CREATE_LIST [21] { + CREATE_LIST [17] { elements: { - CONSTANT [22] { value: "a" } - } - } - CALL [23] { - function: _==_ - args: { - IDENT [24] { - name: @c0:1 - } - CONSTANT [25] { value: "a" } - } - } - CALL [26] { - function: _||_ - args: { - IDENT [27] { - name: @x0:1 - } - IDENT [28] { - name: @index6 - } - } - } - COMPREHENSION [29] { - iter_var: @c0:1 - iter_range: { - IDENT [30] { - name: @index5 - } - } - accu_var: @x0:1 - accu_init: { - CONSTANT [31] { value: false } - } - loop_condition: { - CALL [32] { - function: @not_strictly_false - args: { - CALL [33] { - function: !_ + COMPREHENSION [18] { + iter_var: @c0:1 + iter_range: { + CREATE_LIST [19] { + elements: { + CONSTANT [20] { value: "a" } + } + } + } + accu_var: @x0:1 + accu_init: { + CONSTANT [21] { value: false } + } + loop_condition: { + CALL [22] { + function: @not_strictly_false + args: { + CALL [23] { + function: !_ + args: { + IDENT [24] { + name: @x0:1 + } + } + } + } + } + } + loop_step: { + CALL [25] { + function: _||_ args: { - IDENT [34] { + IDENT [26] { name: @x0:1 } + CALL [27] { + function: _==_ + args: { + IDENT [28] { + name: @c0:1 + } + CONSTANT [29] { value: "a" } + } + } } } } + result: { + IDENT [30] { + name: @x0:1 + } + } } } - loop_step: { - IDENT [35] { - name: @index7 - } - } - result: { - IDENT [36] { - name: @x0:1 - } - } - } - CREATE_LIST [37] { - elements: { - IDENT [38] { - name: @index8 - } - } - } - CREATE_LIST [39] { - elements: { - CONSTANT [40] { value: true } - CONSTANT [41] { value: true } - CONSTANT [42] { value: true } - CONSTANT [43] { value: true } - } } - CALL [44] { + } + } + CALL [31] { + function: _==_ + args: { + CALL [32] { function: _+_ args: { - CALL [45] { + CALL [33] { function: _+_ args: { - CALL [46] { + CALL [34] { function: _+_ args: { - IDENT [47] { - name: @index4 + IDENT [35] { + name: @index0 } - IDENT [48] { - name: @index4 + IDENT [36] { + name: @index0 } } } - IDENT [49] { - name: @index9 + IDENT [37] { + name: @index1 } } } - IDENT [50] { - name: @index9 + IDENT [38] { + name: @index1 } } } - } - } - CALL [51] { - function: _==_ - args: { - IDENT [52] { - name: @index11 - } - IDENT [53] { - name: @index10 + CREATE_LIST [39] { + elements: { + CONSTANT [40] { value: true } + CONSTANT [41] { value: true } + CONSTANT [42] { value: true } + CONSTANT [43] { value: true } + } } } } @@ -1681,60 +1494,47 @@ CALL [1] { CONSTANT [10] { value: 4 } } } - CREATE_LIST [11] { - elements: { - IDENT [12] { - name: @index1 - } - IDENT [13] { - name: @index1 - } - IDENT [14] { - name: @index1 - } - } - } - CALL [15] { + CALL [11] { function: _+_ args: { - IDENT [16] { + IDENT [12] { name: @x0:0 } - CREATE_LIST [17] { + CREATE_LIST [13] { elements: { - COMPREHENSION [18] { + COMPREHENSION [14] { iter_var: @c1:0 iter_range: { - IDENT [19] { + IDENT [15] { name: @index0 } } accu_var: @x1:0 accu_init: { - CREATE_LIST [20] { + CREATE_LIST [16] { elements: { } } } loop_condition: { - CONSTANT [21] { value: true } + CONSTANT [17] { value: true } } loop_step: { - CALL [22] { + CALL [18] { function: _+_ args: { - IDENT [23] { + IDENT [19] { name: @x1:0 } - CREATE_LIST [24] { + CREATE_LIST [20] { elements: { - CALL [25] { + CALL [21] { function: _+_ args: { - IDENT [26] { + IDENT [22] { name: @c1:0 } - CONSTANT [27] { value: 1 } + CONSTANT [23] { value: 1 } } } } @@ -1743,7 +1543,7 @@ CALL [1] { } } result: { - IDENT [28] { + IDENT [24] { name: @x1:0 } } @@ -1752,44 +1552,51 @@ CALL [1] { } } } - COMPREHENSION [29] { + } + } + CALL [25] { + function: _==_ + args: { + COMPREHENSION [26] { iter_var: @c0:0 iter_range: { - IDENT [30] { + IDENT [27] { name: @index0 } } accu_var: @x0:0 accu_init: { - CREATE_LIST [31] { + CREATE_LIST [28] { elements: { } } } loop_condition: { - CONSTANT [32] { value: true } + CONSTANT [29] { value: true } } loop_step: { - IDENT [33] { - name: @index3 + IDENT [30] { + name: @index2 } } result: { - IDENT [34] { + IDENT [31] { name: @x0:0 } } } - } - } - CALL [35] { - function: _==_ - args: { - IDENT [36] { - name: @index4 - } - IDENT [37] { - name: @index2 + CREATE_LIST [32] { + elements: { + IDENT [33] { + name: @index1 + } + IDENT [34] { + name: @index1 + } + IDENT [35] { + name: @index1 + } + } } } } @@ -1803,87 +1610,73 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_LIST [3] { - elements: { - CREATE_LIST [4] { - elements: { - CONSTANT [5] { value: 1 } - } - } - CREATE_LIST [6] { - elements: { - CONSTANT [7] { value: 2 } - } - } - } - } - CALL [8] { + CALL [3] { function: _+_ args: { - IDENT [9] { + IDENT [4] { name: @x0:0 } - CREATE_LIST [10] { + CREATE_LIST [5] { elements: { - COMPREHENSION [11] { + COMPREHENSION [6] { iter_var: @c1:0 iter_range: { - CREATE_LIST [12] { + CREATE_LIST [7] { elements: { - CONSTANT [13] { value: 1 } - CONSTANT [14] { value: 2 } - CONSTANT [15] { value: 3 } + CONSTANT [8] { value: 1 } + CONSTANT [9] { value: 2 } + CONSTANT [10] { value: 3 } } } } accu_var: @x1:0 accu_init: { - CREATE_LIST [16] { + CREATE_LIST [11] { elements: { } } } loop_condition: { - CONSTANT [17] { value: true } + CONSTANT [12] { value: true } } loop_step: { - CALL [18] { + CALL [13] { function: _?_:_ args: { - CALL [19] { + CALL [14] { function: _==_ args: { - IDENT [20] { + IDENT [15] { name: @c1:0 } - IDENT [21] { + IDENT [16] { name: @c0:0 } } } - CALL [22] { + CALL [17] { function: _+_ args: { - IDENT [23] { + IDENT [18] { name: @x1:0 } - CREATE_LIST [24] { + CREATE_LIST [19] { elements: { - IDENT [25] { + IDENT [20] { name: @c1:0 } } } } } - IDENT [26] { + IDENT [21] { name: @x1:0 } } } } result: { - IDENT [27] { + IDENT [22] { name: @x1:0 } } @@ -1892,47 +1685,55 @@ CALL [1] { } } } - COMPREHENSION [28] { + } + } + CALL [23] { + function: _==_ + args: { + COMPREHENSION [24] { iter_var: @c0:0 iter_range: { - CREATE_LIST [29] { + CREATE_LIST [25] { elements: { - CONSTANT [30] { value: 1 } - CONSTANT [31] { value: 2 } + CONSTANT [26] { value: 1 } + CONSTANT [27] { value: 2 } } } } accu_var: @x0:0 accu_init: { - CREATE_LIST [32] { + CREATE_LIST [28] { elements: { } } } loop_condition: { - CONSTANT [33] { value: true } + CONSTANT [29] { value: true } } loop_step: { - IDENT [34] { - name: @index1 + IDENT [30] { + name: @index0 } } result: { - IDENT [35] { + IDENT [31] { name: @x0:0 } } } - } - } - CALL [36] { - function: _==_ - args: { - IDENT [37] { - name: @index2 - } - IDENT [38] { - name: @index0 + CREATE_LIST [32] { + elements: { + CREATE_LIST [33] { + elements: { + CONSTANT [34] { value: 1 } + } + } + CREATE_LIST [35] { + elements: { + CONSTANT [36] { value: 2 } + } + } + } } } } @@ -1946,74 +1747,72 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_LIST [3] { - elements: { - CONSTANT [4] { value: 1 } - CONSTANT [5] { value: 2 } - CONSTANT [6] { value: 3 } - } - } - CALL [7] { + CALL [3] { function: @in args: { - CONSTANT [8] { value: 1 } - IDENT [9] { - name: @index0 + CONSTANT [4] { value: 1 } + CREATE_LIST [5] { + elements: { + CONSTANT [6] { value: 1 } + CONSTANT [7] { value: 2 } + CONSTANT [8] { value: 3 } + } } } } - CALL [10] { + CREATE_LIST [9] { + elements: { + CONSTANT [10] { value: 1 } + CONSTANT [11] { value: 2 } + CONSTANT [12] { value: 3 } + } + } + } + } + CALL [13] { + function: _&&_ + args: { + CALL [14] { function: _&&_ args: { - CALL [11] { + IDENT [15] { + name: @index0 + } + CALL [16] { function: @in args: { - CONSTANT [12] { value: 3 } - CREATE_LIST [13] { - elements: { - CONSTANT [14] { value: 3 } - IDENT [15] { - name: @index0 - } - } + CONSTANT [17] { value: 2 } + IDENT [18] { + name: @index1 } } } - IDENT [16] { - name: @index1 - } } } - CALL [17] { + CALL [19] { function: _&&_ args: { - IDENT [18] { - name: @index1 - } - CALL [19] { + CALL [20] { function: @in args: { - CONSTANT [20] { value: 2 } - IDENT [21] { - name: @index0 + CONSTANT [21] { value: 3 } + CREATE_LIST [22] { + elements: { + CONSTANT [23] { value: 3 } + IDENT [24] { + name: @index1 + } + } } } } + IDENT [25] { + name: @index0 + } } } } } - CALL [22] { - function: _&&_ - args: { - IDENT [23] { - name: @index3 - } - IDENT [24] { - name: @index2 - } - } - } } } Test case: INCLUSION_MAP @@ -2034,31 +1833,37 @@ CALL [1] { } } } - CREATE_MAP [7] { - MAP_ENTRY [8] { + } + } + CALL [7] { + function: @in + args: { + CONSTANT [8] { value: 2 } + CREATE_MAP [9] { + MAP_ENTRY [10] { key: { - CONSTANT [9] { value: "a" } + CONSTANT [11] { value: "a" } } value: { - CONSTANT [10] { value: 1 } + CONSTANT [12] { value: 1 } } } - MAP_ENTRY [11] { + MAP_ENTRY [13] { key: { - CONSTANT [12] { value: 2 } + CONSTANT [14] { value: 2 } } value: { - IDENT [13] { + IDENT [15] { name: @index0 } } } - MAP_ENTRY [14] { + MAP_ENTRY [16] { key: { - CONSTANT [15] { value: 3 } + CONSTANT [17] { value: 3 } } value: { - IDENT [16] { + IDENT [18] { name: @index0 } } @@ -2066,15 +1871,6 @@ CALL [1] { } } } - CALL [17] { - function: @in - args: { - CONSTANT [18] { value: 2 } - IDENT [19] { - name: @index1 - } - } - } } } Test case: MACRO_ITER_VAR_NOT_REFERENCED @@ -2087,123 +1883,123 @@ CALL [1] { elements: { CREATE_LIST [3] { elements: { - CONSTANT [4] { value: 1 } - CONSTANT [5] { value: 2 } - } - } - CREATE_LIST [6] { - elements: { - CONSTANT [7] { value: 3 } - CONSTANT [8] { value: 4 } - } - } - CREATE_LIST [9] { - elements: { - IDENT [10] { - name: @index1 + CREATE_LIST [4] { + elements: { + CONSTANT [5] { value: 3 } + CONSTANT [6] { value: 4 } + } } - IDENT [11] { - name: @index1 + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 3 } + CONSTANT [9] { value: 4 } + } } } } - CREATE_LIST [12] { + CREATE_LIST [10] { elements: { - IDENT [13] { - name: @index2 - } + CONSTANT [11] { value: 1 } + CONSTANT [12] { value: 2 } + } + } + CALL [13] { + function: _+_ + args: { IDENT [14] { - name: @index2 + name: @x0:0 + } + CREATE_LIST [15] { + elements: { + COMPREHENSION [16] { + iter_var: @c1:0 + iter_range: { + IDENT [17] { + name: @index1 + } + } + accu_var: @x1:0 + accu_init: { + CREATE_LIST [18] { + elements: { + } + } + } + loop_condition: { + CONSTANT [19] { value: true } + } + loop_step: { + CALL [20] { + function: _+_ + args: { + IDENT [21] { + name: @x1:0 + } + CREATE_LIST [22] { + elements: { + CREATE_LIST [23] { + elements: { + CONSTANT [24] { value: 3 } + CONSTANT [25] { value: 4 } + } + } + } + } + } + } + } + result: { + IDENT [26] { + name: @x1:0 + } + } + } + } } } } - COMPREHENSION [15] { + } + } + CALL [27] { + function: _==_ + args: { + COMPREHENSION [28] { iter_var: @c0:0 iter_range: { - IDENT [16] { - name: @index0 + IDENT [29] { + name: @index1 } } accu_var: @x0:0 accu_init: { - CREATE_LIST [17] { + CREATE_LIST [30] { elements: { } } } loop_condition: { - CONSTANT [18] { value: true } + CONSTANT [31] { value: true } } loop_step: { - CALL [19] { - function: _+_ - args: { - IDENT [20] { - name: @x0:0 - } - CREATE_LIST [21] { - elements: { - COMPREHENSION [22] { - iter_var: @c1:0 - iter_range: { - IDENT [23] { - name: @index0 - } - } - accu_var: @x1:0 - accu_init: { - CREATE_LIST [24] { - elements: { - } - } - } - loop_condition: { - CONSTANT [25] { value: true } - } - loop_step: { - CALL [26] { - function: _+_ - args: { - IDENT [27] { - name: @x1:0 - } - CREATE_LIST [28] { - elements: { - IDENT [29] { - name: @index1 - } - } - } - } - } - } - result: { - IDENT [30] { - name: @x1:0 - } - } - } - } - } - } + IDENT [32] { + name: @index2 } } result: { - IDENT [31] { + IDENT [33] { name: @x0:0 } } } - } - } - CALL [32] { - function: _==_ - args: { - IDENT [33] { - name: @index4 - } - IDENT [34] { - name: @index3 + CREATE_LIST [34] { + elements: { + IDENT [35] { + name: @index0 + } + IDENT [36] { + name: @index0 + } + } } } } @@ -2218,23 +2014,25 @@ CALL [1] { CREATE_LIST [2] { elements: { CALL [3] { - function: _-_ - args: { - IDENT [4] { - name: x - } - CONSTANT [5] { value: 1 } - } - } - CALL [6] { function: _>_ args: { - IDENT [7] { - name: @index0 + CALL [4] { + function: _-_ + args: { + IDENT [5] { + name: x + } + CONSTANT [6] { value: 1 } + } } - CONSTANT [8] { value: 3 } + CONSTANT [7] { value: 3 } } } + } + } + CALL [8] { + function: _||_ + args: { COMPREHENSION [9] { iter_var: @c0:0 iter_range: { @@ -2244,12 +2042,18 @@ CALL [1] { function: _?_:_ args: { IDENT [12] { - name: @index1 - } - IDENT [13] { name: @index0 } - CONSTANT [14] { value: 5 } + CALL [13] { + function: _-_ + args: { + IDENT [14] { + name: x + } + CONSTANT [15] { value: 1 } + } + } + CONSTANT [16] { value: 5 } } } } @@ -2257,16 +2061,16 @@ CALL [1] { } accu_var: @x0:0 accu_init: { - CONSTANT [15] { value: false } + CONSTANT [17] { value: false } } loop_condition: { - CALL [16] { + CALL [18] { function: @not_strictly_false args: { - CALL [17] { + CALL [19] { function: !_ args: { - IDENT [18] { + IDENT [20] { name: @x0:0 } } @@ -2275,46 +2079,38 @@ CALL [1] { } } loop_step: { - CALL [19] { + CALL [21] { function: _||_ args: { - IDENT [20] { + IDENT [22] { name: @x0:0 } - CALL [21] { + CALL [23] { function: _>_ args: { - CALL [22] { + CALL [24] { function: _-_ args: { - IDENT [23] { + IDENT [25] { name: @c0:0 } - CONSTANT [24] { value: 1 } + CONSTANT [26] { value: 1 } } } - CONSTANT [25] { value: 3 } + CONSTANT [27] { value: 3 } } } } } } result: { - IDENT [26] { + IDENT [28] { name: @x0:0 } } } - } - } - CALL [27] { - function: _||_ - args: { - IDENT [28] { - name: @index2 - } IDENT [29] { - name: @index1 + name: @index0 } } } @@ -2350,63 +2146,46 @@ CALL [1] { } } } - CALL [9] { - function: _+_ - args: { - IDENT [10] { - name: @x0:0 - } - CREATE_LIST [11] { - elements: { - CREATE_LIST [12] { - elements: { - IDENT [13] { - name: @index1 - } - IDENT [14] { - name: @index1 - } - } - } - } - } - } - } - COMPREHENSION [15] { + } + } + COMPREHENSION [9] { + iter_var: @c0:0 + iter_range: { + COMPREHENSION [10] { iter_var: @c1:0 iter_range: { - CREATE_LIST [16] { + CREATE_LIST [11] { elements: { - CONSTANT [17] { value: "foo" } - CONSTANT [18] { value: "bar" } + CONSTANT [12] { value: "foo" } + CONSTANT [13] { value: "bar" } } } } accu_var: @x1:0 accu_init: { - CREATE_LIST [19] { + CREATE_LIST [14] { elements: { } } } loop_condition: { - CONSTANT [20] { value: true } + CONSTANT [15] { value: true } } loop_step: { - CALL [21] { + CALL [16] { function: _+_ args: { - IDENT [22] { + IDENT [17] { name: @x1:0 } - CREATE_LIST [23] { + CREATE_LIST [18] { elements: { - CREATE_LIST [24] { + CREATE_LIST [19] { elements: { - IDENT [25] { + IDENT [20] { name: @index0 } - IDENT [26] { + IDENT [21] { name: @index0 } } @@ -2417,37 +2196,48 @@ CALL [1] { } } result: { - IDENT [27] { + IDENT [22] { name: @x1:0 } } } } - } - COMPREHENSION [28] { - iter_var: @c0:0 - iter_range: { - IDENT [29] { - name: @index3 - } - } accu_var: @x0:0 accu_init: { - CREATE_LIST [30] { + CREATE_LIST [23] { elements: { } } } loop_condition: { - CONSTANT [31] { value: true } + CONSTANT [24] { value: true } } loop_step: { - IDENT [32] { - name: @index2 + CALL [25] { + function: _+_ + args: { + IDENT [26] { + name: @x0:0 + } + CREATE_LIST [27] { + elements: { + CREATE_LIST [28] { + elements: { + IDENT [29] { + name: @index1 + } + IDENT [30] { + name: @index1 + } + } + } + } + } + } } } result: { - IDENT [33] { + IDENT [31] { name: @x0:0 } } @@ -2472,27 +2262,24 @@ CALL [1] { } } } - CALL [7] { - function: _[_] - args: { - IDENT [8] { - name: @index0 - } - CONSTANT [9] { value: "a" } - } - } } } - CALL [10] { + CALL [7] { function: _&&_ args: { - SELECT [11] { - IDENT [12] { + SELECT [8] { + IDENT [9] { name: @index0 }.a~presence_test } - IDENT [13] { - name: @index1 + CALL [10] { + function: _[_] + args: { + IDENT [11] { + name: @index0 + } + CONSTANT [12] { value: "a" } + } } } } @@ -2511,33 +2298,30 @@ CALL [1] { name: msg }.oneof_type } - CALL [5] { + } + } + CALL [5] { + function: _==_ + args: { + CALL [6] { function: _?_:_ args: { - SELECT [6] { - IDENT [7] { + SELECT [7] { + IDENT [8] { name: @index0 }.payload~presence_test } - SELECT [8] { - SELECT [9] { - IDENT [10] { + SELECT [9] { + SELECT [10] { + IDENT [11] { name: @index0 }.payload }.single_int64 } - CONSTANT [11] { value: 0 } + CONSTANT [12] { value: 0 } } } - } - } - CALL [12] { - function: _==_ - args: { - IDENT [13] { - name: @index1 - } - CONSTANT [14] { value: 10 } + CONSTANT [13] { value: 10 } } } } @@ -2551,51 +2335,44 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload - } - SELECT [7] { - IDENT [8] { - name: @index1 + SELECT [4] { + SELECT [5] { + IDENT [6] { + name: msg + }.oneof_type + }.payload }.single_int64 } - CALL [9] { + } + } + CALL [7] { + function: _==_ + args: { + CALL [8] { function: _?_:_ args: { - SELECT [10] { - IDENT [11] { - name: @index0 + SELECT [9] { + SELECT [10] { + IDENT [11] { + name: msg + }.oneof_type }.payload~presence_test } IDENT [12] { - name: @index2 + name: @index0 } CALL [13] { function: _*_ args: { IDENT [14] { - name: @index2 + name: @index0 } CONSTANT [15] { value: 0 } } } } } - } - } - CALL [16] { - function: _==_ - args: { - IDENT [17] { - name: @index3 - } - CONSTANT [18] { value: 10 } + CONSTANT [16] { value: 10 } } } } @@ -2609,51 +2386,46 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload - } - SELECT [7] { - IDENT [8] { - name: @index1 + SELECT [4] { + SELECT [5] { + IDENT [6] { + name: msg + }.oneof_type + }.payload }.single_int64 } - CALL [9] { + } + } + CALL [7] { + function: _==_ + args: { + CALL [8] { function: _?_:_ args: { - SELECT [10] { - IDENT [11] { - name: @index1 + SELECT [9] { + SELECT [10] { + SELECT [11] { + IDENT [12] { + name: msg + }.oneof_type + }.payload }.single_int64~presence_test } - IDENT [12] { - name: @index2 + IDENT [13] { + name: @index0 } - CALL [13] { + CALL [14] { function: _*_ args: { - IDENT [14] { - name: @index2 + IDENT [15] { + name: @index0 } - CONSTANT [15] { value: 0 } + CONSTANT [16] { value: 0 } } } } } - } - } - CALL [16] { - function: _==_ - args: { - IDENT [17] { - name: @index3 - } - CONSTANT [18] { value: 10 } + CONSTANT [17] { value: 10 } } } } @@ -2667,88 +2439,85 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload + SELECT [4] { + SELECT [5] { + IDENT [6] { + name: msg + }.oneof_type + }.payload + }.map_string_string } SELECT [7] { - IDENT [8] { - name: @index1 - }.map_string_string + SELECT [8] { + IDENT [9] { + name: msg + }.oneof_type + }.payload } - CALL [9] { - function: _?_:_ + } + } + CALL [10] { + function: _?_:_ + args: { + CALL [11] { + function: _&&_ args: { - CALL [10] { + CALL [12] { function: _&&_ args: { - SELECT [11] { - IDENT [12] { - name: @index1 - }.map_string_string~presence_test - } SELECT [13] { IDENT [14] { - name: @index2 - }.key~presence_test + name: msg + }.oneof_type~presence_test } - } - } - CALL [15] { - function: _==_ - args: { - SELECT [16] { - IDENT [17] { - name: @index2 - }.key + SELECT [15] { + SELECT [16] { + IDENT [17] { + name: msg + }.oneof_type + }.payload~presence_test } - CONSTANT [18] { value: "A" } } } - CONSTANT [19] { value: false } + SELECT [18] { + IDENT [19] { + name: @index1 + }.single_int64~presence_test + } } } CALL [20] { - function: _&&_ + function: _?_:_ args: { CALL [21] { function: _&&_ args: { SELECT [22] { IDENT [23] { - name: msg - }.oneof_type~presence_test + name: @index1 + }.map_string_string~presence_test } SELECT [24] { IDENT [25] { name: @index0 - }.payload~presence_test + }.key~presence_test } } } - SELECT [26] { - IDENT [27] { - name: @index1 - }.single_int64~presence_test + CALL [26] { + function: _==_ + args: { + SELECT [27] { + IDENT [28] { + name: @index0 + }.key + } + CONSTANT [29] { value: "A" } + } } + CONSTANT [30] { value: false } } } - } - } - CALL [28] { - function: _?_:_ - args: { - IDENT [29] { - name: @index4 - } - IDENT [30] { - name: @index3 - } CONSTANT [31] { value: false } } } @@ -2762,44 +2531,49 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CALL [3] { - function: optional.none - args: { - } - } - CREATE_LIST [4] { + CREATE_LIST [3] { elements: { - IDENT [5] { - name: @index0 + CALL [4] { + function: optional.none + args: { + } } - IDENT [6] { + IDENT [5] { name: opt_x } } optional_indices: [0, 1] } - CREATE_LIST [7] { + CREATE_LIST [6] { elements: { - CONSTANT [8] { value: 5 } + CONSTANT [7] { value: 5 } } } + } + } + CALL [8] { + function: _==_ + args: { CREATE_LIST [9] { elements: { CONSTANT [10] { value: 10 } - IDENT [11] { - name: @index2 + CALL [11] { + function: optional.none + args: { + } } IDENT [12] { - name: @index2 + name: @index0 + } + IDENT [13] { + name: @index0 } } + optional_indices: [0] } - CREATE_LIST [13] { + CREATE_LIST [14] { elements: { - CONSTANT [14] { value: 10 } - IDENT [15] { - name: @index0 - } + CONSTANT [15] { value: 10 } IDENT [16] { name: @index1 } @@ -2807,18 +2581,6 @@ CALL [1] { name: @index1 } } - optional_indices: [0] - } - } - } - CALL [18] { - function: _==_ - args: { - IDENT [19] { - name: @index4 - } - IDENT [20] { - name: @index3 } } } @@ -2833,53 +2595,44 @@ CALL [1] { CREATE_LIST [2] { elements: { CALL [3] { - function: optional.of - args: { - CONSTANT [4] { value: "hello" } - } - } - CREATE_MAP [5] { - MAP_ENTRY [6] { - key: { - CONSTANT [7] { value: "hello" } - } - optional_entry: true - value: { - IDENT [8] { - name: @index0 - } - } - } - } - CALL [9] { function: _[_] args: { - IDENT [10] { - name: @index1 + CREATE_MAP [4] { + MAP_ENTRY [5] { + key: { + CONSTANT [6] { value: "hello" } + } + optional_entry: true + value: { + CALL [7] { + function: optional.of + args: { + CONSTANT [8] { value: "hello" } + } + } + } + } } - CONSTANT [11] { value: "hello" } + CONSTANT [9] { value: "hello" } } } - CALL [12] { + } + } + CALL [10] { + function: _==_ + args: { + CALL [11] { function: _+_ args: { - IDENT [13] { - name: @index2 + IDENT [12] { + name: @index0 } - IDENT [14] { - name: @index2 + IDENT [13] { + name: @index0 } } } - } - } - CALL [15] { - function: _==_ - args: { - IDENT [16] { - name: @index3 - } - CONSTANT [17] { value: "hellohello" } + CONSTANT [14] { value: "hellohello" } } } } @@ -2902,69 +2655,66 @@ CALL [1] { } } } - CALL [7] { + } + } + CALL [7] { + function: _==_ + args: { + CALL [8] { function: orValue target: { - CALL [8] { + CALL [9] { function: or target: { - CALL [9] { + CALL [10] { function: _[?_] args: { - CREATE_MAP [10] { - MAP_ENTRY [11] { + CREATE_MAP [11] { + MAP_ENTRY [12] { key: { - CONSTANT [12] { value: "key" } + CONSTANT [13] { value: "key" } } optional_entry: true value: { - CALL [13] { + CALL [14] { function: optional.of args: { - CONSTANT [14] { value: "test" } + CONSTANT [15] { value: "test" } } } } } } - CONSTANT [15] { value: "bogus" } + CONSTANT [16] { value: "bogus" } } } } args: { - CALL [16] { + CALL [17] { function: _[?_] args: { - IDENT [17] { + IDENT [18] { name: @index0 } - CONSTANT [18] { value: "bogus" } + CONSTANT [19] { value: "bogus" } } } } } } args: { - CALL [19] { + CALL [20] { function: _[_] args: { - IDENT [20] { + IDENT [21] { name: @index0 } - CONSTANT [21] { value: "key" } + CONSTANT [22] { value: "key" } } } } } - } - } - CALL [22] { - function: _==_ - args: { - IDENT [23] { - name: @index1 - } - CONSTANT [24] { value: "test" } + CONSTANT [23] { value: "test" } } } } @@ -2977,139 +2727,62 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CALL [3] { - function: optional.ofNonZeroValue - args: { - CONSTANT [4] { value: 1 } - } - } - CALL [5] { - function: optional.of - args: { - CONSTANT [6] { value: 4 } - } - } - CREATE_STRUCT [7] { + CREATE_STRUCT [3] { name: TestAllTypes entries: { - ENTRY [8] { + ENTRY [4] { field_key: single_int64 optional_entry: true value: { - IDENT [9] { - name: @index0 - } - } - } - ENTRY [10] { - field_key: single_int32 - optional_entry: true - value: { - IDENT [11] { - name: @index1 - } - } - } - } - } - CALL [12] { - function: _+_ - args: { - SELECT [13] { - IDENT [14] { - name: @index2 - }.single_int32 - } - SELECT [15] { - IDENT [16] { - name: @index2 - }.single_int64 - } - } - } - } - } - CALL [17] { - function: _==_ - args: { - IDENT [18] { - name: @index3 - } - CONSTANT [19] { value: 5 } - } - } - } -} -Test case: CALL -Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('h' + 'e' + 'l' + 'l' + 'o') -=====> -CALL [1] { - function: cel.@block - args: { - CREATE_LIST [2] { - elements: { - CALL [3] { - function: _+_ - args: { - CONSTANT [4] { value: "h" } - CONSTANT [5] { value: "e" } - } - } - CALL [6] { - function: _+_ - args: { - IDENT [7] { - name: @index0 + CALL [5] { + function: optional.ofNonZeroValue + args: { + CONSTANT [6] { value: 1 } + } + } + } } - CONSTANT [8] { value: "l" } - } - } - CALL [9] { - function: _+_ - args: { - IDENT [10] { - name: @index1 + ENTRY [7] { + field_key: single_int32 + optional_entry: true + value: { + CALL [8] { + function: optional.of + args: { + CONSTANT [9] { value: 4 } + } + } + } } - CONSTANT [11] { value: "l" } } } - CALL [12] { + } + } + CALL [10] { + function: _==_ + args: { + CALL [11] { function: _+_ args: { - IDENT [13] { - name: @index2 + SELECT [12] { + IDENT [13] { + name: @index0 + }.single_int32 } - CONSTANT [14] { value: "o" } - } - } - CALL [15] { - function: _+_ - args: { - IDENT [16] { - name: @index3 + SELECT [14] { + IDENT [15] { + name: @index0 + }.single_int64 } - CONSTANT [17] { value: " world" } } } - } - } - CALL [18] { - function: matches - target: { - IDENT [19] { - name: @index4 - } - } - args: { - IDENT [20] { - name: @index3 - } + CONSTANT [16] { value: 5 } } } } } -Test case: CALL_ARGUMENT_NESTED_NO_COMMON_SUBEXPR -Source: 'hello world'.matches('h' + 'e' + 'l' + 'l' + 'o') +Test case: CALL +Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('h' + 'e' + 'l' + 'l' + 'o') =====> CALL [1] { function: cel.@block @@ -3146,147 +2819,164 @@ CALL [1] { CALL [12] { function: matches target: { - CONSTANT [13] { value: "hello world" } + CALL [13] { + function: _+_ + args: { + IDENT [14] { + name: @index0 + } + CONSTANT [15] { value: " world" } + } + } } args: { - IDENT [14] { + IDENT [16] { name: @index0 } } } } } -Test case: CALL_TARGET_NESTED_NO_COMMON_SUBEXPR -Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('hello') +Test case: CALL_ARGUMENT_NESTED_NO_COMMON_SUBEXPR +Source: 'hello world'.matches('h' + 'e' + 'l' + 'l' + 'o') =====> -CALL [1] { - function: cel.@block +CALL [2] { + function: matches + target: { + CONSTANT [1] { value: "hello world" } + } args: { - CREATE_LIST [2] { - elements: { - CALL [3] { + CALL [10] { + function: _+_ + args: { + CALL [8] { function: _+_ args: { - CALL [4] { + CALL [6] { function: _+_ args: { - CALL [5] { + CALL [4] { function: _+_ args: { - CALL [6] { - function: _+_ - args: { - CALL [7] { - function: _+_ - args: { - CONSTANT [8] { value: "h" } - CONSTANT [9] { value: "e" } - } - } - CONSTANT [10] { value: "l" } - } - } - CONSTANT [11] { value: "l" } + CONSTANT [3] { value: "h" } + CONSTANT [5] { value: "e" } } } - CONSTANT [12] { value: "o" } + CONSTANT [7] { value: "l" } } } - CONSTANT [13] { value: " world" } + CONSTANT [9] { value: "l" } } } - } - } - CALL [14] { - function: matches - target: { - IDENT [15] { - name: @index0 - } - } - args: { - CONSTANT [16] { value: "hello" } + CONSTANT [11] { value: "o" } } } } } -Test case: CALL_BOTH_ARGUMENT_TARGET_NESTED_NO_COMMON_SUBEXPR -Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('w' + 'o' + 'r' + 'l' + 'd') +Test case: CALL_TARGET_NESTED_NO_COMMON_SUBEXPR +Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('hello') =====> -CALL [1] { - function: cel.@block - args: { - CREATE_LIST [2] { - elements: { - CALL [3] { +CALL [12] { + function: matches + target: { + CALL [10] { + function: _+_ + args: { + CALL [8] { function: _+_ args: { - CALL [4] { + CALL [6] { function: _+_ args: { - CALL [5] { + CALL [4] { function: _+_ args: { - CALL [6] { + CALL [2] { function: _+_ args: { - CONSTANT [7] { value: "w" } - CONSTANT [8] { value: "o" } + CONSTANT [1] { value: "h" } + CONSTANT [3] { value: "e" } } } - CONSTANT [9] { value: "r" } + CONSTANT [5] { value: "l" } } } - CONSTANT [10] { value: "l" } + CONSTANT [7] { value: "l" } } } - CONSTANT [11] { value: "d" } + CONSTANT [9] { value: "o" } } } - CALL [12] { + CONSTANT [11] { value: " world" } + } + } + } + args: { + CONSTANT [13] { value: "hello" } + } +} +Test case: CALL_BOTH_ARGUMENT_TARGET_NESTED_NO_COMMON_SUBEXPR +Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('w' + 'o' + 'r' + 'l' + 'd') +=====> +CALL [12] { + function: matches + target: { + CALL [10] { + function: _+_ + args: { + CALL [8] { function: _+_ args: { - CALL [13] { + CALL [6] { function: _+_ args: { - CALL [14] { + CALL [4] { function: _+_ args: { - CALL [15] { + CALL [2] { function: _+_ args: { - CALL [16] { - function: _+_ - args: { - CONSTANT [17] { value: "h" } - CONSTANT [18] { value: "e" } - } - } - CONSTANT [19] { value: "l" } + CONSTANT [1] { value: "h" } + CONSTANT [3] { value: "e" } } } - CONSTANT [20] { value: "l" } + CONSTANT [5] { value: "l" } } } - CONSTANT [21] { value: "o" } + CONSTANT [7] { value: "l" } } } - CONSTANT [22] { value: " world" } + CONSTANT [9] { value: "o" } } } + CONSTANT [11] { value: " world" } } } - CALL [23] { - function: matches - target: { - IDENT [24] { - name: @index1 - } - } + } + args: { + CALL [20] { + function: _+_ args: { - IDENT [25] { - name: @index0 + CALL [18] { + function: _+_ + args: { + CALL [16] { + function: _+_ + args: { + CALL [14] { + function: _+_ + args: { + CONSTANT [13] { value: "w" } + CONSTANT [15] { value: "o" } + } + } + CONSTANT [17] { value: "r" } + } + } + CONSTANT [19] { value: "l" } + } } + CONSTANT [21] { value: "d" } } } } @@ -3300,74 +2990,66 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload - } - SELECT [7] { - IDENT [8] { - name: @index1 - }.single_int64 - } - SELECT [9] { - IDENT [10] { - name: msg + SELECT [4] { + SELECT [5] { + IDENT [6] { + name: msg + }.oneof_type + }.payload }.single_int64 } - SELECT [11] { - IDENT [12] { - name: @index1 - }.single_int32 - } } } - CALL [13] { + CALL [7] { function: _+_ args: { - CALL [14] { + CALL [8] { function: _+_ args: { - CALL [15] { + CALL [9] { function: _+_ args: { - CALL [16] { + CALL [10] { function: non_pure_custom_func args: { - IDENT [17] { - name: @index2 + IDENT [11] { + name: @index0 } } } - CALL [18] { + CALL [12] { function: non_pure_custom_func args: { - IDENT [19] { - name: @index4 + SELECT [13] { + SELECT [14] { + SELECT [15] { + IDENT [16] { + name: msg + }.oneof_type + }.payload + }.single_int32 } } } } } - CALL [20] { + CALL [17] { function: non_pure_custom_func args: { - IDENT [21] { - name: @index2 + IDENT [18] { + name: @index0 } } } } } - CALL [22] { + CALL [19] { function: non_pure_custom_func args: { - IDENT [23] { - name: @index3 + SELECT [20] { + IDENT [21] { + name: msg + }.single_int64 } } } @@ -3383,75 +3065,67 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload - } - SELECT [7] { - IDENT [8] { - name: @index1 - }.single_int64 - } - CALL [9] { - function: pure_custom_func - args: { - IDENT [10] { - name: @index2 - } - } - } - CALL [11] { + CALL [3] { function: pure_custom_func args: { - SELECT [12] { - IDENT [13] { - name: msg + SELECT [4] { + SELECT [5] { + SELECT [6] { + IDENT [7] { + name: msg + }.oneof_type + }.payload }.single_int64 } } } - CALL [14] { + CALL [8] { function: _+_ args: { - CALL [15] { + CALL [9] { function: _+_ args: { - IDENT [16] { - name: @index3 + IDENT [10] { + name: @index0 } - CALL [17] { + CALL [11] { function: pure_custom_func args: { - SELECT [18] { - IDENT [19] { - name: @index1 + SELECT [12] { + SELECT [13] { + SELECT [14] { + IDENT [15] { + name: msg + }.oneof_type + }.payload }.single_int32 } } } } } - IDENT [20] { - name: @index3 + IDENT [16] { + name: @index0 } } } } } - CALL [21] { + CALL [17] { function: _+_ args: { - IDENT [22] { - name: @index5 + IDENT [18] { + name: @index1 } - IDENT [23] { - name: @index4 + CALL [19] { + function: pure_custom_func + args: { + SELECT [20] { + IDENT [21] { + name: msg + }.single_int64 + } + } } } } diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_7.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_7.baseline index 973b97c3a..866f2c073 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_7.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_7.baseline @@ -6,20 +6,22 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_LIST [3] { - elements: { - CONSTANT [4] { value: 1 } - CONSTANT [5] { value: 2 } - } - } - CALL [6] { + CALL [3] { function: size args: { - IDENT [7] { - name: @index0 + CREATE_LIST [4] { + elements: { + CONSTANT [5] { value: 1 } + CONSTANT [6] { value: 2 } + } } } } + } + } + CALL [7] { + function: _==_ + args: { CALL [8] { function: _+_ args: { @@ -27,25 +29,17 @@ CALL [1] { function: _+_ args: { IDENT [10] { - name: @index1 + name: @index0 } IDENT [11] { - name: @index1 + name: @index0 } } } CONSTANT [12] { value: 1 } } } - } - } - CALL [13] { - function: _==_ - args: { - IDENT [14] { - name: @index2 - } - CONSTANT [15] { value: 5 } + CONSTANT [13] { value: 5 } } } } @@ -58,20 +52,22 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_LIST [3] { - elements: { - CONSTANT [4] { value: 1 } - CONSTANT [5] { value: 2 } - } - } - CALL [6] { + CALL [3] { function: size args: { - IDENT [7] { - name: @index0 + CREATE_LIST [4] { + elements: { + CONSTANT [5] { value: 1 } + CONSTANT [6] { value: 2 } + } } } } + } + } + CALL [7] { + function: _==_ + args: { CALL [8] { function: _+_ args: { @@ -83,27 +79,19 @@ CALL [1] { args: { CONSTANT [11] { value: 2 } IDENT [12] { - name: @index1 + name: @index0 } } } IDENT [13] { - name: @index1 + name: @index0 } } } CONSTANT [14] { value: 1 } } } - } - } - CALL [15] { - function: _==_ - args: { - IDENT [16] { - name: @index2 - } - CONSTANT [17] { value: 7 } + CONSTANT [15] { value: 7 } } } } @@ -116,69 +104,60 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_LIST [3] { - elements: { - CONSTANT [4] { value: 0 } - } - } - CALL [5] { + CALL [3] { function: size args: { - IDENT [6] { - name: @index0 + CREATE_LIST [4] { + elements: { + CONSTANT [5] { value: 0 } + } } } } - CREATE_LIST [7] { - elements: { - CONSTANT [8] { value: 1 } - CONSTANT [9] { value: 2 } - } - } - CALL [10] { + CALL [6] { function: size args: { - IDENT [11] { - name: @index2 + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 1 } + CONSTANT [9] { value: 2 } + } } } } - CALL [12] { + } + } + CALL [10] { + function: _==_ + args: { + CALL [11] { function: _+_ args: { - CALL [13] { + CALL [12] { function: _+_ args: { - CALL [14] { + CALL [13] { function: _+_ args: { - IDENT [15] { - name: @index1 + IDENT [14] { + name: @index0 } - IDENT [16] { - name: @index1 + IDENT [15] { + name: @index0 } } } - IDENT [17] { - name: @index3 + IDENT [16] { + name: @index1 } } } - IDENT [18] { - name: @index3 + IDENT [17] { + name: @index1 } } } - } - } - CALL [19] { - function: _==_ - args: { - IDENT [20] { - name: @index4 - } - CONSTANT [21] { value: 6 } + CONSTANT [18] { value: 6 } } } } @@ -191,106 +170,94 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_LIST [3] { - elements: { - CONSTANT [4] { value: 0 } - } - } - CALL [5] { + CALL [3] { function: size args: { - IDENT [6] { - name: @index0 + CREATE_LIST [4] { + elements: { + CONSTANT [5] { value: 0 } + } } } } - CREATE_LIST [7] { - elements: { - CONSTANT [8] { value: 1 } - CONSTANT [9] { value: 2 } - } - } - CALL [10] { + CALL [6] { function: size args: { - IDENT [11] { - name: @index2 + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 1 } + CONSTANT [9] { value: 2 } + } } } } - CREATE_LIST [12] { - elements: { - CONSTANT [13] { value: 1 } - CONSTANT [14] { value: 2 } - CONSTANT [15] { value: 3 } - } - } - CALL [16] { + CALL [10] { function: size args: { - IDENT [17] { - name: @index4 + CREATE_LIST [11] { + elements: { + CONSTANT [12] { value: 1 } + CONSTANT [13] { value: 2 } + CONSTANT [14] { value: 3 } + } } } } - CALL [18] { + } + } + CALL [15] { + function: _==_ + args: { + CALL [16] { function: _+_ args: { - CALL [19] { + CALL [17] { function: _+_ args: { - CALL [20] { + CALL [18] { function: _+_ args: { - CALL [21] { + CALL [19] { function: _+_ args: { - CALL [22] { + CALL [20] { function: _+_ args: { - CALL [23] { + CALL [21] { function: _+_ args: { - CONSTANT [24] { value: 5 } - IDENT [25] { - name: @index1 + CONSTANT [22] { value: 5 } + IDENT [23] { + name: @index0 } } } - IDENT [26] { - name: @index1 + IDENT [24] { + name: @index0 } } } - IDENT [27] { - name: @index3 + IDENT [25] { + name: @index1 } } } - IDENT [28] { - name: @index3 + IDENT [26] { + name: @index1 } } } - IDENT [29] { - name: @index5 + IDENT [27] { + name: @index2 } } } - IDENT [30] { - name: @index5 + IDENT [28] { + name: @index2 } } } - } - } - CALL [31] { - function: _==_ - args: { - IDENT [32] { - name: @index6 - } - CONSTANT [33] { value: 17 } + CONSTANT [29] { value: 17 } } } } @@ -304,149 +271,109 @@ CALL [1] { CREATE_LIST [2] { elements: { CALL [3] { - function: timestamp - args: { - CONSTANT [4] { value: 1000000000 } - } - } - CALL [5] { - function: int - args: { - IDENT [6] { - name: @index0 + function: getFullYear + target: { + CALL [4] { + function: timestamp + args: { + CALL [5] { + function: int + args: { + CALL [6] { + function: timestamp + args: { + CONSTANT [7] { value: 1000000000 } + } + } + } + } + } } } - } - CALL [7] { - function: timestamp args: { - IDENT [8] { - name: @index1 - } } } - CALL [9] { + CALL [8] { function: getFullYear target: { - IDENT [10] { - name: @index2 + CALL [9] { + function: timestamp + args: { + CALL [10] { + function: int + args: { + CALL [11] { + function: timestamp + args: { + CONSTANT [12] { value: 200 } + } + } + } + } + } } } args: { } } - CALL [11] { - function: timestamp - args: { - CONSTANT [12] { value: 50 } - } - } CALL [13] { - function: int - args: { - IDENT [14] { - name: @index4 - } - } - } - CALL [15] { function: timestamp args: { - IDENT [16] { - name: @index5 + CALL [14] { + function: int + args: { + CALL [15] { + function: timestamp + args: { + CONSTANT [16] { value: 50 } + } + } + } } } } CALL [17] { function: timestamp args: { - CONSTANT [18] { value: 200 } - } - } - CALL [19] { - function: int - args: { - IDENT [20] { - name: @index7 + CALL [18] { + function: int + args: { + CALL [19] { + function: timestamp + args: { + CONSTANT [20] { value: 75 } + } + } + } } } } CALL [21] { - function: timestamp - args: { - IDENT [22] { - name: @index8 - } - } - } - CALL [23] { - function: getFullYear - target: { - IDENT [24] { - name: @index9 - } - } - args: { - } - } - CALL [25] { - function: timestamp - args: { - CONSTANT [26] { value: 75 } - } - } - CALL [27] { - function: int - args: { - IDENT [28] { - name: @index11 - } - } - } - CALL [29] { - function: timestamp + function: _+_ args: { - IDENT [30] { - name: @index12 - } - } - } - CALL [31] { - function: getMinutes - target: { - IDENT [32] { - name: @index13 - } - } - args: { - } - } - CALL [33] { - function: _+_ - args: { - CALL [34] { + CALL [22] { function: _+_ args: { - CALL [35] { + CALL [23] { function: _+_ args: { - CALL [36] { + CALL [24] { function: _+_ args: { - CALL [37] { + CALL [25] { function: _+_ args: { - CALL [38] { + CALL [26] { function: _+_ args: { - IDENT [39] { - name: @index3 + IDENT [27] { + name: @index0 } - CALL [40] { + CALL [28] { function: getFullYear target: { - IDENT [41] { - name: @index13 + IDENT [29] { + name: @index3 } } args: { @@ -454,11 +381,11 @@ CALL [1] { } } } - CALL [42] { + CALL [30] { function: getFullYear target: { - IDENT [43] { - name: @index6 + IDENT [31] { + name: @index2 } } args: { @@ -466,16 +393,16 @@ CALL [1] { } } } - IDENT [44] { - name: @index3 + IDENT [32] { + name: @index0 } } } - CALL [45] { + CALL [33] { function: getSeconds target: { - IDENT [46] { - name: @index6 + IDENT [34] { + name: @index2 } } args: { @@ -483,44 +410,48 @@ CALL [1] { } } } - IDENT [47] { - name: @index10 + IDENT [35] { + name: @index1 } } } - IDENT [48] { - name: @index10 + IDENT [36] { + name: @index1 } } } - CALL [49] { + } + } + CALL [37] { + function: _==_ + args: { + CALL [38] { function: _+_ args: { - CALL [50] { + CALL [39] { function: _+_ args: { - IDENT [51] { - name: @index15 + IDENT [40] { + name: @index4 } - IDENT [52] { - name: @index14 + CALL [41] { + function: getMinutes + target: { + IDENT [42] { + name: @index3 + } + } + args: { + } } } } - IDENT [53] { - name: @index3 + IDENT [43] { + name: @index0 } } } - } - } - CALL [54] { - function: _==_ - args: { - IDENT [55] { - name: @index16 - } - CONSTANT [56] { value: 13934 } + CONSTANT [44] { value: 13934 } } } } @@ -533,53 +464,47 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_MAP [3] { - MAP_ENTRY [4] { - key: { - CONSTANT [5] { value: "a" } - } - value: { - CONSTANT [6] { value: 2 } - } - } - } - CALL [7] { + CALL [3] { function: _[_] args: { - IDENT [8] { - name: @index0 + CREATE_MAP [4] { + MAP_ENTRY [5] { + key: { + CONSTANT [6] { value: "a" } + } + value: { + CONSTANT [7] { value: 2 } + } + } } - CONSTANT [9] { value: "a" } + CONSTANT [8] { value: "a" } } } + } + } + CALL [9] { + function: _==_ + args: { CALL [10] { function: _+_ args: { IDENT [11] { - name: @index1 + name: @index0 } CALL [12] { function: _*_ args: { IDENT [13] { - name: @index1 + name: @index0 } IDENT [14] { - name: @index1 + name: @index0 } } } } } - } - } - CALL [15] { - function: _==_ - args: { - IDENT [16] { - name: @index2 - } - CONSTANT [17] { value: 6 } + CONSTANT [15] { value: 6 } } } } @@ -595,51 +520,48 @@ CALL [1] { CREATE_MAP [3] { MAP_ENTRY [4] { key: { - CONSTANT [5] { value: "b" } + CONSTANT [5] { value: "e" } } value: { - CONSTANT [6] { value: 1 } + CREATE_MAP [6] { + MAP_ENTRY [7] { + key: { + CONSTANT [8] { value: "b" } + } + value: { + CONSTANT [9] { value: 1 } + } + } + } } } } - CREATE_MAP [7] { - MAP_ENTRY [8] { + CREATE_MAP [10] { + MAP_ENTRY [11] { key: { - CONSTANT [9] { value: "e" } + CONSTANT [12] { value: "b" } } value: { - IDENT [10] { - name: @index0 - } + CONSTANT [13] { value: 1 } } } } } } - CREATE_MAP [11] { - MAP_ENTRY [12] { - key: { - CONSTANT [13] { value: "a" } - } - value: { - IDENT [14] { - name: @index0 - } - } - } + CREATE_MAP [14] { MAP_ENTRY [15] { key: { - CONSTANT [16] { value: "c" } + CONSTANT [16] { value: "a" } } value: { IDENT [17] { - name: @index0 + name: @index1 } } } MAP_ENTRY [18] { key: { - CONSTANT [19] { value: "d" } + CONSTANT [19] { value: "c" } } value: { IDENT [20] { @@ -649,11 +571,21 @@ CALL [1] { } MAP_ENTRY [21] { key: { - CONSTANT [22] { value: "e" } + CONSTANT [22] { value: "d" } } value: { IDENT [23] { - name: @index1 + name: @index0 + } + } + } + MAP_ENTRY [24] { + key: { + CONSTANT [25] { value: "e" } + } + value: { + IDENT [26] { + name: @index0 } } } @@ -682,37 +614,34 @@ CALL [1] { CONSTANT [10] { value: 2 } } } - CREATE_LIST [11] { - elements: { - IDENT [12] { - name: @index1 - } - IDENT [13] { - name: @index0 - } - } - } } } - CREATE_LIST [14] { + CREATE_LIST [11] { elements: { - CONSTANT [15] { value: 1 } - IDENT [16] { + CONSTANT [12] { value: 1 } + IDENT [13] { name: @index0 } - CONSTANT [17] { value: 2 } - IDENT [18] { + CONSTANT [14] { value: 2 } + IDENT [15] { name: @index0 } - CONSTANT [19] { value: 5 } - IDENT [20] { + CONSTANT [16] { value: 5 } + IDENT [17] { name: @index0 } - CONSTANT [21] { value: 7 } - IDENT [22] { - name: @index2 + CONSTANT [18] { value: 7 } + CREATE_LIST [19] { + elements: { + IDENT [20] { + name: @index1 + } + IDENT [21] { + name: @index0 + } + } } - IDENT [23] { + IDENT [22] { name: @index1 } } @@ -732,26 +661,23 @@ CALL [1] { name: msg }.single_int64 } - CALL [5] { + } + } + CALL [5] { + function: _==_ + args: { + CALL [6] { function: _+_ args: { - IDENT [6] { + IDENT [7] { name: @index0 } - IDENT [7] { + IDENT [8] { name: @index0 } } } - } - } - CALL [8] { - function: _==_ - args: { - IDENT [9] { - name: @index1 - } - CONSTANT [10] { value: 6 } + CONSTANT [9] { value: 6 } } } } @@ -765,58 +691,64 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload + SELECT [4] { + SELECT [5] { + IDENT [6] { + name: msg + }.oneof_type + }.payload + }.single_int64 } SELECT [7] { - IDENT [8] { - name: @index1 - }.single_int64 + SELECT [8] { + IDENT [9] { + name: msg + }.oneof_type + }.payload } - CALL [9] { + } + } + CALL [10] { + function: _==_ + args: { + CALL [11] { function: _+_ args: { - CALL [10] { + CALL [12] { function: _+_ args: { - CALL [11] { + CALL [13] { function: _+_ args: { - CALL [12] { + CALL [14] { function: _+_ args: { - IDENT [13] { - name: @index2 + IDENT [15] { + name: @index0 } - SELECT [14] { - IDENT [15] { + SELECT [16] { + IDENT [17] { name: @index1 }.single_int32 } } } - IDENT [16] { - name: @index2 + IDENT [18] { + name: @index0 } } } - SELECT [17] { - IDENT [18] { + SELECT [19] { + IDENT [20] { name: msg }.single_int64 } } } - SELECT [19] { - SELECT [20] { - SELECT [21] { - IDENT [22] { + SELECT [21] { + SELECT [22] { + SELECT [23] { + IDENT [24] { name: @index1 }.oneof_type }.payload @@ -824,14 +756,6 @@ CALL [1] { } } } - } - } - CALL [23] { - function: _==_ - args: { - IDENT [24] { - name: @index3 - } CONSTANT [25] { value: 31 } } } @@ -846,51 +770,33 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload - } - SELECT [7] { - IDENT [8] { - name: @index1 - }.oneof_type - } - SELECT [9] { - IDENT [10] { - name: @index2 - }.payload - } - SELECT [11] { - IDENT [12] { - name: @index3 - }.oneof_type - } - SELECT [13] { - SELECT [14] { - SELECT [15] { - SELECT [16] { - IDENT [17] { - name: @index4 - }.child - }.child + SELECT [4] { + SELECT [5] { + SELECT [6] { + SELECT [7] { + IDENT [8] { + name: msg + }.oneof_type + }.payload + }.oneof_type }.payload - }.single_bool + }.oneof_type } - CALL [18] { + } + } + CALL [9] { + function: _||_ + args: { + CALL [10] { function: _||_ args: { - CONSTANT [19] { value: true } - SELECT [20] { - SELECT [21] { - SELECT [22] { - SELECT [23] { - IDENT [24] { - name: @index4 + CONSTANT [11] { value: true } + SELECT [12] { + SELECT [13] { + SELECT [14] { + SELECT [15] { + IDENT [16] { + name: @index0 }.payload }.oneof_type }.payload @@ -898,16 +804,16 @@ CALL [1] { } } } - } - } - CALL [25] { - function: _||_ - args: { - IDENT [26] { - name: @index6 - } - IDENT [27] { - name: @index5 + SELECT [17] { + SELECT [18] { + SELECT [19] { + SELECT [20] { + IDENT [21] { + name: @index0 + }.child + }.child + }.payload + }.single_bool } } } @@ -921,58 +827,46 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload - } - SELECT [7] { - IDENT [8] { - name: @index1 - }.map_int32_int64 - } - CALL [9] { + CALL [3] { function: _[_] args: { - IDENT [10] { - name: @index2 + SELECT [4] { + SELECT [5] { + SELECT [6] { + IDENT [7] { + name: msg + }.oneof_type + }.payload + }.map_int32_int64 } - CONSTANT [11] { value: 1 } + CONSTANT [8] { value: 1 } } } - CALL [12] { + } + } + CALL [9] { + function: _==_ + args: { + CALL [10] { function: _+_ args: { - CALL [13] { + CALL [11] { function: _+_ args: { - IDENT [14] { - name: @index3 + IDENT [12] { + name: @index0 } - IDENT [15] { - name: @index3 + IDENT [13] { + name: @index0 } } } - IDENT [16] { - name: @index3 + IDENT [14] { + name: @index0 } } } - } - } - CALL [17] { - function: _==_ - args: { - IDENT [18] { - name: @index4 - } - CONSTANT [19] { value: 15 } + CONSTANT [15] { value: 15 } } } } @@ -986,66 +880,57 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload - } - SELECT [7] { - IDENT [8] { - name: @index1 + SELECT [4] { + SELECT [5] { + IDENT [6] { + name: msg + }.oneof_type + }.payload }.map_int32_int64 } - CALL [9] { + } + } + CALL [7] { + function: _==_ + args: { + CALL [8] { function: _+_ args: { - CALL [10] { + CALL [9] { function: _+_ args: { - CALL [11] { + CALL [10] { function: _[_] args: { - IDENT [12] { - name: @index2 + IDENT [11] { + name: @index0 } - CONSTANT [13] { value: 0 } + CONSTANT [12] { value: 0 } } } - CALL [14] { + CALL [13] { function: _[_] args: { - IDENT [15] { - name: @index2 + IDENT [14] { + name: @index0 } - CONSTANT [16] { value: 1 } + CONSTANT [15] { value: 1 } } } } } - CALL [17] { + CALL [16] { function: _[_] args: { - IDENT [18] { - name: @index2 + IDENT [17] { + name: @index0 } - CONSTANT [19] { value: 2 } + CONSTANT [18] { value: 2 } } } } } - } - } - CALL [20] { - function: _==_ - args: { - IDENT [21] { - name: @index3 - } - CONSTANT [22] { value: 8 } + CONSTANT [19] { value: 8 } } } } @@ -1075,16 +960,13 @@ CALL [1] { }.payload }.oneof_type } - SELECT [11] { - IDENT [12] { - name: @index0 - }.payload - } } } - SELECT [13] { - IDENT [14] { - name: @index1 + SELECT [11] { + SELECT [12] { + IDENT [13] { + name: @index0 + }.payload }.single_int64 } } @@ -1102,33 +984,30 @@ CALL [1] { name: msg }.single_int64 } - CALL [5] { + } + } + CALL [5] { + function: _==_ + args: { + CALL [6] { function: _?_:_ args: { - CALL [6] { + CALL [7] { function: _>_ args: { - IDENT [7] { + IDENT [8] { name: @index0 } - CONSTANT [8] { value: 0 } + CONSTANT [9] { value: 0 } } } - IDENT [9] { + IDENT [10] { name: @index0 } - CONSTANT [10] { value: 0 } + CONSTANT [11] { value: 0 } } } - } - } - CALL [11] { - function: _==_ - args: { - IDENT [12] { - name: @index1 - } - CONSTANT [13] { value: 3 } + CONSTANT [12] { value: 3 } } } } @@ -1146,47 +1025,44 @@ CALL [1] { name: msg }.single_int64 } - CALL [5] { + } + } + CALL [5] { + function: _?_:_ + args: { + CONSTANT [6] { value: false } + CONSTANT [7] { value: false } + CALL [8] { function: _==_ args: { - CALL [6] { + CALL [9] { function: _+_ args: { - IDENT [7] { + IDENT [10] { name: @index0 } - CALL [8] { + CALL [11] { function: _*_ args: { - CALL [9] { + CALL [12] { function: _+_ args: { - IDENT [10] { + IDENT [13] { name: @index0 } - CONSTANT [11] { value: 1 } + CONSTANT [14] { value: 1 } } } - CONSTANT [12] { value: 2 } + CONSTANT [15] { value: 2 } } } } } - CONSTANT [13] { value: 11 } + CONSTANT [16] { value: 11 } } } } } - CALL [14] { - function: _?_:_ - args: { - CONSTANT [15] { value: false } - CONSTANT [16] { value: false } - IDENT [17] { - name: @index1 - } - } - } } } Test case: NESTED_TERNARY @@ -1207,56 +1083,53 @@ CALL [1] { name: msg }.single_int32 } - CALL [7] { + } + } + CALL [7] { + function: _==_ + args: { + CALL [8] { function: _?_:_ args: { - CALL [8] { + CALL [9] { function: _>_ args: { - IDENT [9] { + IDENT [10] { name: @index0 } - CONSTANT [10] { value: 0 } + CONSTANT [11] { value: 0 } } } - CALL [11] { + CALL [12] { function: _?_:_ args: { - CALL [12] { + CALL [13] { function: _>_ args: { - IDENT [13] { + IDENT [14] { name: @index1 } - CONSTANT [14] { value: 0 } + CONSTANT [15] { value: 0 } } } - CALL [15] { + CALL [16] { function: _+_ args: { - IDENT [16] { + IDENT [17] { name: @index0 } - IDENT [17] { + IDENT [18] { name: @index1 } } } - CONSTANT [18] { value: 0 } + CONSTANT [19] { value: 0 } } } - CONSTANT [19] { value: 0 } + CONSTANT [20] { value: 0 } } } - } - } - CALL [20] { - function: _==_ - args: { - IDENT [21] { - name: @index2 - } - CONSTANT [22] { value: 8 } + CONSTANT [21] { value: 8 } } } } @@ -1269,50 +1142,60 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_LIST [3] { - elements: { - CONSTANT [4] { value: 1 } - } - } - CALL [5] { - function: _>_ - args: { - IDENT [6] { - name: @c0:0 - } - CONSTANT [7] { value: 0 } - } - } - CALL [8] { - function: _||_ + CALL [3] { + function: size args: { - IDENT [9] { - name: @x0:0 - } - IDENT [10] { - name: @index1 - } - } - } - COMPREHENSION [11] { - iter_var: @c0:0 - iter_range: { - IDENT [12] { - name: @index0 - } - } - accu_var: @x0:0 - accu_init: { - CONSTANT [13] { value: false } - } - loop_condition: { - CALL [14] { - function: @not_strictly_false - args: { - CALL [15] { - function: !_ - args: { - IDENT [16] { + CREATE_LIST [4] { + elements: { + COMPREHENSION [5] { + iter_var: @c0:0 + iter_range: { + CREATE_LIST [6] { + elements: { + CONSTANT [7] { value: 1 } + } + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [8] { value: false } + } + loop_condition: { + CALL [9] { + function: @not_strictly_false + args: { + CALL [10] { + function: !_ + args: { + IDENT [11] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + CALL [12] { + function: _||_ + args: { + IDENT [13] { + name: @x0:0 + } + CALL [14] { + function: _>_ + args: { + IDENT [15] { + name: @c0:0 + } + CONSTANT [16] { value: 0 } + } + } + } + } + } + result: { + IDENT [17] { name: @x0:0 } } @@ -1320,76 +1203,61 @@ CALL [1] { } } } - loop_step: { - IDENT [17] { - name: @index2 - } - } - result: { - IDENT [18] { - name: @x0:0 - } - } } - CREATE_LIST [19] { - elements: { - IDENT [20] { - name: @index3 - } - } - } - CALL [21] { + CALL [18] { function: size args: { - IDENT [22] { - name: @index4 - } - } - } - CREATE_LIST [23] { - elements: { - CONSTANT [24] { value: 2 } - } - } - CALL [25] { - function: _>_ - args: { - IDENT [26] { - name: @c0:0 - } - CONSTANT [27] { value: 1 } - } - } - CALL [28] { - function: _||_ - args: { - IDENT [29] { - name: @x0:0 - } - IDENT [30] { - name: @index7 - } - } - } - COMPREHENSION [31] { - iter_var: @c0:0 - iter_range: { - IDENT [32] { - name: @index6 - } - } - accu_var: @x0:0 - accu_init: { - CONSTANT [33] { value: false } - } - loop_condition: { - CALL [34] { - function: @not_strictly_false - args: { - CALL [35] { - function: !_ - args: { - IDENT [36] { + CREATE_LIST [19] { + elements: { + COMPREHENSION [20] { + iter_var: @c0:0 + iter_range: { + CREATE_LIST [21] { + elements: { + CONSTANT [22] { value: 2 } + } + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [23] { value: false } + } + loop_condition: { + CALL [24] { + function: @not_strictly_false + args: { + CALL [25] { + function: !_ + args: { + IDENT [26] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + CALL [27] { + function: _||_ + args: { + IDENT [28] { + name: @x0:0 + } + CALL [29] { + function: _>_ + args: { + IDENT [30] { + name: @c0:0 + } + CONSTANT [31] { value: 1 } + } + } + } + } + } + result: { + IDENT [32] { name: @x0:0 } } @@ -1397,68 +1265,40 @@ CALL [1] { } } } - loop_step: { - IDENT [37] { - name: @index8 - } - } - result: { - IDENT [38] { - name: @x0:0 - } - } } - CREATE_LIST [39] { - elements: { - IDENT [40] { - name: @index9 - } - } - } - CALL [41] { - function: size - args: { - IDENT [42] { - name: @index10 - } - } - } - CALL [43] { + } + } + CALL [33] { + function: _==_ + args: { + CALL [34] { function: _+_ args: { - CALL [44] { + CALL [35] { function: _+_ args: { - CALL [45] { + CALL [36] { function: _+_ args: { - IDENT [46] { - name: @index5 + IDENT [37] { + name: @index0 } - IDENT [47] { - name: @index5 + IDENT [38] { + name: @index0 } } } - IDENT [48] { - name: @index11 + IDENT [39] { + name: @index1 } } } - IDENT [49] { - name: @index11 + IDENT [40] { + name: @index1 } } } - } - } - CALL [50] { - function: _==_ - args: { - IDENT [51] { - name: @index12 - } - CONSTANT [52] { value: 4 } + CONSTANT [41] { value: 4 } } } } @@ -1473,187 +1313,157 @@ CALL [1] { elements: { CREATE_LIST [3] { elements: { - CONSTANT [4] { value: 1 } - } - } - CALL [5] { - function: _>_ - args: { - IDENT [6] { - name: @c0:0 - } - CONSTANT [7] { value: 0 } - } - } - CALL [8] { - function: _||_ - args: { - IDENT [9] { - name: @x0:0 - } - IDENT [10] { - name: @index1 - } - } - } - COMPREHENSION [11] { - iter_var: @c0:0 - iter_range: { - IDENT [12] { - name: @index0 - } - } - accu_var: @x0:0 - accu_init: { - CONSTANT [13] { value: false } - } - loop_condition: { - CALL [14] { - function: @not_strictly_false - args: { - CALL [15] { - function: !_ + COMPREHENSION [4] { + iter_var: @c0:0 + iter_range: { + CREATE_LIST [5] { + elements: { + CONSTANT [6] { value: 1 } + } + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [7] { value: false } + } + loop_condition: { + CALL [8] { + function: @not_strictly_false + args: { + CALL [9] { + function: !_ + args: { + IDENT [10] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + CALL [11] { + function: _||_ args: { - IDENT [16] { + IDENT [12] { name: @x0:0 } + CALL [13] { + function: _>_ + args: { + IDENT [14] { + name: @c0:0 + } + CONSTANT [15] { value: 0 } + } + } } } } - } - } - loop_step: { - IDENT [17] { - name: @index2 - } - } - result: { - IDENT [18] { - name: @x0:0 - } - } - } - CREATE_LIST [19] { - elements: { - IDENT [20] { - name: @index3 + result: { + IDENT [16] { + name: @x0:0 + } + } } } } - CREATE_LIST [21] { + CREATE_LIST [17] { elements: { - CONSTANT [22] { value: "a" } - } - } - CALL [23] { - function: _==_ - args: { - IDENT [24] { - name: @c0:1 - } - CONSTANT [25] { value: "a" } - } - } - CALL [26] { - function: _||_ - args: { - IDENT [27] { - name: @x0:1 - } - IDENT [28] { - name: @index6 - } - } - } - COMPREHENSION [29] { - iter_var: @c0:1 - iter_range: { - IDENT [30] { - name: @index5 - } - } - accu_var: @x0:1 - accu_init: { - CONSTANT [31] { value: false } - } - loop_condition: { - CALL [32] { - function: @not_strictly_false - args: { - CALL [33] { - function: !_ + COMPREHENSION [18] { + iter_var: @c0:1 + iter_range: { + CREATE_LIST [19] { + elements: { + CONSTANT [20] { value: "a" } + } + } + } + accu_var: @x0:1 + accu_init: { + CONSTANT [21] { value: false } + } + loop_condition: { + CALL [22] { + function: @not_strictly_false + args: { + CALL [23] { + function: !_ + args: { + IDENT [24] { + name: @x0:1 + } + } + } + } + } + } + loop_step: { + CALL [25] { + function: _||_ args: { - IDENT [34] { + IDENT [26] { name: @x0:1 } + CALL [27] { + function: _==_ + args: { + IDENT [28] { + name: @c0:1 + } + CONSTANT [29] { value: "a" } + } + } } } } + result: { + IDENT [30] { + name: @x0:1 + } + } } } - loop_step: { - IDENT [35] { - name: @index7 - } - } - result: { - IDENT [36] { - name: @x0:1 - } - } - } - CREATE_LIST [37] { - elements: { - IDENT [38] { - name: @index8 - } - } - } - CREATE_LIST [39] { - elements: { - CONSTANT [40] { value: true } - CONSTANT [41] { value: true } - CONSTANT [42] { value: true } - CONSTANT [43] { value: true } - } } - CALL [44] { + } + } + CALL [31] { + function: _==_ + args: { + CALL [32] { function: _+_ args: { - CALL [45] { + CALL [33] { function: _+_ args: { - CALL [46] { + CALL [34] { function: _+_ args: { - IDENT [47] { - name: @index4 + IDENT [35] { + name: @index0 } - IDENT [48] { - name: @index4 + IDENT [36] { + name: @index0 } } } - IDENT [49] { - name: @index9 + IDENT [37] { + name: @index1 } } } - IDENT [50] { - name: @index9 + IDENT [38] { + name: @index1 } } } - } - } - CALL [51] { - function: _==_ - args: { - IDENT [52] { - name: @index11 - } - IDENT [53] { - name: @index10 + CREATE_LIST [39] { + elements: { + CONSTANT [40] { value: true } + CONSTANT [41] { value: true } + CONSTANT [42] { value: true } + CONSTANT [43] { value: true } + } } } } @@ -1681,78 +1491,65 @@ CALL [1] { CONSTANT [10] { value: 4 } } } - CREATE_LIST [11] { - elements: { - IDENT [12] { - name: @index1 - } - IDENT [13] { - name: @index1 - } - IDENT [14] { - name: @index1 - } - } - } - COMPREHENSION [15] { + COMPREHENSION [11] { iter_var: @c0:0 iter_range: { - IDENT [16] { + IDENT [12] { name: @index0 } } accu_var: @x0:0 accu_init: { - CREATE_LIST [17] { + CREATE_LIST [13] { elements: { } } } loop_condition: { - CONSTANT [18] { value: true } + CONSTANT [14] { value: true } } loop_step: { - CALL [19] { + CALL [15] { function: _+_ args: { - IDENT [20] { + IDENT [16] { name: @x0:0 } - CREATE_LIST [21] { + CREATE_LIST [17] { elements: { - COMPREHENSION [22] { + COMPREHENSION [18] { iter_var: @c1:0 iter_range: { - IDENT [23] { + IDENT [19] { name: @index0 } } accu_var: @x1:0 accu_init: { - CREATE_LIST [24] { + CREATE_LIST [20] { elements: { } } } loop_condition: { - CONSTANT [25] { value: true } + CONSTANT [21] { value: true } } loop_step: { - CALL [26] { + CALL [22] { function: _+_ args: { - IDENT [27] { + IDENT [23] { name: @x1:0 } - CREATE_LIST [28] { + CREATE_LIST [24] { elements: { - CALL [29] { + CALL [25] { function: _+_ args: { - IDENT [30] { + IDENT [26] { name: @c1:0 } - CONSTANT [31] { value: 1 } + CONSTANT [27] { value: 1 } } } } @@ -1761,7 +1558,7 @@ CALL [1] { } } result: { - IDENT [32] { + IDENT [28] { name: @x1:0 } } @@ -1772,22 +1569,32 @@ CALL [1] { } } result: { - IDENT [33] { + IDENT [29] { name: @x0:0 } } } } } - CALL [34] { + CALL [30] { function: _==_ args: { - IDENT [35] { - name: @index3 - } - IDENT [36] { + IDENT [31] { name: @index2 } + CREATE_LIST [32] { + elements: { + IDENT [33] { + name: @index1 + } + IDENT [34] { + name: @index1 + } + IDENT [35] { + name: @index1 + } + } + } } } } @@ -1800,108 +1607,94 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_LIST [3] { - elements: { - CREATE_LIST [4] { - elements: { - CONSTANT [5] { value: 1 } - } - } - CREATE_LIST [6] { - elements: { - CONSTANT [7] { value: 2 } - } - } - } - } - COMPREHENSION [8] { + COMPREHENSION [3] { iter_var: @c0:0 iter_range: { - CREATE_LIST [9] { + CREATE_LIST [4] { elements: { - CONSTANT [10] { value: 1 } - CONSTANT [11] { value: 2 } + CONSTANT [5] { value: 1 } + CONSTANT [6] { value: 2 } } } } accu_var: @x0:0 accu_init: { - CREATE_LIST [12] { + CREATE_LIST [7] { elements: { } } } loop_condition: { - CONSTANT [13] { value: true } + CONSTANT [8] { value: true } } loop_step: { - CALL [14] { + CALL [9] { function: _+_ args: { - IDENT [15] { + IDENT [10] { name: @x0:0 } - CREATE_LIST [16] { + CREATE_LIST [11] { elements: { - COMPREHENSION [17] { + COMPREHENSION [12] { iter_var: @c1:0 iter_range: { - CREATE_LIST [18] { + CREATE_LIST [13] { elements: { - CONSTANT [19] { value: 1 } - CONSTANT [20] { value: 2 } - CONSTANT [21] { value: 3 } + CONSTANT [14] { value: 1 } + CONSTANT [15] { value: 2 } + CONSTANT [16] { value: 3 } } } } accu_var: @x1:0 accu_init: { - CREATE_LIST [22] { + CREATE_LIST [17] { elements: { } } } loop_condition: { - CONSTANT [23] { value: true } + CONSTANT [18] { value: true } } loop_step: { - CALL [24] { + CALL [19] { function: _?_:_ args: { - CALL [25] { + CALL [20] { function: _==_ args: { - IDENT [26] { + IDENT [21] { name: @c1:0 } - IDENT [27] { + IDENT [22] { name: @c0:0 } } } - CALL [28] { + CALL [23] { function: _+_ args: { - IDENT [29] { + IDENT [24] { name: @x1:0 } - CREATE_LIST [30] { + CREATE_LIST [25] { elements: { - IDENT [31] { + IDENT [26] { name: @c1:0 } } } } } - IDENT [32] { + IDENT [27] { name: @x1:0 } } } } result: { - IDENT [33] { + IDENT [28] { name: @x1:0 } } @@ -1912,22 +1705,33 @@ CALL [1] { } } result: { - IDENT [34] { + IDENT [29] { name: @x0:0 } } } } } - CALL [35] { + CALL [30] { function: _==_ args: { - IDENT [36] { - name: @index1 - } - IDENT [37] { + IDENT [31] { name: @index0 } + CREATE_LIST [32] { + elements: { + CREATE_LIST [33] { + elements: { + CONSTANT [34] { value: 1 } + } + } + CREATE_LIST [35] { + elements: { + CONSTANT [36] { value: 2 } + } + } + } + } } } } @@ -1940,71 +1744,69 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_LIST [3] { - elements: { - CONSTANT [4] { value: 1 } - CONSTANT [5] { value: 2 } - CONSTANT [6] { value: 3 } - } - } - CALL [7] { + CALL [3] { function: @in args: { - CONSTANT [8] { value: 1 } - IDENT [9] { - name: @index0 + CONSTANT [4] { value: 1 } + CREATE_LIST [5] { + elements: { + CONSTANT [6] { value: 1 } + CONSTANT [7] { value: 2 } + CONSTANT [8] { value: 3 } + } } } } - CALL [10] { + CREATE_LIST [9] { + elements: { + CONSTANT [10] { value: 1 } + CONSTANT [11] { value: 2 } + CONSTANT [12] { value: 3 } + } + } + } + } + CALL [13] { + function: _&&_ + args: { + CALL [14] { function: _&&_ args: { - CALL [11] { + IDENT [15] { + name: @index0 + } + CALL [16] { function: @in args: { - CONSTANT [12] { value: 3 } - CREATE_LIST [13] { - elements: { - CONSTANT [14] { value: 3 } - IDENT [15] { - name: @index0 - } - } + CONSTANT [17] { value: 2 } + IDENT [18] { + name: @index1 } } } - IDENT [16] { - name: @index1 - } } } - CALL [17] { + CALL [19] { function: _&&_ args: { - IDENT [18] { - name: @index1 - } - CALL [19] { + CALL [20] { function: @in args: { - CONSTANT [20] { value: 2 } - IDENT [21] { - name: @index0 + CONSTANT [21] { value: 3 } + CREATE_LIST [22] { + elements: { + CONSTANT [23] { value: 3 } + IDENT [24] { + name: @index1 + } + } } } - } - } - } - } - } - CALL [22] { - function: _&&_ - args: { - IDENT [23] { - name: @index3 - } - IDENT [24] { - name: @index2 + } + IDENT [25] { + name: @index0 + } + } } } } @@ -2028,31 +1830,37 @@ CALL [1] { } } } - CREATE_MAP [7] { - MAP_ENTRY [8] { + } + } + CALL [7] { + function: @in + args: { + CONSTANT [8] { value: 2 } + CREATE_MAP [9] { + MAP_ENTRY [10] { key: { - CONSTANT [9] { value: "a" } + CONSTANT [11] { value: "a" } } value: { - CONSTANT [10] { value: 1 } + CONSTANT [12] { value: 1 } } } - MAP_ENTRY [11] { + MAP_ENTRY [13] { key: { - CONSTANT [12] { value: 2 } + CONSTANT [14] { value: 2 } } value: { - IDENT [13] { + IDENT [15] { name: @index0 } } } - MAP_ENTRY [14] { + MAP_ENTRY [16] { key: { - CONSTANT [15] { value: 3 } + CONSTANT [17] { value: 3 } } value: { - IDENT [16] { + IDENT [18] { name: @index0 } } @@ -2060,15 +1868,6 @@ CALL [1] { } } } - CALL [17] { - function: @in - args: { - CONSTANT [18] { value: 2 } - IDENT [19] { - name: @index1 - } - } - } } } Test case: MACRO_ITER_VAR_NOT_REFERENCED @@ -2081,90 +1880,83 @@ CALL [1] { elements: { CREATE_LIST [3] { elements: { - CONSTANT [4] { value: 1 } - CONSTANT [5] { value: 2 } - } - } - CREATE_LIST [6] { - elements: { - CONSTANT [7] { value: 3 } - CONSTANT [8] { value: 4 } - } - } - CREATE_LIST [9] { - elements: { - IDENT [10] { - name: @index1 + CREATE_LIST [4] { + elements: { + CONSTANT [5] { value: 3 } + CONSTANT [6] { value: 4 } + } } - IDENT [11] { - name: @index1 + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 3 } + CONSTANT [9] { value: 4 } + } } } } - CREATE_LIST [12] { + CREATE_LIST [10] { elements: { - IDENT [13] { - name: @index2 - } - IDENT [14] { - name: @index2 - } + CONSTANT [11] { value: 1 } + CONSTANT [12] { value: 2 } } } - COMPREHENSION [15] { + COMPREHENSION [13] { iter_var: @c0:0 iter_range: { - IDENT [16] { - name: @index0 + IDENT [14] { + name: @index1 } } accu_var: @x0:0 accu_init: { - CREATE_LIST [17] { + CREATE_LIST [15] { elements: { } } } loop_condition: { - CONSTANT [18] { value: true } + CONSTANT [16] { value: true } } loop_step: { - CALL [19] { + CALL [17] { function: _+_ args: { - IDENT [20] { + IDENT [18] { name: @x0:0 } - CREATE_LIST [21] { + CREATE_LIST [19] { elements: { - COMPREHENSION [22] { + COMPREHENSION [20] { iter_var: @c1:0 iter_range: { - IDENT [23] { - name: @index0 + IDENT [21] { + name: @index1 } } accu_var: @x1:0 accu_init: { - CREATE_LIST [24] { + CREATE_LIST [22] { elements: { } } } loop_condition: { - CONSTANT [25] { value: true } + CONSTANT [23] { value: true } } loop_step: { - CALL [26] { + CALL [24] { function: _+_ args: { - IDENT [27] { + IDENT [25] { name: @x1:0 } - CREATE_LIST [28] { + CREATE_LIST [26] { elements: { - IDENT [29] { - name: @index1 + CREATE_LIST [27] { + elements: { + CONSTANT [28] { value: 3 } + CONSTANT [29] { value: 4 } + } } } } @@ -2194,10 +1986,17 @@ CALL [1] { function: _==_ args: { IDENT [33] { - name: @index4 + name: @index2 } - IDENT [34] { - name: @index3 + CREATE_LIST [34] { + elements: { + IDENT [35] { + name: @index0 + } + IDENT [36] { + name: @index0 + } + } } } } @@ -2212,23 +2011,25 @@ CALL [1] { CREATE_LIST [2] { elements: { CALL [3] { - function: _-_ - args: { - IDENT [4] { - name: x - } - CONSTANT [5] { value: 1 } - } - } - CALL [6] { function: _>_ args: { - IDENT [7] { - name: @index0 + CALL [4] { + function: _-_ + args: { + IDENT [5] { + name: x + } + CONSTANT [6] { value: 1 } + } } - CONSTANT [8] { value: 3 } + CONSTANT [7] { value: 3 } } } + } + } + CALL [8] { + function: _||_ + args: { COMPREHENSION [9] { iter_var: @c0:0 iter_range: { @@ -2238,12 +2039,18 @@ CALL [1] { function: _?_:_ args: { IDENT [12] { - name: @index1 - } - IDENT [13] { name: @index0 } - CONSTANT [14] { value: 5 } + CALL [13] { + function: _-_ + args: { + IDENT [14] { + name: x + } + CONSTANT [15] { value: 1 } + } + } + CONSTANT [16] { value: 5 } } } } @@ -2251,16 +2058,16 @@ CALL [1] { } accu_var: @x0:0 accu_init: { - CONSTANT [15] { value: false } + CONSTANT [17] { value: false } } loop_condition: { - CALL [16] { + CALL [18] { function: @not_strictly_false args: { - CALL [17] { + CALL [19] { function: !_ args: { - IDENT [18] { + IDENT [20] { name: @x0:0 } } @@ -2269,46 +2076,38 @@ CALL [1] { } } loop_step: { - CALL [19] { + CALL [21] { function: _||_ args: { - IDENT [20] { + IDENT [22] { name: @x0:0 } - CALL [21] { + CALL [23] { function: _>_ args: { - CALL [22] { + CALL [24] { function: _-_ args: { - IDENT [23] { + IDENT [25] { name: @c0:0 } - CONSTANT [24] { value: 1 } + CONSTANT [26] { value: 1 } } } - CONSTANT [25] { value: 3 } + CONSTANT [27] { value: 3 } } } } } } result: { - IDENT [26] { + IDENT [28] { name: @x0:0 } } } - } - } - CALL [27] { - function: _||_ - args: { - IDENT [28] { - name: @index2 - } IDENT [29] { - name: @index1 + name: @index0 } } } @@ -2344,63 +2143,46 @@ CALL [1] { } } } - CALL [9] { - function: _+_ - args: { - IDENT [10] { - name: @x0:0 - } - CREATE_LIST [11] { - elements: { - CREATE_LIST [12] { - elements: { - IDENT [13] { - name: @index1 - } - IDENT [14] { - name: @index1 - } - } - } - } - } - } - } - COMPREHENSION [15] { + } + } + COMPREHENSION [9] { + iter_var: @c0:0 + iter_range: { + COMPREHENSION [10] { iter_var: @c1:0 iter_range: { - CREATE_LIST [16] { + CREATE_LIST [11] { elements: { - CONSTANT [17] { value: "foo" } - CONSTANT [18] { value: "bar" } + CONSTANT [12] { value: "foo" } + CONSTANT [13] { value: "bar" } } } } accu_var: @x1:0 accu_init: { - CREATE_LIST [19] { + CREATE_LIST [14] { elements: { } } } loop_condition: { - CONSTANT [20] { value: true } + CONSTANT [15] { value: true } } loop_step: { - CALL [21] { + CALL [16] { function: _+_ args: { - IDENT [22] { + IDENT [17] { name: @x1:0 } - CREATE_LIST [23] { + CREATE_LIST [18] { elements: { - CREATE_LIST [24] { + CREATE_LIST [19] { elements: { - IDENT [25] { + IDENT [20] { name: @index0 } - IDENT [26] { + IDENT [21] { name: @index0 } } @@ -2411,37 +2193,48 @@ CALL [1] { } } result: { - IDENT [27] { + IDENT [22] { name: @x1:0 } } } } - } - COMPREHENSION [28] { - iter_var: @c0:0 - iter_range: { - IDENT [29] { - name: @index3 - } - } accu_var: @x0:0 accu_init: { - CREATE_LIST [30] { + CREATE_LIST [23] { elements: { } } } loop_condition: { - CONSTANT [31] { value: true } + CONSTANT [24] { value: true } } loop_step: { - IDENT [32] { - name: @index2 + CALL [25] { + function: _+_ + args: { + IDENT [26] { + name: @x0:0 + } + CREATE_LIST [27] { + elements: { + CREATE_LIST [28] { + elements: { + IDENT [29] { + name: @index1 + } + IDENT [30] { + name: @index1 + } + } + } + } + } + } } } result: { - IDENT [33] { + IDENT [31] { name: @x0:0 } } @@ -2466,27 +2259,24 @@ CALL [1] { } } } - CALL [7] { - function: _[_] - args: { - IDENT [8] { - name: @index0 - } - CONSTANT [9] { value: "a" } - } - } } } - CALL [10] { + CALL [7] { function: _&&_ args: { - SELECT [11] { - IDENT [12] { + SELECT [8] { + IDENT [9] { name: @index0 }.a~presence_test } - IDENT [13] { - name: @index1 + CALL [10] { + function: _[_] + args: { + IDENT [11] { + name: @index0 + } + CONSTANT [12] { value: "a" } + } } } } @@ -2505,33 +2295,30 @@ CALL [1] { name: msg }.oneof_type } - CALL [5] { + } + } + CALL [5] { + function: _==_ + args: { + CALL [6] { function: _?_:_ args: { - SELECT [6] { - IDENT [7] { + SELECT [7] { + IDENT [8] { name: @index0 }.payload~presence_test } - SELECT [8] { - SELECT [9] { - IDENT [10] { + SELECT [9] { + SELECT [10] { + IDENT [11] { name: @index0 }.payload }.single_int64 } - CONSTANT [11] { value: 0 } + CONSTANT [12] { value: 0 } } } - } - } - CALL [12] { - function: _==_ - args: { - IDENT [13] { - name: @index1 - } - CONSTANT [14] { value: 10 } + CONSTANT [13] { value: 10 } } } } @@ -2545,51 +2332,44 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload - } - SELECT [7] { - IDENT [8] { - name: @index1 + SELECT [4] { + SELECT [5] { + IDENT [6] { + name: msg + }.oneof_type + }.payload }.single_int64 } - CALL [9] { + } + } + CALL [7] { + function: _==_ + args: { + CALL [8] { function: _?_:_ args: { - SELECT [10] { - IDENT [11] { - name: @index0 + SELECT [9] { + SELECT [10] { + IDENT [11] { + name: msg + }.oneof_type }.payload~presence_test } IDENT [12] { - name: @index2 + name: @index0 } CALL [13] { function: _*_ args: { IDENT [14] { - name: @index2 + name: @index0 } CONSTANT [15] { value: 0 } } } } } - } - } - CALL [16] { - function: _==_ - args: { - IDENT [17] { - name: @index3 - } - CONSTANT [18] { value: 10 } + CONSTANT [16] { value: 10 } } } } @@ -2603,51 +2383,46 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload - } - SELECT [7] { - IDENT [8] { - name: @index1 + SELECT [4] { + SELECT [5] { + IDENT [6] { + name: msg + }.oneof_type + }.payload }.single_int64 } - CALL [9] { + } + } + CALL [7] { + function: _==_ + args: { + CALL [8] { function: _?_:_ args: { - SELECT [10] { - IDENT [11] { - name: @index1 + SELECT [9] { + SELECT [10] { + SELECT [11] { + IDENT [12] { + name: msg + }.oneof_type + }.payload }.single_int64~presence_test } - IDENT [12] { - name: @index2 + IDENT [13] { + name: @index0 } - CALL [13] { + CALL [14] { function: _*_ args: { - IDENT [14] { - name: @index2 + IDENT [15] { + name: @index0 } - CONSTANT [15] { value: 0 } + CONSTANT [16] { value: 0 } } } } } - } - } - CALL [16] { - function: _==_ - args: { - IDENT [17] { - name: @index3 - } - CONSTANT [18] { value: 10 } + CONSTANT [17] { value: 10 } } } } @@ -2661,88 +2436,85 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload + SELECT [4] { + SELECT [5] { + IDENT [6] { + name: msg + }.oneof_type + }.payload + }.map_string_string } SELECT [7] { - IDENT [8] { - name: @index1 - }.map_string_string + SELECT [8] { + IDENT [9] { + name: msg + }.oneof_type + }.payload } - CALL [9] { - function: _?_:_ + } + } + CALL [10] { + function: _?_:_ + args: { + CALL [11] { + function: _&&_ args: { - CALL [10] { + CALL [12] { function: _&&_ args: { - SELECT [11] { - IDENT [12] { - name: @index1 - }.map_string_string~presence_test - } SELECT [13] { IDENT [14] { - name: @index2 - }.key~presence_test + name: msg + }.oneof_type~presence_test } - } - } - CALL [15] { - function: _==_ - args: { - SELECT [16] { - IDENT [17] { - name: @index2 - }.key + SELECT [15] { + SELECT [16] { + IDENT [17] { + name: msg + }.oneof_type + }.payload~presence_test } - CONSTANT [18] { value: "A" } } } - CONSTANT [19] { value: false } + SELECT [18] { + IDENT [19] { + name: @index1 + }.single_int64~presence_test + } } } CALL [20] { - function: _&&_ + function: _?_:_ args: { CALL [21] { function: _&&_ args: { SELECT [22] { IDENT [23] { - name: msg - }.oneof_type~presence_test + name: @index1 + }.map_string_string~presence_test } SELECT [24] { IDENT [25] { name: @index0 - }.payload~presence_test + }.key~presence_test } } } - SELECT [26] { - IDENT [27] { - name: @index1 - }.single_int64~presence_test + CALL [26] { + function: _==_ + args: { + SELECT [27] { + IDENT [28] { + name: @index0 + }.key + } + CONSTANT [29] { value: "A" } + } } + CONSTANT [30] { value: false } } } - } - } - CALL [28] { - function: _?_:_ - args: { - IDENT [29] { - name: @index4 - } - IDENT [30] { - name: @index3 - } CONSTANT [31] { value: false } } } @@ -2756,44 +2528,49 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CALL [3] { - function: optional.none - args: { - } - } - CREATE_LIST [4] { + CREATE_LIST [3] { elements: { - IDENT [5] { - name: @index0 + CALL [4] { + function: optional.none + args: { + } } - IDENT [6] { + IDENT [5] { name: opt_x } } optional_indices: [0, 1] } - CREATE_LIST [7] { + CREATE_LIST [6] { elements: { - CONSTANT [8] { value: 5 } + CONSTANT [7] { value: 5 } } } + } + } + CALL [8] { + function: _==_ + args: { CREATE_LIST [9] { elements: { CONSTANT [10] { value: 10 } - IDENT [11] { - name: @index2 + CALL [11] { + function: optional.none + args: { + } } IDENT [12] { - name: @index2 + name: @index0 + } + IDENT [13] { + name: @index0 } } + optional_indices: [0] } - CREATE_LIST [13] { + CREATE_LIST [14] { elements: { - CONSTANT [14] { value: 10 } - IDENT [15] { - name: @index0 - } + CONSTANT [15] { value: 10 } IDENT [16] { name: @index1 } @@ -2801,18 +2578,6 @@ CALL [1] { name: @index1 } } - optional_indices: [0] - } - } - } - CALL [18] { - function: _==_ - args: { - IDENT [19] { - name: @index4 - } - IDENT [20] { - name: @index3 } } } @@ -2827,53 +2592,44 @@ CALL [1] { CREATE_LIST [2] { elements: { CALL [3] { - function: optional.of - args: { - CONSTANT [4] { value: "hello" } - } - } - CREATE_MAP [5] { - MAP_ENTRY [6] { - key: { - CONSTANT [7] { value: "hello" } - } - optional_entry: true - value: { - IDENT [8] { - name: @index0 - } - } - } - } - CALL [9] { function: _[_] args: { - IDENT [10] { - name: @index1 + CREATE_MAP [4] { + MAP_ENTRY [5] { + key: { + CONSTANT [6] { value: "hello" } + } + optional_entry: true + value: { + CALL [7] { + function: optional.of + args: { + CONSTANT [8] { value: "hello" } + } + } + } + } } - CONSTANT [11] { value: "hello" } + CONSTANT [9] { value: "hello" } } } - CALL [12] { + } + } + CALL [10] { + function: _==_ + args: { + CALL [11] { function: _+_ args: { - IDENT [13] { - name: @index2 + IDENT [12] { + name: @index0 } - IDENT [14] { - name: @index2 + IDENT [13] { + name: @index0 } } } - } - } - CALL [15] { - function: _==_ - args: { - IDENT [16] { - name: @index3 - } - CONSTANT [17] { value: "hellohello" } + CONSTANT [14] { value: "hellohello" } } } } @@ -2896,69 +2652,66 @@ CALL [1] { } } } - CALL [7] { + } + } + CALL [7] { + function: _==_ + args: { + CALL [8] { function: orValue target: { - CALL [8] { + CALL [9] { function: or target: { - CALL [9] { + CALL [10] { function: _[?_] args: { - CREATE_MAP [10] { - MAP_ENTRY [11] { + CREATE_MAP [11] { + MAP_ENTRY [12] { key: { - CONSTANT [12] { value: "key" } + CONSTANT [13] { value: "key" } } optional_entry: true value: { - CALL [13] { + CALL [14] { function: optional.of args: { - CONSTANT [14] { value: "test" } + CONSTANT [15] { value: "test" } } } } } } - CONSTANT [15] { value: "bogus" } + CONSTANT [16] { value: "bogus" } } } } args: { - CALL [16] { + CALL [17] { function: _[?_] args: { - IDENT [17] { + IDENT [18] { name: @index0 } - CONSTANT [18] { value: "bogus" } + CONSTANT [19] { value: "bogus" } } } } } } args: { - CALL [19] { + CALL [20] { function: _[_] args: { - IDENT [20] { + IDENT [21] { name: @index0 } - CONSTANT [21] { value: "key" } + CONSTANT [22] { value: "key" } } } } } - } - } - CALL [22] { - function: _==_ - args: { - IDENT [23] { - name: @index1 - } - CONSTANT [24] { value: "test" } + CONSTANT [23] { value: "test" } } } } @@ -2971,139 +2724,62 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CALL [3] { - function: optional.ofNonZeroValue - args: { - CONSTANT [4] { value: 1 } - } - } - CALL [5] { - function: optional.of - args: { - CONSTANT [6] { value: 4 } - } - } - CREATE_STRUCT [7] { + CREATE_STRUCT [3] { name: TestAllTypes entries: { - ENTRY [8] { + ENTRY [4] { field_key: single_int64 optional_entry: true value: { - IDENT [9] { - name: @index0 - } - } - } - ENTRY [10] { - field_key: single_int32 - optional_entry: true - value: { - IDENT [11] { - name: @index1 - } - } - } - } - } - CALL [12] { - function: _+_ - args: { - SELECT [13] { - IDENT [14] { - name: @index2 - }.single_int32 - } - SELECT [15] { - IDENT [16] { - name: @index2 - }.single_int64 - } - } - } - } - } - CALL [17] { - function: _==_ - args: { - IDENT [18] { - name: @index3 - } - CONSTANT [19] { value: 5 } - } - } - } -} -Test case: CALL -Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('h' + 'e' + 'l' + 'l' + 'o') -=====> -CALL [1] { - function: cel.@block - args: { - CREATE_LIST [2] { - elements: { - CALL [3] { - function: _+_ - args: { - CONSTANT [4] { value: "h" } - CONSTANT [5] { value: "e" } - } - } - CALL [6] { - function: _+_ - args: { - IDENT [7] { - name: @index0 - } - CONSTANT [8] { value: "l" } - } - } - CALL [9] { - function: _+_ - args: { - IDENT [10] { - name: @index1 + CALL [5] { + function: optional.ofNonZeroValue + args: { + CONSTANT [6] { value: 1 } + } + } + } } - CONSTANT [11] { value: "l" } - } - } - CALL [12] { - function: _+_ - args: { - IDENT [13] { - name: @index2 + ENTRY [7] { + field_key: single_int32 + optional_entry: true + value: { + CALL [8] { + function: optional.of + args: { + CONSTANT [9] { value: 4 } + } + } + } } - CONSTANT [14] { value: "o" } } } - CALL [15] { + } + } + CALL [10] { + function: _==_ + args: { + CALL [11] { function: _+_ args: { - IDENT [16] { - name: @index3 + SELECT [12] { + IDENT [13] { + name: @index0 + }.single_int32 + } + SELECT [14] { + IDENT [15] { + name: @index0 + }.single_int64 } - CONSTANT [17] { value: " world" } } } - } - } - CALL [18] { - function: matches - target: { - IDENT [19] { - name: @index4 - } - } - args: { - IDENT [20] { - name: @index3 - } + CONSTANT [16] { value: 5 } } } } } -Test case: CALL_ARGUMENT_NESTED_NO_COMMON_SUBEXPR -Source: 'hello world'.matches('h' + 'e' + 'l' + 'l' + 'o') +Test case: CALL +Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('h' + 'e' + 'l' + 'l' + 'o') =====> CALL [1] { function: cel.@block @@ -3140,147 +2816,164 @@ CALL [1] { CALL [12] { function: matches target: { - CONSTANT [13] { value: "hello world" } + CALL [13] { + function: _+_ + args: { + IDENT [14] { + name: @index0 + } + CONSTANT [15] { value: " world" } + } + } } args: { - IDENT [14] { + IDENT [16] { name: @index0 } } } } } -Test case: CALL_TARGET_NESTED_NO_COMMON_SUBEXPR -Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('hello') +Test case: CALL_ARGUMENT_NESTED_NO_COMMON_SUBEXPR +Source: 'hello world'.matches('h' + 'e' + 'l' + 'l' + 'o') =====> -CALL [1] { - function: cel.@block +CALL [2] { + function: matches + target: { + CONSTANT [1] { value: "hello world" } + } args: { - CREATE_LIST [2] { - elements: { - CALL [3] { + CALL [10] { + function: _+_ + args: { + CALL [8] { function: _+_ args: { - CALL [4] { + CALL [6] { function: _+_ args: { - CALL [5] { + CALL [4] { function: _+_ args: { - CALL [6] { - function: _+_ - args: { - CALL [7] { - function: _+_ - args: { - CONSTANT [8] { value: "h" } - CONSTANT [9] { value: "e" } - } - } - CONSTANT [10] { value: "l" } - } - } - CONSTANT [11] { value: "l" } + CONSTANT [3] { value: "h" } + CONSTANT [5] { value: "e" } } } - CONSTANT [12] { value: "o" } + CONSTANT [7] { value: "l" } } } - CONSTANT [13] { value: " world" } + CONSTANT [9] { value: "l" } } } - } - } - CALL [14] { - function: matches - target: { - IDENT [15] { - name: @index0 - } - } - args: { - CONSTANT [16] { value: "hello" } + CONSTANT [11] { value: "o" } } } } } -Test case: CALL_BOTH_ARGUMENT_TARGET_NESTED_NO_COMMON_SUBEXPR -Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('w' + 'o' + 'r' + 'l' + 'd') +Test case: CALL_TARGET_NESTED_NO_COMMON_SUBEXPR +Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('hello') =====> -CALL [1] { - function: cel.@block - args: { - CREATE_LIST [2] { - elements: { - CALL [3] { +CALL [12] { + function: matches + target: { + CALL [10] { + function: _+_ + args: { + CALL [8] { function: _+_ args: { - CALL [4] { + CALL [6] { function: _+_ args: { - CALL [5] { + CALL [4] { function: _+_ args: { - CALL [6] { + CALL [2] { function: _+_ args: { - CONSTANT [7] { value: "w" } - CONSTANT [8] { value: "o" } + CONSTANT [1] { value: "h" } + CONSTANT [3] { value: "e" } } } - CONSTANT [9] { value: "r" } + CONSTANT [5] { value: "l" } } } - CONSTANT [10] { value: "l" } + CONSTANT [7] { value: "l" } } } - CONSTANT [11] { value: "d" } + CONSTANT [9] { value: "o" } } } - CALL [12] { + CONSTANT [11] { value: " world" } + } + } + } + args: { + CONSTANT [13] { value: "hello" } + } +} +Test case: CALL_BOTH_ARGUMENT_TARGET_NESTED_NO_COMMON_SUBEXPR +Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('w' + 'o' + 'r' + 'l' + 'd') +=====> +CALL [12] { + function: matches + target: { + CALL [10] { + function: _+_ + args: { + CALL [8] { function: _+_ args: { - CALL [13] { + CALL [6] { function: _+_ args: { - CALL [14] { + CALL [4] { function: _+_ args: { - CALL [15] { + CALL [2] { function: _+_ args: { - CALL [16] { - function: _+_ - args: { - CONSTANT [17] { value: "h" } - CONSTANT [18] { value: "e" } - } - } - CONSTANT [19] { value: "l" } + CONSTANT [1] { value: "h" } + CONSTANT [3] { value: "e" } } } - CONSTANT [20] { value: "l" } + CONSTANT [5] { value: "l" } } } - CONSTANT [21] { value: "o" } + CONSTANT [7] { value: "l" } } } - CONSTANT [22] { value: " world" } + CONSTANT [9] { value: "o" } } } + CONSTANT [11] { value: " world" } } } - CALL [23] { - function: matches - target: { - IDENT [24] { - name: @index1 - } - } + } + args: { + CALL [20] { + function: _+_ args: { - IDENT [25] { - name: @index0 + CALL [18] { + function: _+_ + args: { + CALL [16] { + function: _+_ + args: { + CALL [14] { + function: _+_ + args: { + CONSTANT [13] { value: "w" } + CONSTANT [15] { value: "o" } + } + } + CONSTANT [17] { value: "r" } + } + } + CONSTANT [19] { value: "l" } + } } + CONSTANT [21] { value: "d" } } } } @@ -3294,74 +2987,66 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload - } - SELECT [7] { - IDENT [8] { - name: @index1 - }.single_int64 - } - SELECT [9] { - IDENT [10] { - name: msg + SELECT [4] { + SELECT [5] { + IDENT [6] { + name: msg + }.oneof_type + }.payload }.single_int64 } - SELECT [11] { - IDENT [12] { - name: @index1 - }.single_int32 - } } } - CALL [13] { + CALL [7] { function: _+_ args: { - CALL [14] { + CALL [8] { function: _+_ args: { - CALL [15] { + CALL [9] { function: _+_ args: { - CALL [16] { + CALL [10] { function: non_pure_custom_func args: { - IDENT [17] { - name: @index2 + IDENT [11] { + name: @index0 } } } - CALL [18] { + CALL [12] { function: non_pure_custom_func args: { - IDENT [19] { - name: @index4 + SELECT [13] { + SELECT [14] { + SELECT [15] { + IDENT [16] { + name: msg + }.oneof_type + }.payload + }.single_int32 } } } } } - CALL [20] { + CALL [17] { function: non_pure_custom_func args: { - IDENT [21] { - name: @index2 + IDENT [18] { + name: @index0 } } } } } - CALL [22] { + CALL [19] { function: non_pure_custom_func args: { - IDENT [23] { - name: @index3 + SELECT [20] { + IDENT [21] { + name: msg + }.single_int64 } } } @@ -3377,75 +3062,64 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload - } - SELECT [7] { - IDENT [8] { - name: @index1 - }.single_int64 - } - CALL [9] { - function: pure_custom_func - args: { - IDENT [10] { - name: @index2 - } - } - } - CALL [11] { + CALL [3] { function: pure_custom_func args: { - SELECT [12] { - IDENT [13] { - name: msg + SELECT [4] { + SELECT [5] { + SELECT [6] { + IDENT [7] { + name: msg + }.oneof_type + }.payload }.single_int64 } } } - CALL [14] { + } + } + CALL [8] { + function: _+_ + args: { + CALL [9] { function: _+_ args: { - CALL [15] { + CALL [10] { function: _+_ args: { - IDENT [16] { - name: @index3 + IDENT [11] { + name: @index0 } - CALL [17] { + CALL [12] { function: pure_custom_func args: { - SELECT [18] { - IDENT [19] { - name: @index1 + SELECT [13] { + SELECT [14] { + SELECT [15] { + IDENT [16] { + name: msg + }.oneof_type + }.payload }.single_int32 } } } } } - IDENT [20] { - name: @index3 + IDENT [17] { + name: @index0 } } } - } - } - CALL [21] { - function: _+_ - args: { - IDENT [22] { - name: @index5 - } - IDENT [23] { - name: @index4 + CALL [18] { + function: pure_custom_func + args: { + SELECT [19] { + IDENT [20] { + name: msg + }.single_int64 + } + } } } } diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_8.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_8.baseline index 67f1b1308..7da4bdebb 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_8.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_8.baseline @@ -6,20 +6,22 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_LIST [3] { - elements: { - CONSTANT [4] { value: 1 } - CONSTANT [5] { value: 2 } - } - } - CALL [6] { + CALL [3] { function: size args: { - IDENT [7] { - name: @index0 + CREATE_LIST [4] { + elements: { + CONSTANT [5] { value: 1 } + CONSTANT [6] { value: 2 } + } } } } + } + } + CALL [7] { + function: _==_ + args: { CALL [8] { function: _+_ args: { @@ -27,25 +29,17 @@ CALL [1] { function: _+_ args: { IDENT [10] { - name: @index1 + name: @index0 } IDENT [11] { - name: @index1 + name: @index0 } } } CONSTANT [12] { value: 1 } } } - } - } - CALL [13] { - function: _==_ - args: { - IDENT [14] { - name: @index2 - } - CONSTANT [15] { value: 5 } + CONSTANT [13] { value: 5 } } } } @@ -58,20 +52,22 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_LIST [3] { - elements: { - CONSTANT [4] { value: 1 } - CONSTANT [5] { value: 2 } - } - } - CALL [6] { + CALL [3] { function: size args: { - IDENT [7] { - name: @index0 + CREATE_LIST [4] { + elements: { + CONSTANT [5] { value: 1 } + CONSTANT [6] { value: 2 } + } } } } + } + } + CALL [7] { + function: _==_ + args: { CALL [8] { function: _+_ args: { @@ -83,27 +79,19 @@ CALL [1] { args: { CONSTANT [11] { value: 2 } IDENT [12] { - name: @index1 + name: @index0 } } } IDENT [13] { - name: @index1 + name: @index0 } } } CONSTANT [14] { value: 1 } } } - } - } - CALL [15] { - function: _==_ - args: { - IDENT [16] { - name: @index2 - } - CONSTANT [17] { value: 7 } + CONSTANT [15] { value: 7 } } } } @@ -116,69 +104,60 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_LIST [3] { - elements: { - CONSTANT [4] { value: 0 } - } - } - CALL [5] { + CALL [3] { function: size args: { - IDENT [6] { - name: @index0 + CREATE_LIST [4] { + elements: { + CONSTANT [5] { value: 0 } + } } } } - CREATE_LIST [7] { - elements: { - CONSTANT [8] { value: 1 } - CONSTANT [9] { value: 2 } - } - } - CALL [10] { + CALL [6] { function: size args: { - IDENT [11] { - name: @index2 + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 1 } + CONSTANT [9] { value: 2 } + } } } } - CALL [12] { + } + } + CALL [10] { + function: _==_ + args: { + CALL [11] { function: _+_ args: { - CALL [13] { + CALL [12] { function: _+_ args: { - CALL [14] { + CALL [13] { function: _+_ args: { - IDENT [15] { - name: @index1 + IDENT [14] { + name: @index0 } - IDENT [16] { - name: @index1 + IDENT [15] { + name: @index0 } } } - IDENT [17] { - name: @index3 + IDENT [16] { + name: @index1 } } } - IDENT [18] { - name: @index3 + IDENT [17] { + name: @index1 } } } - } - } - CALL [19] { - function: _==_ - args: { - IDENT [20] { - name: @index4 - } - CONSTANT [21] { value: 6 } + CONSTANT [18] { value: 6 } } } } @@ -191,106 +170,94 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_LIST [3] { - elements: { - CONSTANT [4] { value: 0 } - } - } - CALL [5] { + CALL [3] { function: size args: { - IDENT [6] { - name: @index0 + CREATE_LIST [4] { + elements: { + CONSTANT [5] { value: 0 } + } } } } - CREATE_LIST [7] { - elements: { - CONSTANT [8] { value: 1 } - CONSTANT [9] { value: 2 } - } - } - CALL [10] { + CALL [6] { function: size args: { - IDENT [11] { - name: @index2 + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 1 } + CONSTANT [9] { value: 2 } + } } } } - CREATE_LIST [12] { - elements: { - CONSTANT [13] { value: 1 } - CONSTANT [14] { value: 2 } - CONSTANT [15] { value: 3 } - } - } - CALL [16] { + CALL [10] { function: size args: { - IDENT [17] { - name: @index4 + CREATE_LIST [11] { + elements: { + CONSTANT [12] { value: 1 } + CONSTANT [13] { value: 2 } + CONSTANT [14] { value: 3 } + } } } } - CALL [18] { + } + } + CALL [15] { + function: _==_ + args: { + CALL [16] { function: _+_ args: { - CALL [19] { + CALL [17] { function: _+_ args: { - CALL [20] { + CALL [18] { function: _+_ args: { - CALL [21] { + CALL [19] { function: _+_ args: { - CALL [22] { + CALL [20] { function: _+_ args: { - CALL [23] { + CALL [21] { function: _+_ args: { - CONSTANT [24] { value: 5 } - IDENT [25] { - name: @index1 + CONSTANT [22] { value: 5 } + IDENT [23] { + name: @index0 } } } - IDENT [26] { - name: @index1 + IDENT [24] { + name: @index0 } } } - IDENT [27] { - name: @index3 + IDENT [25] { + name: @index1 } } } - IDENT [28] { - name: @index3 + IDENT [26] { + name: @index1 } } } - IDENT [29] { - name: @index5 + IDENT [27] { + name: @index2 } } } - IDENT [30] { - name: @index5 + IDENT [28] { + name: @index2 } } } - } - } - CALL [31] { - function: _==_ - args: { - IDENT [32] { - name: @index6 - } - CONSTANT [33] { value: 17 } + CONSTANT [29] { value: 17 } } } } @@ -304,142 +271,112 @@ CALL [1] { CREATE_LIST [2] { elements: { CALL [3] { - function: timestamp - args: { - CONSTANT [4] { value: 1000000000 } - } - } - CALL [5] { - function: int - args: { - IDENT [6] { - name: @index0 + function: getFullYear + target: { + CALL [4] { + function: timestamp + args: { + CALL [5] { + function: int + args: { + CALL [6] { + function: timestamp + args: { + CONSTANT [7] { value: 1000000000 } + } + } + } + } + } } } - } - CALL [7] { - function: timestamp args: { - IDENT [8] { - name: @index1 - } } } - CALL [9] { + CALL [8] { function: getFullYear target: { - IDENT [10] { - name: @index2 + CALL [9] { + function: timestamp + args: { + CALL [10] { + function: int + args: { + CALL [11] { + function: timestamp + args: { + CONSTANT [12] { value: 200 } + } + } + } + } + } } } args: { } } - CALL [11] { - function: timestamp - args: { - CONSTANT [12] { value: 50 } - } - } CALL [13] { - function: int - args: { - IDENT [14] { - name: @index4 - } - } - } - CALL [15] { function: timestamp args: { - IDENT [16] { - name: @index5 + CALL [14] { + function: int + args: { + CALL [15] { + function: timestamp + args: { + CONSTANT [16] { value: 50 } + } + } + } } } } CALL [17] { function: timestamp args: { - CONSTANT [18] { value: 200 } - } - } - CALL [19] { - function: int - args: { - IDENT [20] { - name: @index7 + CALL [18] { + function: int + args: { + CALL [19] { + function: timestamp + args: { + CONSTANT [20] { value: 75 } + } + } + } } } } CALL [21] { - function: timestamp - args: { - IDENT [22] { - name: @index8 - } - } - } - CALL [23] { - function: getFullYear - target: { - IDENT [24] { - name: @index9 - } - } - args: { - } - } - CALL [25] { - function: timestamp - args: { - CONSTANT [26] { value: 75 } - } - } - CALL [27] { - function: int - args: { - IDENT [28] { - name: @index11 - } - } - } - CALL [29] { - function: timestamp - args: { - IDENT [30] { - name: @index12 - } - } - } - CALL [31] { function: _+_ args: { - CALL [32] { + CALL [22] { function: _+_ args: { - CALL [33] { + CALL [23] { function: _+_ args: { - CALL [34] { + CALL [24] { function: _+_ args: { - CALL [35] { + CALL [25] { function: _+_ args: { - CALL [36] { + CALL [26] { function: _+_ args: { - CALL [37] { + CALL [27] { function: _+_ args: { - IDENT [38] { - name: @index3 + IDENT [28] { + name: @index0 } - CALL [39] { + CALL [29] { function: getFullYear target: { - IDENT [40] { - name: @index13 + IDENT [30] { + name: @index3 } } args: { @@ -447,11 +384,11 @@ CALL [1] { } } } - CALL [41] { + CALL [31] { function: getFullYear target: { - IDENT [42] { - name: @index6 + IDENT [32] { + name: @index2 } } args: { @@ -459,16 +396,16 @@ CALL [1] { } } } - IDENT [43] { - name: @index3 + IDENT [33] { + name: @index0 } } } - CALL [44] { + CALL [34] { function: getSeconds target: { - IDENT [45] { - name: @index6 + IDENT [35] { + name: @index2 } } args: { @@ -476,21 +413,21 @@ CALL [1] { } } } - IDENT [46] { - name: @index10 + IDENT [36] { + name: @index1 } } } - IDENT [47] { - name: @index10 + IDENT [37] { + name: @index1 } } } - CALL [48] { + CALL [38] { function: getMinutes target: { - IDENT [49] { - name: @index13 + IDENT [39] { + name: @index3 } } args: { @@ -498,26 +435,23 @@ CALL [1] { } } } - CALL [50] { + } + } + CALL [40] { + function: _==_ + args: { + CALL [41] { function: _+_ args: { - IDENT [51] { - name: @index14 + IDENT [42] { + name: @index4 } - IDENT [52] { - name: @index3 + IDENT [43] { + name: @index0 } } } - } - } - CALL [53] { - function: _==_ - args: { - IDENT [54] { - name: @index15 - } - CONSTANT [55] { value: 13934 } + CONSTANT [44] { value: 13934 } } } } @@ -530,53 +464,47 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_MAP [3] { - MAP_ENTRY [4] { - key: { - CONSTANT [5] { value: "a" } - } - value: { - CONSTANT [6] { value: 2 } - } - } - } - CALL [7] { + CALL [3] { function: _[_] args: { - IDENT [8] { - name: @index0 + CREATE_MAP [4] { + MAP_ENTRY [5] { + key: { + CONSTANT [6] { value: "a" } + } + value: { + CONSTANT [7] { value: 2 } + } + } } - CONSTANT [9] { value: "a" } + CONSTANT [8] { value: "a" } } } + } + } + CALL [9] { + function: _==_ + args: { CALL [10] { function: _+_ args: { IDENT [11] { - name: @index1 + name: @index0 } CALL [12] { function: _*_ args: { IDENT [13] { - name: @index1 + name: @index0 } IDENT [14] { - name: @index1 + name: @index0 } } } } } - } - } - CALL [15] { - function: _==_ - args: { - IDENT [16] { - name: @index2 - } - CONSTANT [17] { value: 6 } + CONSTANT [15] { value: 6 } } } } @@ -592,51 +520,48 @@ CALL [1] { CREATE_MAP [3] { MAP_ENTRY [4] { key: { - CONSTANT [5] { value: "b" } + CONSTANT [5] { value: "e" } } value: { - CONSTANT [6] { value: 1 } + CREATE_MAP [6] { + MAP_ENTRY [7] { + key: { + CONSTANT [8] { value: "b" } + } + value: { + CONSTANT [9] { value: 1 } + } + } + } } } } - CREATE_MAP [7] { - MAP_ENTRY [8] { + CREATE_MAP [10] { + MAP_ENTRY [11] { key: { - CONSTANT [9] { value: "e" } + CONSTANT [12] { value: "b" } } value: { - IDENT [10] { - name: @index0 - } + CONSTANT [13] { value: 1 } } } } } } - CREATE_MAP [11] { - MAP_ENTRY [12] { - key: { - CONSTANT [13] { value: "a" } - } - value: { - IDENT [14] { - name: @index0 - } - } - } + CREATE_MAP [14] { MAP_ENTRY [15] { key: { - CONSTANT [16] { value: "c" } + CONSTANT [16] { value: "a" } } value: { IDENT [17] { - name: @index0 + name: @index1 } } } MAP_ENTRY [18] { key: { - CONSTANT [19] { value: "d" } + CONSTANT [19] { value: "c" } } value: { IDENT [20] { @@ -646,11 +571,21 @@ CALL [1] { } MAP_ENTRY [21] { key: { - CONSTANT [22] { value: "e" } + CONSTANT [22] { value: "d" } } value: { IDENT [23] { - name: @index1 + name: @index0 + } + } + } + MAP_ENTRY [24] { + key: { + CONSTANT [25] { value: "e" } + } + value: { + IDENT [26] { + name: @index0 } } } @@ -679,37 +614,34 @@ CALL [1] { CONSTANT [10] { value: 2 } } } - CREATE_LIST [11] { - elements: { - IDENT [12] { - name: @index1 - } - IDENT [13] { - name: @index0 - } - } - } } } - CREATE_LIST [14] { + CREATE_LIST [11] { elements: { - CONSTANT [15] { value: 1 } - IDENT [16] { + CONSTANT [12] { value: 1 } + IDENT [13] { name: @index0 } - CONSTANT [17] { value: 2 } - IDENT [18] { + CONSTANT [14] { value: 2 } + IDENT [15] { name: @index0 } - CONSTANT [19] { value: 5 } - IDENT [20] { + CONSTANT [16] { value: 5 } + IDENT [17] { name: @index0 } - CONSTANT [21] { value: 7 } - IDENT [22] { - name: @index2 + CONSTANT [18] { value: 7 } + CREATE_LIST [19] { + elements: { + IDENT [20] { + name: @index1 + } + IDENT [21] { + name: @index0 + } + } } - IDENT [23] { + IDENT [22] { name: @index1 } } @@ -729,26 +661,23 @@ CALL [1] { name: msg }.single_int64 } - CALL [5] { + } + } + CALL [5] { + function: _==_ + args: { + CALL [6] { function: _+_ args: { - IDENT [6] { + IDENT [7] { name: @index0 } - IDENT [7] { + IDENT [8] { name: @index0 } } } - } - } - CALL [8] { - function: _==_ - args: { - IDENT [9] { - name: @index1 - } - CONSTANT [10] { value: 6 } + CONSTANT [9] { value: 6 } } } } @@ -762,58 +691,64 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload + SELECT [4] { + SELECT [5] { + IDENT [6] { + name: msg + }.oneof_type + }.payload + }.single_int64 } SELECT [7] { - IDENT [8] { - name: @index1 - }.single_int64 + SELECT [8] { + IDENT [9] { + name: msg + }.oneof_type + }.payload } - CALL [9] { + } + } + CALL [10] { + function: _==_ + args: { + CALL [11] { function: _+_ args: { - CALL [10] { + CALL [12] { function: _+_ args: { - CALL [11] { + CALL [13] { function: _+_ args: { - CALL [12] { + CALL [14] { function: _+_ args: { - IDENT [13] { - name: @index2 + IDENT [15] { + name: @index0 } - SELECT [14] { - IDENT [15] { + SELECT [16] { + IDENT [17] { name: @index1 }.single_int32 } } } - IDENT [16] { - name: @index2 + IDENT [18] { + name: @index0 } } } - SELECT [17] { - IDENT [18] { + SELECT [19] { + IDENT [20] { name: msg }.single_int64 } } } - SELECT [19] { - SELECT [20] { - SELECT [21] { - IDENT [22] { + SELECT [21] { + SELECT [22] { + SELECT [23] { + IDENT [24] { name: @index1 }.oneof_type }.payload @@ -821,14 +756,6 @@ CALL [1] { } } } - } - } - CALL [23] { - function: _==_ - args: { - IDENT [24] { - name: @index3 - } CONSTANT [25] { value: 31 } } } @@ -843,51 +770,33 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload - } - SELECT [7] { - IDENT [8] { - name: @index1 - }.oneof_type - } - SELECT [9] { - IDENT [10] { - name: @index2 - }.payload - } - SELECT [11] { - IDENT [12] { - name: @index3 - }.oneof_type - } - SELECT [13] { - SELECT [14] { - SELECT [15] { - SELECT [16] { - IDENT [17] { - name: @index4 - }.child - }.child + SELECT [4] { + SELECT [5] { + SELECT [6] { + SELECT [7] { + IDENT [8] { + name: msg + }.oneof_type + }.payload + }.oneof_type }.payload - }.single_bool + }.oneof_type } - CALL [18] { + } + } + CALL [9] { + function: _||_ + args: { + CALL [10] { function: _||_ args: { - CONSTANT [19] { value: true } - SELECT [20] { - SELECT [21] { - SELECT [22] { - SELECT [23] { - IDENT [24] { - name: @index4 + CONSTANT [11] { value: true } + SELECT [12] { + SELECT [13] { + SELECT [14] { + SELECT [15] { + IDENT [16] { + name: @index0 }.payload }.oneof_type }.payload @@ -895,16 +804,16 @@ CALL [1] { } } } - } - } - CALL [25] { - function: _||_ - args: { - IDENT [26] { - name: @index6 - } - IDENT [27] { - name: @index5 + SELECT [17] { + SELECT [18] { + SELECT [19] { + SELECT [20] { + IDENT [21] { + name: @index0 + }.child + }.child + }.payload + }.single_bool } } } @@ -918,58 +827,46 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload - } - SELECT [7] { - IDENT [8] { - name: @index1 - }.map_int32_int64 - } - CALL [9] { + CALL [3] { function: _[_] args: { - IDENT [10] { - name: @index2 + SELECT [4] { + SELECT [5] { + SELECT [6] { + IDENT [7] { + name: msg + }.oneof_type + }.payload + }.map_int32_int64 } - CONSTANT [11] { value: 1 } + CONSTANT [8] { value: 1 } } } - CALL [12] { + } + } + CALL [9] { + function: _==_ + args: { + CALL [10] { function: _+_ args: { - CALL [13] { + CALL [11] { function: _+_ args: { - IDENT [14] { - name: @index3 + IDENT [12] { + name: @index0 } - IDENT [15] { - name: @index3 + IDENT [13] { + name: @index0 } } } - IDENT [16] { - name: @index3 + IDENT [14] { + name: @index0 } } } - } - } - CALL [17] { - function: _==_ - args: { - IDENT [18] { - name: @index4 - } - CONSTANT [19] { value: 15 } + CONSTANT [15] { value: 15 } } } } @@ -983,66 +880,57 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload - } - SELECT [7] { - IDENT [8] { - name: @index1 + SELECT [4] { + SELECT [5] { + IDENT [6] { + name: msg + }.oneof_type + }.payload }.map_int32_int64 } - CALL [9] { + } + } + CALL [7] { + function: _==_ + args: { + CALL [8] { function: _+_ args: { - CALL [10] { + CALL [9] { function: _+_ args: { - CALL [11] { + CALL [10] { function: _[_] args: { - IDENT [12] { - name: @index2 + IDENT [11] { + name: @index0 } - CONSTANT [13] { value: 0 } + CONSTANT [12] { value: 0 } } } - CALL [14] { + CALL [13] { function: _[_] args: { - IDENT [15] { - name: @index2 + IDENT [14] { + name: @index0 } - CONSTANT [16] { value: 1 } + CONSTANT [15] { value: 1 } } } } } - CALL [17] { + CALL [16] { function: _[_] args: { - IDENT [18] { - name: @index2 + IDENT [17] { + name: @index0 } - CONSTANT [19] { value: 2 } + CONSTANT [18] { value: 2 } } } } } - } - } - CALL [20] { - function: _==_ - args: { - IDENT [21] { - name: @index3 - } - CONSTANT [22] { value: 8 } + CONSTANT [19] { value: 8 } } } } @@ -1096,33 +984,30 @@ CALL [1] { name: msg }.single_int64 } - CALL [5] { + } + } + CALL [5] { + function: _==_ + args: { + CALL [6] { function: _?_:_ args: { - CALL [6] { + CALL [7] { function: _>_ args: { - IDENT [7] { + IDENT [8] { name: @index0 } - CONSTANT [8] { value: 0 } + CONSTANT [9] { value: 0 } } } - IDENT [9] { + IDENT [10] { name: @index0 } - CONSTANT [10] { value: 0 } + CONSTANT [11] { value: 0 } } } - } - } - CALL [11] { - function: _==_ - args: { - IDENT [12] { - name: @index1 - } - CONSTANT [13] { value: 3 } + CONSTANT [12] { value: 3 } } } } @@ -1140,47 +1025,44 @@ CALL [1] { name: msg }.single_int64 } - CALL [5] { + } + } + CALL [5] { + function: _?_:_ + args: { + CONSTANT [6] { value: false } + CONSTANT [7] { value: false } + CALL [8] { function: _==_ args: { - CALL [6] { + CALL [9] { function: _+_ args: { - IDENT [7] { + IDENT [10] { name: @index0 } - CALL [8] { + CALL [11] { function: _*_ args: { - CALL [9] { + CALL [12] { function: _+_ args: { - IDENT [10] { + IDENT [13] { name: @index0 } - CONSTANT [11] { value: 1 } + CONSTANT [14] { value: 1 } } } - CONSTANT [12] { value: 2 } + CONSTANT [15] { value: 2 } } } } } - CONSTANT [13] { value: 11 } + CONSTANT [16] { value: 11 } } } } } - CALL [14] { - function: _?_:_ - args: { - CONSTANT [15] { value: false } - CONSTANT [16] { value: false } - IDENT [17] { - name: @index1 - } - } - } } } Test case: NESTED_TERNARY @@ -1201,56 +1083,53 @@ CALL [1] { name: msg }.single_int32 } - CALL [7] { + } + } + CALL [7] { + function: _==_ + args: { + CALL [8] { function: _?_:_ args: { - CALL [8] { + CALL [9] { function: _>_ args: { - IDENT [9] { + IDENT [10] { name: @index0 } - CONSTANT [10] { value: 0 } + CONSTANT [11] { value: 0 } } } - CALL [11] { + CALL [12] { function: _?_:_ args: { - CALL [12] { + CALL [13] { function: _>_ args: { - IDENT [13] { + IDENT [14] { name: @index1 } - CONSTANT [14] { value: 0 } + CONSTANT [15] { value: 0 } } } - CALL [15] { + CALL [16] { function: _+_ args: { - IDENT [16] { + IDENT [17] { name: @index0 } - IDENT [17] { + IDENT [18] { name: @index1 } } } - CONSTANT [18] { value: 0 } + CONSTANT [19] { value: 0 } } } - CONSTANT [19] { value: 0 } + CONSTANT [20] { value: 0 } } } - } - } - CALL [20] { - function: _==_ - args: { - IDENT [21] { - name: @index2 - } - CONSTANT [22] { value: 8 } + CONSTANT [21] { value: 8 } } } } @@ -1263,343 +1142,318 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_LIST [3] { - elements: { - CONSTANT [4] { value: 1 } + CALL [3] { + function: size + args: { + CREATE_LIST [4] { + elements: { + COMPREHENSION [5] { + iter_var: @c0:0 + iter_range: { + CREATE_LIST [6] { + elements: { + CONSTANT [7] { value: 1 } + } + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [8] { value: false } + } + loop_condition: { + CALL [9] { + function: @not_strictly_false + args: { + CALL [10] { + function: !_ + args: { + IDENT [11] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + CALL [12] { + function: _||_ + args: { + IDENT [13] { + name: @x0:0 + } + CALL [14] { + function: _>_ + args: { + IDENT [15] { + name: @c0:0 + } + CONSTANT [16] { value: 0 } + } + } + } + } + } + result: { + IDENT [17] { + name: @x0:0 + } + } + } + } + } } } - CALL [5] { - function: _>_ + CALL [18] { + function: size args: { - IDENT [6] { - name: @c0:0 + CREATE_LIST [19] { + elements: { + COMPREHENSION [20] { + iter_var: @c0:0 + iter_range: { + CREATE_LIST [21] { + elements: { + CONSTANT [22] { value: 2 } + } + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [23] { value: false } + } + loop_condition: { + CALL [24] { + function: @not_strictly_false + args: { + CALL [25] { + function: !_ + args: { + IDENT [26] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + CALL [27] { + function: _||_ + args: { + IDENT [28] { + name: @x0:0 + } + CALL [29] { + function: _>_ + args: { + IDENT [30] { + name: @c0:0 + } + CONSTANT [31] { value: 1 } + } + } + } + } + } + result: { + IDENT [32] { + name: @x0:0 + } + } + } + } } - CONSTANT [7] { value: 0 } } } - CALL [8] { - function: _||_ + } + } + CALL [33] { + function: _==_ + args: { + CALL [34] { + function: _+_ args: { - IDENT [9] { - name: @x0:0 + CALL [35] { + function: _+_ + args: { + CALL [36] { + function: _+_ + args: { + IDENT [37] { + name: @index0 + } + IDENT [38] { + name: @index0 + } + } + } + IDENT [39] { + name: @index1 + } + } } - IDENT [10] { + IDENT [40] { name: @index1 } } } - COMPREHENSION [11] { - iter_var: @c0:0 - iter_range: { - IDENT [12] { - name: @index0 - } - } - accu_var: @x0:0 - accu_init: { - CONSTANT [13] { value: false } - } - loop_condition: { - CALL [14] { - function: @not_strictly_false - args: { - CALL [15] { - function: !_ + CONSTANT [41] { value: 4 } + } + } + } +} +Test case: MULTIPLE_MACROS_2 +Source: [[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == 'a')] + [['a'].exists(l, l == 'a')] == [true, true, true, true] +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_LIST [3] { + elements: { + COMPREHENSION [4] { + iter_var: @c0:0 + iter_range: { + CREATE_LIST [5] { + elements: { + CONSTANT [6] { value: 1 } + } + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [7] { value: false } + } + loop_condition: { + CALL [8] { + function: @not_strictly_false args: { - IDENT [16] { + CALL [9] { + function: !_ + args: { + IDENT [10] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + CALL [11] { + function: _||_ + args: { + IDENT [12] { name: @x0:0 } + CALL [13] { + function: _>_ + args: { + IDENT [14] { + name: @c0:0 + } + CONSTANT [15] { value: 0 } + } + } } } } - } - } - loop_step: { - IDENT [17] { - name: @index2 - } - } - result: { - IDENT [18] { - name: @x0:0 - } - } - } - CREATE_LIST [19] { - elements: { - IDENT [20] { - name: @index3 - } - } - } - CALL [21] { - function: size - args: { - IDENT [22] { - name: @index4 + result: { + IDENT [16] { + name: @x0:0 + } + } } } } - CREATE_LIST [23] { + CREATE_LIST [17] { elements: { - CONSTANT [24] { value: 2 } - } - } - CALL [25] { - function: _>_ - args: { - IDENT [26] { - name: @c0:0 - } - CONSTANT [27] { value: 1 } - } - } - CALL [28] { - function: _||_ - args: { - IDENT [29] { - name: @x0:0 - } - IDENT [30] { - name: @index7 - } - } - } - COMPREHENSION [31] { - iter_var: @c0:0 - iter_range: { - IDENT [32] { - name: @index6 - } - } - accu_var: @x0:0 - accu_init: { - CONSTANT [33] { value: false } - } - loop_condition: { - CALL [34] { - function: @not_strictly_false - args: { - CALL [35] { - function: !_ + COMPREHENSION [18] { + iter_var: @c0:1 + iter_range: { + CREATE_LIST [19] { + elements: { + CONSTANT [20] { value: "a" } + } + } + } + accu_var: @x0:1 + accu_init: { + CONSTANT [21] { value: false } + } + loop_condition: { + CALL [22] { + function: @not_strictly_false args: { - IDENT [36] { - name: @x0:0 + CALL [23] { + function: !_ + args: { + IDENT [24] { + name: @x0:1 + } + } } } } } - } - } - loop_step: { - IDENT [37] { - name: @index8 - } - } - result: { - IDENT [38] { - name: @x0:0 - } - } - } - CREATE_LIST [39] { - elements: { - IDENT [40] { - name: @index9 - } - } - } - CALL [41] { - function: size - args: { - IDENT [42] { - name: @index10 - } - } - } - CALL [43] { - function: _+_ - args: { - CALL [44] { - function: _+_ - args: { - CALL [45] { - function: _+_ + loop_step: { + CALL [25] { + function: _||_ args: { - IDENT [46] { - name: @index5 + IDENT [26] { + name: @x0:1 } - IDENT [47] { - name: @index5 + CALL [27] { + function: _==_ + args: { + IDENT [28] { + name: @c0:1 + } + CONSTANT [29] { value: "a" } + } } } } - IDENT [48] { - name: @index11 + } + result: { + IDENT [30] { + name: @x0:1 } } } - IDENT [49] { - name: @index11 - } } } } } - CALL [50] { + CALL [31] { function: _==_ args: { - IDENT [51] { - name: @index12 - } - CONSTANT [52] { value: 4 } - } - } - } -} -Test case: MULTIPLE_MACROS_2 -Source: [[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == 'a')] + [['a'].exists(l, l == 'a')] == [true, true, true, true] -=====> -CALL [1] { - function: cel.@block - args: { - CREATE_LIST [2] { - elements: { - CREATE_LIST [3] { - elements: { - CONSTANT [4] { value: 1 } - } - } - CALL [5] { - function: _>_ - args: { - IDENT [6] { - name: @c0:0 - } - CONSTANT [7] { value: 0 } - } - } - CALL [8] { - function: _||_ + CALL [32] { + function: _+_ args: { - IDENT [9] { - name: @x0:0 - } - IDENT [10] { - name: @index1 - } - } - } - COMPREHENSION [11] { - iter_var: @c0:0 - iter_range: { - IDENT [12] { - name: @index0 - } - } - accu_var: @x0:0 - accu_init: { - CONSTANT [13] { value: false } - } - loop_condition: { - CALL [14] { - function: @not_strictly_false + CALL [33] { + function: _+_ args: { - CALL [15] { - function: !_ + CALL [34] { + function: _+_ args: { - IDENT [16] { - name: @x0:0 + IDENT [35] { + name: @index0 } - } - } - } - } - } - loop_step: { - IDENT [17] { - name: @index2 - } - } - result: { - IDENT [18] { - name: @x0:0 - } - } - } - CREATE_LIST [19] { - elements: { - IDENT [20] { - name: @index3 - } - } - } - CREATE_LIST [21] { - elements: { - CONSTANT [22] { value: "a" } - } - } - CALL [23] { - function: _==_ - args: { - IDENT [24] { - name: @c0:1 - } - CONSTANT [25] { value: "a" } - } - } - CALL [26] { - function: _||_ - args: { - IDENT [27] { - name: @x0:1 - } - IDENT [28] { - name: @index6 - } - } - } - COMPREHENSION [29] { - iter_var: @c0:1 - iter_range: { - IDENT [30] { - name: @index5 - } - } - accu_var: @x0:1 - accu_init: { - CONSTANT [31] { value: false } - } - loop_condition: { - CALL [32] { - function: @not_strictly_false - args: { - CALL [33] { - function: !_ - args: { - IDENT [34] { - name: @x0:1 + IDENT [36] { + name: @index0 } } } + IDENT [37] { + name: @index1 + } } } - } - loop_step: { - IDENT [35] { - name: @index7 - } - } - result: { - IDENT [36] { - name: @x0:1 - } - } - } - CREATE_LIST [37] { - elements: { IDENT [38] { - name: @index8 + name: @index1 } } } @@ -1611,44 +1465,6 @@ CALL [1] { CONSTANT [43] { value: true } } } - CALL [44] { - function: _+_ - args: { - CALL [45] { - function: _+_ - args: { - CALL [46] { - function: _+_ - args: { - IDENT [47] { - name: @index4 - } - IDENT [48] { - name: @index4 - } - } - } - IDENT [49] { - name: @index9 - } - } - } - IDENT [50] { - name: @index9 - } - } - } - } - } - CALL [51] { - function: _==_ - args: { - IDENT [52] { - name: @index11 - } - IDENT [53] { - name: @index10 - } } } } @@ -1675,78 +1491,70 @@ CALL [1] { CONSTANT [10] { value: 4 } } } - CREATE_LIST [11] { - elements: { - IDENT [12] { - name: @index1 - } - IDENT [13] { - name: @index1 - } - IDENT [14] { - name: @index1 - } - } - } - COMPREHENSION [15] { + } + } + CALL [11] { + function: _==_ + args: { + COMPREHENSION [12] { iter_var: @c0:0 iter_range: { - IDENT [16] { + IDENT [13] { name: @index0 } } accu_var: @x0:0 accu_init: { - CREATE_LIST [17] { + CREATE_LIST [14] { elements: { } } } loop_condition: { - CONSTANT [18] { value: true } + CONSTANT [15] { value: true } } loop_step: { - CALL [19] { + CALL [16] { function: _+_ args: { - IDENT [20] { + IDENT [17] { name: @x0:0 } - CREATE_LIST [21] { + CREATE_LIST [18] { elements: { - COMPREHENSION [22] { + COMPREHENSION [19] { iter_var: @c1:0 iter_range: { - IDENT [23] { + IDENT [20] { name: @index0 } } accu_var: @x1:0 accu_init: { - CREATE_LIST [24] { + CREATE_LIST [21] { elements: { } } } loop_condition: { - CONSTANT [25] { value: true } + CONSTANT [22] { value: true } } loop_step: { - CALL [26] { + CALL [23] { function: _+_ args: { - IDENT [27] { + IDENT [24] { name: @x1:0 } - CREATE_LIST [28] { + CREATE_LIST [25] { elements: { - CALL [29] { + CALL [26] { function: _+_ args: { - IDENT [30] { + IDENT [27] { name: @c1:0 } - CONSTANT [31] { value: 1 } + CONSTANT [28] { value: 1 } } } } @@ -1755,7 +1563,7 @@ CALL [1] { } } result: { - IDENT [32] { + IDENT [29] { name: @x1:0 } } @@ -1766,21 +1574,23 @@ CALL [1] { } } result: { - IDENT [33] { + IDENT [30] { name: @x0:0 } } } - } - } - CALL [34] { - function: _==_ - args: { - IDENT [35] { - name: @index3 - } - IDENT [36] { - name: @index2 + CREATE_LIST [31] { + elements: { + IDENT [32] { + name: @index1 + } + IDENT [33] { + name: @index1 + } + IDENT [34] { + name: @index1 + } + } } } } @@ -1789,138 +1599,123 @@ CALL [1] { Test case: NESTED_MACROS_2 Source: [1, 2].map(y, [1, 2, 3].filter(x, x == y)) == [[1], [2]] =====> -CALL [1] { - function: cel.@block +CALL [31] { + function: _==_ args: { - CREATE_LIST [2] { - elements: { - CREATE_LIST [3] { + COMPREHENSION [30] { + iter_var: @c0:0 + iter_range: { + CREATE_LIST [1] { elements: { - CREATE_LIST [4] { - elements: { - CONSTANT [5] { value: 1 } - } - } - CREATE_LIST [6] { - elements: { - CONSTANT [7] { value: 2 } - } - } + CONSTANT [2] { value: 1 } + CONSTANT [3] { value: 2 } } } - COMPREHENSION [8] { - iter_var: @c0:0 - iter_range: { - CREATE_LIST [9] { - elements: { - CONSTANT [10] { value: 1 } - CONSTANT [11] { value: 2 } - } - } + } + accu_var: @x0:0 + accu_init: { + CREATE_LIST [24] { + elements: { } - accu_var: @x0:0 - accu_init: { - CREATE_LIST [12] { - elements: { - } + } + } + loop_condition: { + CONSTANT [25] { value: true } + } + loop_step: { + CALL [28] { + function: _+_ + args: { + IDENT [26] { + name: @x0:0 } - } - loop_condition: { - CONSTANT [13] { value: true } - } - loop_step: { - CALL [14] { - function: _+_ - args: { - IDENT [15] { - name: @x0:0 - } - CREATE_LIST [16] { - elements: { - COMPREHENSION [17] { - iter_var: @c1:0 - iter_range: { - CREATE_LIST [18] { - elements: { - CONSTANT [19] { value: 1 } - CONSTANT [20] { value: 2 } - CONSTANT [21] { value: 3 } - } - } + CREATE_LIST [27] { + elements: { + COMPREHENSION [23] { + iter_var: @c1:0 + iter_range: { + CREATE_LIST [6] { + elements: { + CONSTANT [7] { value: 1 } + CONSTANT [8] { value: 2 } + CONSTANT [9] { value: 3 } } - accu_var: @x1:0 - accu_init: { - CREATE_LIST [22] { - elements: { + } + } + accu_var: @x1:0 + accu_init: { + CREATE_LIST [15] { + elements: { + } + } + } + loop_condition: { + CONSTANT [16] { value: true } + } + loop_step: { + CALL [21] { + function: _?_:_ + args: { + CALL [13] { + function: _==_ + args: { + IDENT [12] { + name: @c1:0 + } + IDENT [14] { + name: @c0:0 + } } } - } - loop_condition: { - CONSTANT [23] { value: true } - } - loop_step: { - CALL [24] { - function: _?_:_ + CALL [19] { + function: _+_ args: { - CALL [25] { - function: _==_ - args: { - IDENT [26] { - name: @c1:0 - } - IDENT [27] { - name: @c0:0 - } - } + IDENT [17] { + name: @x1:0 } - CALL [28] { - function: _+_ - args: { - IDENT [29] { - name: @x1:0 - } - CREATE_LIST [30] { - elements: { - IDENT [31] { - name: @c1:0 - } - } + CREATE_LIST [18] { + elements: { + IDENT [11] { + name: @c1:0 } } } - IDENT [32] { - name: @x1:0 - } } } - } - result: { - IDENT [33] { + IDENT [20] { name: @x1:0 } } } } + result: { + IDENT [22] { + name: @x1:0 + } + } } } } } - result: { - IDENT [34] { - name: @x0:0 - } - } + } + } + result: { + IDENT [29] { + name: @x0:0 } } } - CALL [35] { - function: _==_ - args: { - IDENT [36] { - name: @index1 + CREATE_LIST [32] { + elements: { + CREATE_LIST [33] { + elements: { + CONSTANT [34] { value: 1 } + } } - IDENT [37] { - name: @index0 + CREATE_LIST [35] { + elements: { + CONSTANT [36] { value: 2 } + } } } } @@ -1934,74 +1729,72 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_LIST [3] { - elements: { - CONSTANT [4] { value: 1 } - CONSTANT [5] { value: 2 } - CONSTANT [6] { value: 3 } - } - } - CALL [7] { + CALL [3] { function: @in args: { - CONSTANT [8] { value: 1 } - IDENT [9] { - name: @index0 + CONSTANT [4] { value: 1 } + CREATE_LIST [5] { + elements: { + CONSTANT [6] { value: 1 } + CONSTANT [7] { value: 2 } + CONSTANT [8] { value: 3 } + } } } } - CALL [10] { + CREATE_LIST [9] { + elements: { + CONSTANT [10] { value: 1 } + CONSTANT [11] { value: 2 } + CONSTANT [12] { value: 3 } + } + } + } + } + CALL [13] { + function: _&&_ + args: { + CALL [14] { function: _&&_ args: { - CALL [11] { + IDENT [15] { + name: @index0 + } + CALL [16] { function: @in args: { - CONSTANT [12] { value: 3 } - CREATE_LIST [13] { - elements: { - CONSTANT [14] { value: 3 } - IDENT [15] { - name: @index0 - } - } + CONSTANT [17] { value: 2 } + IDENT [18] { + name: @index1 } } } - IDENT [16] { - name: @index1 - } } } - CALL [17] { + CALL [19] { function: _&&_ args: { - IDENT [18] { - name: @index1 - } - CALL [19] { + CALL [20] { function: @in args: { - CONSTANT [20] { value: 2 } - IDENT [21] { - name: @index0 + CONSTANT [21] { value: 3 } + CREATE_LIST [22] { + elements: { + CONSTANT [23] { value: 3 } + IDENT [24] { + name: @index1 + } + } } } } + IDENT [25] { + name: @index0 + } } } } } - CALL [22] { - function: _&&_ - args: { - IDENT [23] { - name: @index3 - } - IDENT [24] { - name: @index2 - } - } - } } } Test case: INCLUSION_MAP @@ -2022,31 +1815,37 @@ CALL [1] { } } } - CREATE_MAP [7] { - MAP_ENTRY [8] { + } + } + CALL [7] { + function: @in + args: { + CONSTANT [8] { value: 2 } + CREATE_MAP [9] { + MAP_ENTRY [10] { key: { - CONSTANT [9] { value: "a" } + CONSTANT [11] { value: "a" } } value: { - CONSTANT [10] { value: 1 } + CONSTANT [12] { value: 1 } } } - MAP_ENTRY [11] { + MAP_ENTRY [13] { key: { - CONSTANT [12] { value: 2 } + CONSTANT [14] { value: 2 } } value: { - IDENT [13] { + IDENT [15] { name: @index0 } } } - MAP_ENTRY [14] { + MAP_ENTRY [16] { key: { - CONSTANT [15] { value: 3 } + CONSTANT [17] { value: 3 } } value: { - IDENT [16] { + IDENT [18] { name: @index0 } } @@ -2054,15 +1853,6 @@ CALL [1] { } } } - CALL [17] { - function: @in - args: { - CONSTANT [18] { value: 2 } - IDENT [19] { - name: @index1 - } - } - } } } Test case: MACRO_ITER_VAR_NOT_REFERENCED @@ -2075,90 +1865,88 @@ CALL [1] { elements: { CREATE_LIST [3] { elements: { - CONSTANT [4] { value: 1 } - CONSTANT [5] { value: 2 } - } - } - CREATE_LIST [6] { - elements: { - CONSTANT [7] { value: 3 } - CONSTANT [8] { value: 4 } - } - } - CREATE_LIST [9] { - elements: { - IDENT [10] { - name: @index1 + CREATE_LIST [4] { + elements: { + CONSTANT [5] { value: 3 } + CONSTANT [6] { value: 4 } + } } - IDENT [11] { - name: @index1 + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 3 } + CONSTANT [9] { value: 4 } + } } } } - CREATE_LIST [12] { + CREATE_LIST [10] { elements: { - IDENT [13] { - name: @index2 - } - IDENT [14] { - name: @index2 - } + CONSTANT [11] { value: 1 } + CONSTANT [12] { value: 2 } } } - COMPREHENSION [15] { + } + } + CALL [13] { + function: _==_ + args: { + COMPREHENSION [14] { iter_var: @c0:0 iter_range: { - IDENT [16] { - name: @index0 + IDENT [15] { + name: @index1 } } accu_var: @x0:0 accu_init: { - CREATE_LIST [17] { + CREATE_LIST [16] { elements: { } } } loop_condition: { - CONSTANT [18] { value: true } + CONSTANT [17] { value: true } } loop_step: { - CALL [19] { + CALL [18] { function: _+_ args: { - IDENT [20] { + IDENT [19] { name: @x0:0 } - CREATE_LIST [21] { + CREATE_LIST [20] { elements: { - COMPREHENSION [22] { + COMPREHENSION [21] { iter_var: @c1:0 iter_range: { - IDENT [23] { - name: @index0 + IDENT [22] { + name: @index1 } } accu_var: @x1:0 accu_init: { - CREATE_LIST [24] { + CREATE_LIST [23] { elements: { } } } loop_condition: { - CONSTANT [25] { value: true } + CONSTANT [24] { value: true } } loop_step: { - CALL [26] { + CALL [25] { function: _+_ args: { - IDENT [27] { + IDENT [26] { name: @x1:0 } - CREATE_LIST [28] { + CREATE_LIST [27] { elements: { - IDENT [29] { - name: @index1 + CREATE_LIST [28] { + elements: { + CONSTANT [29] { value: 3 } + CONSTANT [30] { value: 4 } + } } } } @@ -2166,7 +1954,7 @@ CALL [1] { } } result: { - IDENT [30] { + IDENT [31] { name: @x1:0 } } @@ -2177,21 +1965,20 @@ CALL [1] { } } result: { - IDENT [31] { + IDENT [32] { name: @x0:0 } } } - } - } - CALL [32] { - function: _==_ - args: { - IDENT [33] { - name: @index4 - } - IDENT [34] { - name: @index3 + CREATE_LIST [33] { + elements: { + IDENT [34] { + name: @index0 + } + IDENT [35] { + name: @index0 + } + } } } } @@ -2206,23 +1993,25 @@ CALL [1] { CREATE_LIST [2] { elements: { CALL [3] { - function: _-_ - args: { - IDENT [4] { - name: x - } - CONSTANT [5] { value: 1 } - } - } - CALL [6] { function: _>_ args: { - IDENT [7] { - name: @index0 + CALL [4] { + function: _-_ + args: { + IDENT [5] { + name: x + } + CONSTANT [6] { value: 1 } + } } - CONSTANT [8] { value: 3 } + CONSTANT [7] { value: 3 } } } + } + } + CALL [8] { + function: _||_ + args: { COMPREHENSION [9] { iter_var: @c0:0 iter_range: { @@ -2232,12 +2021,18 @@ CALL [1] { function: _?_:_ args: { IDENT [12] { - name: @index1 - } - IDENT [13] { name: @index0 } - CONSTANT [14] { value: 5 } + CALL [13] { + function: _-_ + args: { + IDENT [14] { + name: x + } + CONSTANT [15] { value: 1 } + } + } + CONSTANT [16] { value: 5 } } } } @@ -2245,16 +2040,16 @@ CALL [1] { } accu_var: @x0:0 accu_init: { - CONSTANT [15] { value: false } + CONSTANT [17] { value: false } } loop_condition: { - CALL [16] { + CALL [18] { function: @not_strictly_false args: { - CALL [17] { + CALL [19] { function: !_ args: { - IDENT [18] { + IDENT [20] { name: @x0:0 } } @@ -2263,46 +2058,38 @@ CALL [1] { } } loop_step: { - CALL [19] { + CALL [21] { function: _||_ args: { - IDENT [20] { + IDENT [22] { name: @x0:0 } - CALL [21] { + CALL [23] { function: _>_ args: { - CALL [22] { + CALL [24] { function: _-_ args: { - IDENT [23] { + IDENT [25] { name: @c0:0 } - CONSTANT [24] { value: 1 } + CONSTANT [26] { value: 1 } } } - CONSTANT [25] { value: 3 } + CONSTANT [27] { value: 3 } } } } } } result: { - IDENT [26] { + IDENT [28] { name: @x0:0 } } } - } - } - CALL [27] { - function: _||_ - args: { - IDENT [28] { - name: @index2 - } IDENT [29] { - name: @index1 + name: @index0 } } } @@ -2338,63 +2125,46 @@ CALL [1] { } } } - CALL [9] { - function: _+_ - args: { - IDENT [10] { - name: @x0:0 - } - CREATE_LIST [11] { - elements: { - CREATE_LIST [12] { - elements: { - IDENT [13] { - name: @index1 - } - IDENT [14] { - name: @index1 - } - } - } - } - } - } - } - COMPREHENSION [15] { + } + } + COMPREHENSION [9] { + iter_var: @c0:0 + iter_range: { + COMPREHENSION [10] { iter_var: @c1:0 iter_range: { - CREATE_LIST [16] { + CREATE_LIST [11] { elements: { - CONSTANT [17] { value: "foo" } - CONSTANT [18] { value: "bar" } + CONSTANT [12] { value: "foo" } + CONSTANT [13] { value: "bar" } } } } accu_var: @x1:0 accu_init: { - CREATE_LIST [19] { + CREATE_LIST [14] { elements: { } } } loop_condition: { - CONSTANT [20] { value: true } + CONSTANT [15] { value: true } } loop_step: { - CALL [21] { + CALL [16] { function: _+_ args: { - IDENT [22] { + IDENT [17] { name: @x1:0 } - CREATE_LIST [23] { + CREATE_LIST [18] { elements: { - CREATE_LIST [24] { + CREATE_LIST [19] { elements: { - IDENT [25] { + IDENT [20] { name: @index0 } - IDENT [26] { + IDENT [21] { name: @index0 } } @@ -2405,37 +2175,48 @@ CALL [1] { } } result: { - IDENT [27] { + IDENT [22] { name: @x1:0 } } } } - } - COMPREHENSION [28] { - iter_var: @c0:0 - iter_range: { - IDENT [29] { - name: @index3 - } - } accu_var: @x0:0 accu_init: { - CREATE_LIST [30] { + CREATE_LIST [23] { elements: { } } } loop_condition: { - CONSTANT [31] { value: true } + CONSTANT [24] { value: true } } loop_step: { - IDENT [32] { - name: @index2 + CALL [25] { + function: _+_ + args: { + IDENT [26] { + name: @x0:0 + } + CREATE_LIST [27] { + elements: { + CREATE_LIST [28] { + elements: { + IDENT [29] { + name: @index1 + } + IDENT [30] { + name: @index1 + } + } + } + } + } + } } } result: { - IDENT [33] { + IDENT [31] { name: @x0:0 } } @@ -2460,27 +2241,24 @@ CALL [1] { } } } - CALL [7] { - function: _[_] - args: { - IDENT [8] { - name: @index0 - } - CONSTANT [9] { value: "a" } - } - } } } - CALL [10] { + CALL [7] { function: _&&_ args: { - SELECT [11] { - IDENT [12] { + SELECT [8] { + IDENT [9] { name: @index0 }.a~presence_test } - IDENT [13] { - name: @index1 + CALL [10] { + function: _[_] + args: { + IDENT [11] { + name: @index0 + } + CONSTANT [12] { value: "a" } + } } } } @@ -2499,33 +2277,30 @@ CALL [1] { name: msg }.oneof_type } - CALL [5] { + } + } + CALL [5] { + function: _==_ + args: { + CALL [6] { function: _?_:_ args: { - SELECT [6] { - IDENT [7] { + SELECT [7] { + IDENT [8] { name: @index0 }.payload~presence_test } - SELECT [8] { - SELECT [9] { - IDENT [10] { + SELECT [9] { + SELECT [10] { + IDENT [11] { name: @index0 }.payload }.single_int64 } - CONSTANT [11] { value: 0 } + CONSTANT [12] { value: 0 } } } - } - } - CALL [12] { - function: _==_ - args: { - IDENT [13] { - name: @index1 - } - CONSTANT [14] { value: 10 } + CONSTANT [13] { value: 10 } } } } @@ -2539,51 +2314,44 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload - } - SELECT [7] { - IDENT [8] { - name: @index1 + SELECT [4] { + SELECT [5] { + IDENT [6] { + name: msg + }.oneof_type + }.payload }.single_int64 } - CALL [9] { + } + } + CALL [7] { + function: _==_ + args: { + CALL [8] { function: _?_:_ args: { - SELECT [10] { - IDENT [11] { - name: @index0 + SELECT [9] { + SELECT [10] { + IDENT [11] { + name: msg + }.oneof_type }.payload~presence_test } IDENT [12] { - name: @index2 + name: @index0 } CALL [13] { function: _*_ args: { IDENT [14] { - name: @index2 + name: @index0 } CONSTANT [15] { value: 0 } } } } } - } - } - CALL [16] { - function: _==_ - args: { - IDENT [17] { - name: @index3 - } - CONSTANT [18] { value: 10 } + CONSTANT [16] { value: 10 } } } } @@ -2597,51 +2365,46 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload - } - SELECT [7] { - IDENT [8] { - name: @index1 + SELECT [4] { + SELECT [5] { + IDENT [6] { + name: msg + }.oneof_type + }.payload }.single_int64 } - CALL [9] { + } + } + CALL [7] { + function: _==_ + args: { + CALL [8] { function: _?_:_ args: { - SELECT [10] { - IDENT [11] { - name: @index1 + SELECT [9] { + SELECT [10] { + SELECT [11] { + IDENT [12] { + name: msg + }.oneof_type + }.payload }.single_int64~presence_test } - IDENT [12] { - name: @index2 + IDENT [13] { + name: @index0 } - CALL [13] { + CALL [14] { function: _*_ args: { - IDENT [14] { - name: @index2 + IDENT [15] { + name: @index0 } - CONSTANT [15] { value: 0 } + CONSTANT [16] { value: 0 } } } } } - } - } - CALL [16] { - function: _==_ - args: { - IDENT [17] { - name: @index3 - } - CONSTANT [18] { value: 10 } + CONSTANT [17] { value: 10 } } } } @@ -2655,88 +2418,85 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload + SELECT [4] { + SELECT [5] { + IDENT [6] { + name: msg + }.oneof_type + }.payload + }.map_string_string } SELECT [7] { - IDENT [8] { - name: @index1 - }.map_string_string + SELECT [8] { + IDENT [9] { + name: msg + }.oneof_type + }.payload } - CALL [9] { - function: _?_:_ + } + } + CALL [10] { + function: _?_:_ + args: { + CALL [11] { + function: _&&_ args: { - CALL [10] { + CALL [12] { function: _&&_ args: { - SELECT [11] { - IDENT [12] { - name: @index1 - }.map_string_string~presence_test - } SELECT [13] { IDENT [14] { - name: @index2 - }.key~presence_test + name: msg + }.oneof_type~presence_test } - } - } - CALL [15] { - function: _==_ - args: { - SELECT [16] { - IDENT [17] { - name: @index2 - }.key + SELECT [15] { + SELECT [16] { + IDENT [17] { + name: msg + }.oneof_type + }.payload~presence_test } - CONSTANT [18] { value: "A" } } } - CONSTANT [19] { value: false } + SELECT [18] { + IDENT [19] { + name: @index1 + }.single_int64~presence_test + } } } CALL [20] { - function: _&&_ + function: _?_:_ args: { CALL [21] { function: _&&_ args: { SELECT [22] { IDENT [23] { - name: msg - }.oneof_type~presence_test + name: @index1 + }.map_string_string~presence_test } SELECT [24] { IDENT [25] { name: @index0 - }.payload~presence_test + }.key~presence_test } } } - SELECT [26] { - IDENT [27] { - name: @index1 - }.single_int64~presence_test + CALL [26] { + function: _==_ + args: { + SELECT [27] { + IDENT [28] { + name: @index0 + }.key + } + CONSTANT [29] { value: "A" } + } } + CONSTANT [30] { value: false } } } - } - } - CALL [28] { - function: _?_:_ - args: { - IDENT [29] { - name: @index4 - } - IDENT [30] { - name: @index3 - } CONSTANT [31] { value: false } } } @@ -2750,44 +2510,49 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CALL [3] { - function: optional.none - args: { - } - } - CREATE_LIST [4] { + CREATE_LIST [3] { elements: { - IDENT [5] { - name: @index0 + CALL [4] { + function: optional.none + args: { + } } - IDENT [6] { + IDENT [5] { name: opt_x } } optional_indices: [0, 1] } - CREATE_LIST [7] { + CREATE_LIST [6] { elements: { - CONSTANT [8] { value: 5 } + CONSTANT [7] { value: 5 } } } + } + } + CALL [8] { + function: _==_ + args: { CREATE_LIST [9] { elements: { CONSTANT [10] { value: 10 } - IDENT [11] { - name: @index2 + CALL [11] { + function: optional.none + args: { + } } IDENT [12] { - name: @index2 + name: @index0 + } + IDENT [13] { + name: @index0 } } + optional_indices: [0] } - CREATE_LIST [13] { + CREATE_LIST [14] { elements: { - CONSTANT [14] { value: 10 } - IDENT [15] { - name: @index0 - } + CONSTANT [15] { value: 10 } IDENT [16] { name: @index1 } @@ -2795,18 +2560,6 @@ CALL [1] { name: @index1 } } - optional_indices: [0] - } - } - } - CALL [18] { - function: _==_ - args: { - IDENT [19] { - name: @index4 - } - IDENT [20] { - name: @index3 } } } @@ -2821,53 +2574,44 @@ CALL [1] { CREATE_LIST [2] { elements: { CALL [3] { - function: optional.of - args: { - CONSTANT [4] { value: "hello" } - } - } - CREATE_MAP [5] { - MAP_ENTRY [6] { - key: { - CONSTANT [7] { value: "hello" } - } - optional_entry: true - value: { - IDENT [8] { - name: @index0 - } - } - } - } - CALL [9] { function: _[_] args: { - IDENT [10] { - name: @index1 + CREATE_MAP [4] { + MAP_ENTRY [5] { + key: { + CONSTANT [6] { value: "hello" } + } + optional_entry: true + value: { + CALL [7] { + function: optional.of + args: { + CONSTANT [8] { value: "hello" } + } + } + } + } } - CONSTANT [11] { value: "hello" } + CONSTANT [9] { value: "hello" } } } - CALL [12] { + } + } + CALL [10] { + function: _==_ + args: { + CALL [11] { function: _+_ args: { - IDENT [13] { - name: @index2 + IDENT [12] { + name: @index0 } - IDENT [14] { - name: @index2 + IDENT [13] { + name: @index0 } } } - } - } - CALL [15] { - function: _==_ - args: { - IDENT [16] { - name: @index3 - } - CONSTANT [17] { value: "hellohello" } + CONSTANT [14] { value: "hellohello" } } } } @@ -2890,69 +2634,66 @@ CALL [1] { } } } - CALL [7] { + } + } + CALL [7] { + function: _==_ + args: { + CALL [8] { function: orValue target: { - CALL [8] { + CALL [9] { function: or target: { - CALL [9] { + CALL [10] { function: _[?_] args: { - CREATE_MAP [10] { - MAP_ENTRY [11] { + CREATE_MAP [11] { + MAP_ENTRY [12] { key: { - CONSTANT [12] { value: "key" } + CONSTANT [13] { value: "key" } } optional_entry: true value: { - CALL [13] { + CALL [14] { function: optional.of args: { - CONSTANT [14] { value: "test" } + CONSTANT [15] { value: "test" } } } } } } - CONSTANT [15] { value: "bogus" } + CONSTANT [16] { value: "bogus" } } } } args: { - CALL [16] { + CALL [17] { function: _[?_] args: { - IDENT [17] { + IDENT [18] { name: @index0 } - CONSTANT [18] { value: "bogus" } + CONSTANT [19] { value: "bogus" } } } } } } args: { - CALL [19] { + CALL [20] { function: _[_] args: { - IDENT [20] { + IDENT [21] { name: @index0 } - CONSTANT [21] { value: "key" } + CONSTANT [22] { value: "key" } } } } } - } - } - CALL [22] { - function: _==_ - args: { - IDENT [23] { - name: @index1 - } - CONSTANT [24] { value: "test" } + CONSTANT [23] { value: "test" } } } } @@ -2965,139 +2706,62 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CALL [3] { - function: optional.ofNonZeroValue - args: { - CONSTANT [4] { value: 1 } - } - } - CALL [5] { - function: optional.of - args: { - CONSTANT [6] { value: 4 } - } - } - CREATE_STRUCT [7] { + CREATE_STRUCT [3] { name: TestAllTypes entries: { - ENTRY [8] { + ENTRY [4] { field_key: single_int64 optional_entry: true value: { - IDENT [9] { - name: @index0 - } - } - } - ENTRY [10] { - field_key: single_int32 - optional_entry: true - value: { - IDENT [11] { - name: @index1 + CALL [5] { + function: optional.ofNonZeroValue + args: { + CONSTANT [6] { value: 1 } + } } } } - } - } - CALL [12] { - function: _+_ - args: { - SELECT [13] { - IDENT [14] { - name: @index2 - }.single_int32 - } - SELECT [15] { - IDENT [16] { - name: @index2 - }.single_int64 - } - } - } - } - } - CALL [17] { - function: _==_ - args: { - IDENT [18] { - name: @index3 - } - CONSTANT [19] { value: 5 } - } - } - } -} -Test case: CALL -Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('h' + 'e' + 'l' + 'l' + 'o') -=====> -CALL [1] { - function: cel.@block - args: { - CREATE_LIST [2] { - elements: { - CALL [3] { - function: _+_ - args: { - CONSTANT [4] { value: "h" } - CONSTANT [5] { value: "e" } - } - } - CALL [6] { - function: _+_ - args: { - IDENT [7] { - name: @index0 - } - CONSTANT [8] { value: "l" } - } - } - CALL [9] { - function: _+_ - args: { - IDENT [10] { - name: @index1 + ENTRY [7] { + field_key: single_int32 + optional_entry: true + value: { + CALL [8] { + function: optional.of + args: { + CONSTANT [9] { value: 4 } + } + } + } } - CONSTANT [11] { value: "l" } } } - CALL [12] { + } + } + CALL [10] { + function: _==_ + args: { + CALL [11] { function: _+_ args: { - IDENT [13] { - name: @index2 + SELECT [12] { + IDENT [13] { + name: @index0 + }.single_int32 } - CONSTANT [14] { value: "o" } - } - } - CALL [15] { - function: _+_ - args: { - IDENT [16] { - name: @index3 + SELECT [14] { + IDENT [15] { + name: @index0 + }.single_int64 } - CONSTANT [17] { value: " world" } } } - } - } - CALL [18] { - function: matches - target: { - IDENT [19] { - name: @index4 - } - } - args: { - IDENT [20] { - name: @index3 - } + CONSTANT [16] { value: 5 } } } } } -Test case: CALL_ARGUMENT_NESTED_NO_COMMON_SUBEXPR -Source: 'hello world'.matches('h' + 'e' + 'l' + 'l' + 'o') +Test case: CALL +Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('h' + 'e' + 'l' + 'l' + 'o') =====> CALL [1] { function: cel.@block @@ -3134,147 +2798,164 @@ CALL [1] { CALL [12] { function: matches target: { - CONSTANT [13] { value: "hello world" } + CALL [13] { + function: _+_ + args: { + IDENT [14] { + name: @index0 + } + CONSTANT [15] { value: " world" } + } + } } args: { - IDENT [14] { + IDENT [16] { name: @index0 } } } } } -Test case: CALL_TARGET_NESTED_NO_COMMON_SUBEXPR -Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('hello') +Test case: CALL_ARGUMENT_NESTED_NO_COMMON_SUBEXPR +Source: 'hello world'.matches('h' + 'e' + 'l' + 'l' + 'o') =====> -CALL [1] { - function: cel.@block +CALL [2] { + function: matches + target: { + CONSTANT [1] { value: "hello world" } + } args: { - CREATE_LIST [2] { - elements: { - CALL [3] { + CALL [10] { + function: _+_ + args: { + CALL [8] { function: _+_ args: { - CALL [4] { + CALL [6] { function: _+_ args: { - CALL [5] { + CALL [4] { function: _+_ args: { - CALL [6] { - function: _+_ - args: { - CALL [7] { - function: _+_ - args: { - CONSTANT [8] { value: "h" } - CONSTANT [9] { value: "e" } - } - } - CONSTANT [10] { value: "l" } - } - } - CONSTANT [11] { value: "l" } + CONSTANT [3] { value: "h" } + CONSTANT [5] { value: "e" } } } - CONSTANT [12] { value: "o" } + CONSTANT [7] { value: "l" } } } - CONSTANT [13] { value: " world" } + CONSTANT [9] { value: "l" } } } - } - } - CALL [14] { - function: matches - target: { - IDENT [15] { - name: @index0 - } - } - args: { - CONSTANT [16] { value: "hello" } + CONSTANT [11] { value: "o" } } } } } -Test case: CALL_BOTH_ARGUMENT_TARGET_NESTED_NO_COMMON_SUBEXPR -Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('w' + 'o' + 'r' + 'l' + 'd') +Test case: CALL_TARGET_NESTED_NO_COMMON_SUBEXPR +Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('hello') =====> -CALL [1] { - function: cel.@block - args: { - CREATE_LIST [2] { - elements: { - CALL [3] { +CALL [12] { + function: matches + target: { + CALL [10] { + function: _+_ + args: { + CALL [8] { function: _+_ args: { - CALL [4] { + CALL [6] { function: _+_ args: { - CALL [5] { + CALL [4] { function: _+_ args: { - CALL [6] { + CALL [2] { function: _+_ args: { - CONSTANT [7] { value: "w" } - CONSTANT [8] { value: "o" } + CONSTANT [1] { value: "h" } + CONSTANT [3] { value: "e" } } } - CONSTANT [9] { value: "r" } + CONSTANT [5] { value: "l" } } } - CONSTANT [10] { value: "l" } + CONSTANT [7] { value: "l" } } } - CONSTANT [11] { value: "d" } + CONSTANT [9] { value: "o" } } } - CALL [12] { + CONSTANT [11] { value: " world" } + } + } + } + args: { + CONSTANT [13] { value: "hello" } + } +} +Test case: CALL_BOTH_ARGUMENT_TARGET_NESTED_NO_COMMON_SUBEXPR +Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('w' + 'o' + 'r' + 'l' + 'd') +=====> +CALL [12] { + function: matches + target: { + CALL [10] { + function: _+_ + args: { + CALL [8] { function: _+_ args: { - CALL [13] { + CALL [6] { function: _+_ args: { - CALL [14] { + CALL [4] { function: _+_ args: { - CALL [15] { + CALL [2] { function: _+_ args: { - CALL [16] { - function: _+_ - args: { - CONSTANT [17] { value: "h" } - CONSTANT [18] { value: "e" } - } - } - CONSTANT [19] { value: "l" } + CONSTANT [1] { value: "h" } + CONSTANT [3] { value: "e" } } } - CONSTANT [20] { value: "l" } + CONSTANT [5] { value: "l" } } } - CONSTANT [21] { value: "o" } + CONSTANT [7] { value: "l" } } } - CONSTANT [22] { value: " world" } + CONSTANT [9] { value: "o" } } } + CONSTANT [11] { value: " world" } } } - CALL [23] { - function: matches - target: { - IDENT [24] { - name: @index1 - } - } + } + args: { + CALL [20] { + function: _+_ args: { - IDENT [25] { - name: @index0 + CALL [18] { + function: _+_ + args: { + CALL [16] { + function: _+_ + args: { + CALL [14] { + function: _+_ + args: { + CONSTANT [13] { value: "w" } + CONSTANT [15] { value: "o" } + } + } + CONSTANT [17] { value: "r" } + } + } + CONSTANT [19] { value: "l" } + } } + CONSTANT [21] { value: "d" } } } } @@ -3288,74 +2969,66 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload - } - SELECT [7] { - IDENT [8] { - name: @index1 - }.single_int64 - } - SELECT [9] { - IDENT [10] { - name: msg + SELECT [4] { + SELECT [5] { + IDENT [6] { + name: msg + }.oneof_type + }.payload }.single_int64 } - SELECT [11] { - IDENT [12] { - name: @index1 - }.single_int32 - } } } - CALL [13] { + CALL [7] { function: _+_ args: { - CALL [14] { + CALL [8] { function: _+_ args: { - CALL [15] { + CALL [9] { function: _+_ args: { - CALL [16] { + CALL [10] { function: non_pure_custom_func args: { - IDENT [17] { - name: @index2 + IDENT [11] { + name: @index0 } } } - CALL [18] { + CALL [12] { function: non_pure_custom_func args: { - IDENT [19] { - name: @index4 + SELECT [13] { + SELECT [14] { + SELECT [15] { + IDENT [16] { + name: msg + }.oneof_type + }.payload + }.single_int32 } } } } } - CALL [20] { + CALL [17] { function: non_pure_custom_func args: { - IDENT [21] { - name: @index2 + IDENT [18] { + name: @index0 } } } } } - CALL [22] { + CALL [19] { function: non_pure_custom_func args: { - IDENT [23] { - name: @index3 + SELECT [20] { + IDENT [21] { + name: msg + }.single_int64 } } } @@ -3371,75 +3044,64 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload - } - SELECT [7] { - IDENT [8] { - name: @index1 - }.single_int64 - } - CALL [9] { - function: pure_custom_func - args: { - IDENT [10] { - name: @index2 - } - } - } - CALL [11] { + CALL [3] { function: pure_custom_func args: { - SELECT [12] { - IDENT [13] { - name: msg + SELECT [4] { + SELECT [5] { + SELECT [6] { + IDENT [7] { + name: msg + }.oneof_type + }.payload }.single_int64 } } } - CALL [14] { + } + } + CALL [8] { + function: _+_ + args: { + CALL [9] { function: _+_ args: { - CALL [15] { + CALL [10] { function: _+_ args: { - IDENT [16] { - name: @index3 + IDENT [11] { + name: @index0 } - CALL [17] { + CALL [12] { function: pure_custom_func args: { - SELECT [18] { - IDENT [19] { - name: @index1 + SELECT [13] { + SELECT [14] { + SELECT [15] { + IDENT [16] { + name: msg + }.oneof_type + }.payload }.single_int32 } } } } } - IDENT [20] { - name: @index3 + IDENT [17] { + name: @index0 } } } - } - } - CALL [21] { - function: _+_ - args: { - IDENT [22] { - name: @index5 - } - IDENT [23] { - name: @index4 + CALL [18] { + function: pure_custom_func + args: { + SELECT [19] { + IDENT [20] { + name: msg + }.single_int64 + } + } } } } diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_9.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_9.baseline index fc16cdf85..b20801a0f 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_9.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_9.baseline @@ -6,20 +6,22 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_LIST [3] { - elements: { - CONSTANT [4] { value: 1 } - CONSTANT [5] { value: 2 } - } - } - CALL [6] { + CALL [3] { function: size args: { - IDENT [7] { - name: @index0 + CREATE_LIST [4] { + elements: { + CONSTANT [5] { value: 1 } + CONSTANT [6] { value: 2 } + } } } } + } + } + CALL [7] { + function: _==_ + args: { CALL [8] { function: _+_ args: { @@ -27,25 +29,17 @@ CALL [1] { function: _+_ args: { IDENT [10] { - name: @index1 + name: @index0 } IDENT [11] { - name: @index1 + name: @index0 } } } CONSTANT [12] { value: 1 } } } - } - } - CALL [13] { - function: _==_ - args: { - IDENT [14] { - name: @index2 - } - CONSTANT [15] { value: 5 } + CONSTANT [13] { value: 5 } } } } @@ -58,20 +52,22 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_LIST [3] { - elements: { - CONSTANT [4] { value: 1 } - CONSTANT [5] { value: 2 } - } - } - CALL [6] { + CALL [3] { function: size args: { - IDENT [7] { - name: @index0 + CREATE_LIST [4] { + elements: { + CONSTANT [5] { value: 1 } + CONSTANT [6] { value: 2 } + } } } } + } + } + CALL [7] { + function: _==_ + args: { CALL [8] { function: _+_ args: { @@ -83,27 +79,19 @@ CALL [1] { args: { CONSTANT [11] { value: 2 } IDENT [12] { - name: @index1 + name: @index0 } } } IDENT [13] { - name: @index1 + name: @index0 } } } CONSTANT [14] { value: 1 } } } - } - } - CALL [15] { - function: _==_ - args: { - IDENT [16] { - name: @index2 - } - CONSTANT [17] { value: 7 } + CONSTANT [15] { value: 7 } } } } @@ -116,69 +104,60 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_LIST [3] { - elements: { - CONSTANT [4] { value: 0 } - } - } - CALL [5] { + CALL [3] { function: size args: { - IDENT [6] { - name: @index0 + CREATE_LIST [4] { + elements: { + CONSTANT [5] { value: 0 } + } } } } - CREATE_LIST [7] { - elements: { - CONSTANT [8] { value: 1 } - CONSTANT [9] { value: 2 } - } - } - CALL [10] { + CALL [6] { function: size args: { - IDENT [11] { - name: @index2 + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 1 } + CONSTANT [9] { value: 2 } + } } } } - CALL [12] { + } + } + CALL [10] { + function: _==_ + args: { + CALL [11] { function: _+_ args: { - CALL [13] { + CALL [12] { function: _+_ args: { - CALL [14] { + CALL [13] { function: _+_ args: { - IDENT [15] { - name: @index1 + IDENT [14] { + name: @index0 } - IDENT [16] { - name: @index1 + IDENT [15] { + name: @index0 } } } - IDENT [17] { - name: @index3 + IDENT [16] { + name: @index1 } } } - IDENT [18] { - name: @index3 + IDENT [17] { + name: @index1 } } } - } - } - CALL [19] { - function: _==_ - args: { - IDENT [20] { - name: @index4 - } - CONSTANT [21] { value: 6 } + CONSTANT [18] { value: 6 } } } } @@ -191,106 +170,94 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_LIST [3] { - elements: { - CONSTANT [4] { value: 0 } - } - } - CALL [5] { + CALL [3] { function: size args: { - IDENT [6] { - name: @index0 + CREATE_LIST [4] { + elements: { + CONSTANT [5] { value: 0 } + } } } } - CREATE_LIST [7] { - elements: { - CONSTANT [8] { value: 1 } - CONSTANT [9] { value: 2 } - } - } - CALL [10] { + CALL [6] { function: size args: { - IDENT [11] { - name: @index2 + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 1 } + CONSTANT [9] { value: 2 } + } } } } - CREATE_LIST [12] { - elements: { - CONSTANT [13] { value: 1 } - CONSTANT [14] { value: 2 } - CONSTANT [15] { value: 3 } - } - } - CALL [16] { + CALL [10] { function: size args: { - IDENT [17] { - name: @index4 + CREATE_LIST [11] { + elements: { + CONSTANT [12] { value: 1 } + CONSTANT [13] { value: 2 } + CONSTANT [14] { value: 3 } + } } } } - CALL [18] { + } + } + CALL [15] { + function: _==_ + args: { + CALL [16] { function: _+_ args: { - CALL [19] { + CALL [17] { function: _+_ args: { - CALL [20] { + CALL [18] { function: _+_ args: { - CALL [21] { + CALL [19] { function: _+_ args: { - CALL [22] { + CALL [20] { function: _+_ args: { - CALL [23] { + CALL [21] { function: _+_ args: { - CONSTANT [24] { value: 5 } - IDENT [25] { - name: @index1 + CONSTANT [22] { value: 5 } + IDENT [23] { + name: @index0 } } } - IDENT [26] { - name: @index1 + IDENT [24] { + name: @index0 } } } - IDENT [27] { - name: @index3 + IDENT [25] { + name: @index1 } } } - IDENT [28] { - name: @index3 + IDENT [26] { + name: @index1 } } } - IDENT [29] { - name: @index5 + IDENT [27] { + name: @index2 } } } - IDENT [30] { - name: @index5 + IDENT [28] { + name: @index2 } } } - } - } - CALL [31] { - function: _==_ - args: { - IDENT [32] { - name: @index6 - } - CONSTANT [33] { value: 17 } + CONSTANT [29] { value: 17 } } } } @@ -304,145 +271,115 @@ CALL [1] { CREATE_LIST [2] { elements: { CALL [3] { - function: timestamp - args: { - CONSTANT [4] { value: 1000000000 } - } - } - CALL [5] { - function: int - args: { - IDENT [6] { - name: @index0 + function: getFullYear + target: { + CALL [4] { + function: timestamp + args: { + CALL [5] { + function: int + args: { + CALL [6] { + function: timestamp + args: { + CONSTANT [7] { value: 1000000000 } + } + } + } + } + } } } - } - CALL [7] { - function: timestamp args: { - IDENT [8] { - name: @index1 - } } } - CALL [9] { + CALL [8] { function: getFullYear target: { - IDENT [10] { - name: @index2 + CALL [9] { + function: timestamp + args: { + CALL [10] { + function: int + args: { + CALL [11] { + function: timestamp + args: { + CONSTANT [12] { value: 200 } + } + } + } + } + } } } args: { } } - CALL [11] { - function: timestamp - args: { - CONSTANT [12] { value: 50 } - } - } CALL [13] { - function: int - args: { - IDENT [14] { - name: @index4 - } - } - } - CALL [15] { function: timestamp args: { - IDENT [16] { - name: @index5 + CALL [14] { + function: int + args: { + CALL [15] { + function: timestamp + args: { + CONSTANT [16] { value: 50 } + } + } + } } } } CALL [17] { function: timestamp args: { - CONSTANT [18] { value: 200 } - } - } - CALL [19] { - function: int - args: { - IDENT [20] { - name: @index7 + CALL [18] { + function: int + args: { + CALL [19] { + function: timestamp + args: { + CONSTANT [20] { value: 75 } + } + } + } } } } CALL [21] { - function: timestamp - args: { - IDENT [22] { - name: @index8 - } - } - } - CALL [23] { - function: getFullYear - target: { - IDENT [24] { - name: @index9 - } - } - args: { - } - } - CALL [25] { - function: timestamp - args: { - CONSTANT [26] { value: 75 } - } - } - CALL [27] { - function: int - args: { - IDENT [28] { - name: @index11 - } - } - } - CALL [29] { - function: timestamp - args: { - IDENT [30] { - name: @index12 - } - } - } - CALL [31] { function: _+_ args: { - CALL [32] { + CALL [22] { function: _+_ args: { - CALL [33] { + CALL [23] { function: _+_ args: { - CALL [34] { + CALL [24] { function: _+_ args: { - CALL [35] { + CALL [25] { function: _+_ args: { - CALL [36] { + CALL [26] { function: _+_ args: { - CALL [37] { + CALL [27] { function: _+_ args: { - CALL [38] { + CALL [28] { function: _+_ args: { - IDENT [39] { - name: @index3 + IDENT [29] { + name: @index0 } - CALL [40] { + CALL [30] { function: getFullYear target: { - IDENT [41] { - name: @index13 + IDENT [31] { + name: @index3 } } args: { @@ -450,11 +387,11 @@ CALL [1] { } } } - CALL [42] { + CALL [32] { function: getFullYear target: { - IDENT [43] { - name: @index6 + IDENT [33] { + name: @index2 } } args: { @@ -462,16 +399,16 @@ CALL [1] { } } } - IDENT [44] { - name: @index3 + IDENT [34] { + name: @index0 } } } - CALL [45] { + CALL [35] { function: getSeconds target: { - IDENT [46] { - name: @index6 + IDENT [36] { + name: @index2 } } args: { @@ -479,21 +416,21 @@ CALL [1] { } } } - IDENT [47] { - name: @index10 + IDENT [37] { + name: @index1 } } } - IDENT [48] { - name: @index10 + IDENT [38] { + name: @index1 } } } - CALL [49] { + CALL [39] { function: getMinutes target: { - IDENT [50] { - name: @index13 + IDENT [40] { + name: @index3 } } args: { @@ -501,20 +438,20 @@ CALL [1] { } } } - IDENT [51] { - name: @index3 + IDENT [41] { + name: @index0 } } } } } - CALL [52] { + CALL [42] { function: _==_ args: { - IDENT [53] { - name: @index14 + IDENT [43] { + name: @index4 } - CONSTANT [54] { value: 13934 } + CONSTANT [44] { value: 13934 } } } } @@ -527,53 +464,47 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_MAP [3] { - MAP_ENTRY [4] { - key: { - CONSTANT [5] { value: "a" } - } - value: { - CONSTANT [6] { value: 2 } - } - } - } - CALL [7] { + CALL [3] { function: _[_] args: { - IDENT [8] { - name: @index0 + CREATE_MAP [4] { + MAP_ENTRY [5] { + key: { + CONSTANT [6] { value: "a" } + } + value: { + CONSTANT [7] { value: 2 } + } + } } - CONSTANT [9] { value: "a" } + CONSTANT [8] { value: "a" } } } + } + } + CALL [9] { + function: _==_ + args: { CALL [10] { function: _+_ args: { IDENT [11] { - name: @index1 + name: @index0 } CALL [12] { function: _*_ args: { IDENT [13] { - name: @index1 + name: @index0 } IDENT [14] { - name: @index1 + name: @index0 } } } } } - } - } - CALL [15] { - function: _==_ - args: { - IDENT [16] { - name: @index2 - } - CONSTANT [17] { value: 6 } + CONSTANT [15] { value: 6 } } } } @@ -589,51 +520,48 @@ CALL [1] { CREATE_MAP [3] { MAP_ENTRY [4] { key: { - CONSTANT [5] { value: "b" } + CONSTANT [5] { value: "e" } } value: { - CONSTANT [6] { value: 1 } + CREATE_MAP [6] { + MAP_ENTRY [7] { + key: { + CONSTANT [8] { value: "b" } + } + value: { + CONSTANT [9] { value: 1 } + } + } + } } } } - CREATE_MAP [7] { - MAP_ENTRY [8] { + CREATE_MAP [10] { + MAP_ENTRY [11] { key: { - CONSTANT [9] { value: "e" } + CONSTANT [12] { value: "b" } } value: { - IDENT [10] { - name: @index0 - } + CONSTANT [13] { value: 1 } } } } } } - CREATE_MAP [11] { - MAP_ENTRY [12] { - key: { - CONSTANT [13] { value: "a" } - } - value: { - IDENT [14] { - name: @index0 - } - } - } + CREATE_MAP [14] { MAP_ENTRY [15] { key: { - CONSTANT [16] { value: "c" } + CONSTANT [16] { value: "a" } } value: { IDENT [17] { - name: @index0 + name: @index1 } } } MAP_ENTRY [18] { key: { - CONSTANT [19] { value: "d" } + CONSTANT [19] { value: "c" } } value: { IDENT [20] { @@ -643,11 +571,21 @@ CALL [1] { } MAP_ENTRY [21] { key: { - CONSTANT [22] { value: "e" } + CONSTANT [22] { value: "d" } } value: { IDENT [23] { - name: @index1 + name: @index0 + } + } + } + MAP_ENTRY [24] { + key: { + CONSTANT [25] { value: "e" } + } + value: { + IDENT [26] { + name: @index0 } } } @@ -676,37 +614,34 @@ CALL [1] { CONSTANT [10] { value: 2 } } } - CREATE_LIST [11] { - elements: { - IDENT [12] { - name: @index1 - } - IDENT [13] { - name: @index0 - } - } - } } } - CREATE_LIST [14] { + CREATE_LIST [11] { elements: { - CONSTANT [15] { value: 1 } - IDENT [16] { + CONSTANT [12] { value: 1 } + IDENT [13] { name: @index0 } - CONSTANT [17] { value: 2 } - IDENT [18] { + CONSTANT [14] { value: 2 } + IDENT [15] { name: @index0 } - CONSTANT [19] { value: 5 } - IDENT [20] { + CONSTANT [16] { value: 5 } + IDENT [17] { name: @index0 } - CONSTANT [21] { value: 7 } - IDENT [22] { - name: @index2 + CONSTANT [18] { value: 7 } + CREATE_LIST [19] { + elements: { + IDENT [20] { + name: @index1 + } + IDENT [21] { + name: @index0 + } + } } - IDENT [23] { + IDENT [22] { name: @index1 } } @@ -726,26 +661,23 @@ CALL [1] { name: msg }.single_int64 } - CALL [5] { + } + } + CALL [5] { + function: _==_ + args: { + CALL [6] { function: _+_ args: { - IDENT [6] { + IDENT [7] { name: @index0 } - IDENT [7] { + IDENT [8] { name: @index0 } } } - } - } - CALL [8] { - function: _==_ - args: { - IDENT [9] { - name: @index1 - } - CONSTANT [10] { value: 6 } + CONSTANT [9] { value: 6 } } } } @@ -759,58 +691,64 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload + SELECT [4] { + SELECT [5] { + IDENT [6] { + name: msg + }.oneof_type + }.payload + }.single_int64 } SELECT [7] { - IDENT [8] { - name: @index1 - }.single_int64 + SELECT [8] { + IDENT [9] { + name: msg + }.oneof_type + }.payload } - CALL [9] { + } + } + CALL [10] { + function: _==_ + args: { + CALL [11] { function: _+_ args: { - CALL [10] { + CALL [12] { function: _+_ args: { - CALL [11] { + CALL [13] { function: _+_ args: { - CALL [12] { + CALL [14] { function: _+_ args: { - IDENT [13] { - name: @index2 + IDENT [15] { + name: @index0 } - SELECT [14] { - IDENT [15] { + SELECT [16] { + IDENT [17] { name: @index1 }.single_int32 } } } - IDENT [16] { - name: @index2 + IDENT [18] { + name: @index0 } } } - SELECT [17] { - IDENT [18] { + SELECT [19] { + IDENT [20] { name: msg }.single_int64 } } } - SELECT [19] { - SELECT [20] { - SELECT [21] { - IDENT [22] { + SELECT [21] { + SELECT [22] { + SELECT [23] { + IDENT [24] { name: @index1 }.oneof_type }.payload @@ -818,14 +756,6 @@ CALL [1] { } } } - } - } - CALL [23] { - function: _==_ - args: { - IDENT [24] { - name: @index3 - } CONSTANT [25] { value: 31 } } } @@ -840,51 +770,33 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload - } - SELECT [7] { - IDENT [8] { - name: @index1 - }.oneof_type - } - SELECT [9] { - IDENT [10] { - name: @index2 - }.payload - } - SELECT [11] { - IDENT [12] { - name: @index3 - }.oneof_type - } - SELECT [13] { - SELECT [14] { - SELECT [15] { - SELECT [16] { - IDENT [17] { - name: @index4 - }.child - }.child + SELECT [4] { + SELECT [5] { + SELECT [6] { + SELECT [7] { + IDENT [8] { + name: msg + }.oneof_type + }.payload + }.oneof_type }.payload - }.single_bool + }.oneof_type } - CALL [18] { + } + } + CALL [9] { + function: _||_ + args: { + CALL [10] { function: _||_ args: { - CONSTANT [19] { value: true } - SELECT [20] { - SELECT [21] { - SELECT [22] { - SELECT [23] { - IDENT [24] { - name: @index4 + CONSTANT [11] { value: true } + SELECT [12] { + SELECT [13] { + SELECT [14] { + SELECT [15] { + IDENT [16] { + name: @index0 }.payload }.oneof_type }.payload @@ -892,16 +804,16 @@ CALL [1] { } } } - } - } - CALL [25] { - function: _||_ - args: { - IDENT [26] { - name: @index6 - } - IDENT [27] { - name: @index5 + SELECT [17] { + SELECT [18] { + SELECT [19] { + SELECT [20] { + IDENT [21] { + name: @index0 + }.child + }.child + }.payload + }.single_bool } } } @@ -915,58 +827,46 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload - } - SELECT [7] { - IDENT [8] { - name: @index1 - }.map_int32_int64 - } - CALL [9] { + CALL [3] { function: _[_] args: { - IDENT [10] { - name: @index2 + SELECT [4] { + SELECT [5] { + SELECT [6] { + IDENT [7] { + name: msg + }.oneof_type + }.payload + }.map_int32_int64 } - CONSTANT [11] { value: 1 } + CONSTANT [8] { value: 1 } } } - CALL [12] { + } + } + CALL [9] { + function: _==_ + args: { + CALL [10] { function: _+_ args: { - CALL [13] { + CALL [11] { function: _+_ args: { - IDENT [14] { - name: @index3 + IDENT [12] { + name: @index0 } - IDENT [15] { - name: @index3 + IDENT [13] { + name: @index0 } } } - IDENT [16] { - name: @index3 + IDENT [14] { + name: @index0 } } } - } - } - CALL [17] { - function: _==_ - args: { - IDENT [18] { - name: @index4 - } - CONSTANT [19] { value: 15 } + CONSTANT [15] { value: 15 } } } } @@ -980,66 +880,57 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload - } - SELECT [7] { - IDENT [8] { - name: @index1 + SELECT [4] { + SELECT [5] { + IDENT [6] { + name: msg + }.oneof_type + }.payload }.map_int32_int64 } - CALL [9] { + } + } + CALL [7] { + function: _==_ + args: { + CALL [8] { function: _+_ args: { - CALL [10] { + CALL [9] { function: _+_ args: { - CALL [11] { + CALL [10] { function: _[_] args: { - IDENT [12] { - name: @index2 + IDENT [11] { + name: @index0 } - CONSTANT [13] { value: 0 } + CONSTANT [12] { value: 0 } } } - CALL [14] { + CALL [13] { function: _[_] args: { - IDENT [15] { - name: @index2 + IDENT [14] { + name: @index0 } - CONSTANT [16] { value: 1 } + CONSTANT [15] { value: 1 } } } } } - CALL [17] { + CALL [16] { function: _[_] args: { - IDENT [18] { - name: @index2 + IDENT [17] { + name: @index0 } - CONSTANT [19] { value: 2 } + CONSTANT [18] { value: 2 } } } } } - } - } - CALL [20] { - function: _==_ - args: { - IDENT [21] { - name: @index3 - } - CONSTANT [22] { value: 8 } + CONSTANT [19] { value: 8 } } } } @@ -1047,38 +938,26 @@ CALL [1] { Test case: SELECT_NESTED_NO_COMMON_SUBEXPR Source: msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload.single_int64 =====> -CALL [1] { - function: cel.@block - args: { - CREATE_LIST [2] { - elements: { - SELECT [3] { - SELECT [4] { - SELECT [5] { - SELECT [6] { - SELECT [7] { - SELECT [8] { - SELECT [9] { - SELECT [10] { - IDENT [11] { - name: msg - }.oneof_type - }.payload - }.oneof_type - }.payload - }.oneof_type - }.payload - }.oneof_type - }.payload - } - } - } - SELECT [12] { - IDENT [13] { - name: @index0 - }.single_int64 - } - } +SELECT [10] { + SELECT [9] { + SELECT [8] { + SELECT [7] { + SELECT [6] { + SELECT [5] { + SELECT [4] { + SELECT [3] { + SELECT [2] { + IDENT [1] { + name: msg + }.oneof_type + }.payload + }.oneof_type + }.payload + }.oneof_type + }.payload + }.oneof_type + }.payload + }.single_int64 } Test case: TERNARY Source: (msg.single_int64 > 0 ? msg.single_int64 : 0) == 3 @@ -1093,33 +972,30 @@ CALL [1] { name: msg }.single_int64 } - CALL [5] { + } + } + CALL [5] { + function: _==_ + args: { + CALL [6] { function: _?_:_ args: { - CALL [6] { + CALL [7] { function: _>_ args: { - IDENT [7] { + IDENT [8] { name: @index0 } - CONSTANT [8] { value: 0 } + CONSTANT [9] { value: 0 } } } - IDENT [9] { + IDENT [10] { name: @index0 } - CONSTANT [10] { value: 0 } + CONSTANT [11] { value: 0 } } } - } - } - CALL [11] { - function: _==_ - args: { - IDENT [12] { - name: @index1 - } - CONSTANT [13] { value: 3 } + CONSTANT [12] { value: 3 } } } } @@ -1137,47 +1013,44 @@ CALL [1] { name: msg }.single_int64 } - CALL [5] { + } + } + CALL [5] { + function: _?_:_ + args: { + CONSTANT [6] { value: false } + CONSTANT [7] { value: false } + CALL [8] { function: _==_ args: { - CALL [6] { + CALL [9] { function: _+_ args: { - IDENT [7] { + IDENT [10] { name: @index0 } - CALL [8] { + CALL [11] { function: _*_ args: { - CALL [9] { + CALL [12] { function: _+_ args: { - IDENT [10] { + IDENT [13] { name: @index0 } - CONSTANT [11] { value: 1 } + CONSTANT [14] { value: 1 } } } - CONSTANT [12] { value: 2 } + CONSTANT [15] { value: 2 } } } } } - CONSTANT [13] { value: 11 } + CONSTANT [16] { value: 11 } } } } } - CALL [14] { - function: _?_:_ - args: { - CONSTANT [15] { value: false } - CONSTANT [16] { value: false } - IDENT [17] { - name: @index1 - } - } - } } } Test case: NESTED_TERNARY @@ -1198,56 +1071,53 @@ CALL [1] { name: msg }.single_int32 } - CALL [7] { + } + } + CALL [7] { + function: _==_ + args: { + CALL [8] { function: _?_:_ args: { - CALL [8] { + CALL [9] { function: _>_ args: { - IDENT [9] { + IDENT [10] { name: @index0 } - CONSTANT [10] { value: 0 } + CONSTANT [11] { value: 0 } } } - CALL [11] { + CALL [12] { function: _?_:_ args: { - CALL [12] { + CALL [13] { function: _>_ args: { - IDENT [13] { + IDENT [14] { name: @index1 } - CONSTANT [14] { value: 0 } + CONSTANT [15] { value: 0 } } } - CALL [15] { + CALL [16] { function: _+_ args: { - IDENT [16] { + IDENT [17] { name: @index0 } - IDENT [17] { + IDENT [18] { name: @index1 } } } - CONSTANT [18] { value: 0 } + CONSTANT [19] { value: 0 } } } - CONSTANT [19] { value: 0 } + CONSTANT [20] { value: 0 } } } - } - } - CALL [20] { - function: _==_ - args: { - IDENT [21] { - name: @index2 - } - CONSTANT [22] { value: 8 } + CONSTANT [21] { value: 8 } } } } @@ -1260,50 +1130,60 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_LIST [3] { - elements: { - CONSTANT [4] { value: 1 } - } - } - CALL [5] { - function: _>_ - args: { - IDENT [6] { - name: @c0:0 - } - CONSTANT [7] { value: 0 } - } - } - CALL [8] { - function: _||_ + CALL [3] { + function: size args: { - IDENT [9] { - name: @x0:0 - } - IDENT [10] { - name: @index1 - } - } - } - COMPREHENSION [11] { - iter_var: @c0:0 - iter_range: { - IDENT [12] { - name: @index0 - } - } - accu_var: @x0:0 - accu_init: { - CONSTANT [13] { value: false } - } - loop_condition: { - CALL [14] { - function: @not_strictly_false - args: { - CALL [15] { - function: !_ - args: { - IDENT [16] { + CREATE_LIST [4] { + elements: { + COMPREHENSION [5] { + iter_var: @c0:0 + iter_range: { + CREATE_LIST [6] { + elements: { + CONSTANT [7] { value: 1 } + } + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [8] { value: false } + } + loop_condition: { + CALL [9] { + function: @not_strictly_false + args: { + CALL [10] { + function: !_ + args: { + IDENT [11] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + CALL [12] { + function: _||_ + args: { + IDENT [13] { + name: @x0:0 + } + CALL [14] { + function: _>_ + args: { + IDENT [15] { + name: @c0:0 + } + CONSTANT [16] { value: 0 } + } + } + } + } + } + result: { + IDENT [17] { name: @x0:0 } } @@ -1311,76 +1191,61 @@ CALL [1] { } } } - loop_step: { - IDENT [17] { - name: @index2 - } - } - result: { - IDENT [18] { - name: @x0:0 - } - } - } - CREATE_LIST [19] { - elements: { - IDENT [20] { - name: @index3 - } - } } - CALL [21] { + CALL [18] { function: size args: { - IDENT [22] { - name: @index4 - } - } - } - CREATE_LIST [23] { - elements: { - CONSTANT [24] { value: 2 } - } - } - CALL [25] { - function: _>_ - args: { - IDENT [26] { - name: @c0:0 - } - CONSTANT [27] { value: 1 } - } - } - CALL [28] { - function: _||_ - args: { - IDENT [29] { - name: @x0:0 - } - IDENT [30] { - name: @index7 - } - } - } - COMPREHENSION [31] { - iter_var: @c0:0 - iter_range: { - IDENT [32] { - name: @index6 - } - } - accu_var: @x0:0 - accu_init: { - CONSTANT [33] { value: false } - } - loop_condition: { - CALL [34] { - function: @not_strictly_false - args: { - CALL [35] { - function: !_ - args: { - IDENT [36] { + CREATE_LIST [19] { + elements: { + COMPREHENSION [20] { + iter_var: @c0:0 + iter_range: { + CREATE_LIST [21] { + elements: { + CONSTANT [22] { value: 2 } + } + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [23] { value: false } + } + loop_condition: { + CALL [24] { + function: @not_strictly_false + args: { + CALL [25] { + function: !_ + args: { + IDENT [26] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + CALL [27] { + function: _||_ + args: { + IDENT [28] { + name: @x0:0 + } + CALL [29] { + function: _>_ + args: { + IDENT [30] { + name: @c0:0 + } + CONSTANT [31] { value: 1 } + } + } + } + } + } + result: { + IDENT [32] { name: @x0:0 } } @@ -1388,68 +1253,40 @@ CALL [1] { } } } - loop_step: { - IDENT [37] { - name: @index8 - } - } - result: { - IDENT [38] { - name: @x0:0 - } - } - } - CREATE_LIST [39] { - elements: { - IDENT [40] { - name: @index9 - } - } - } - CALL [41] { - function: size - args: { - IDENT [42] { - name: @index10 - } - } } - CALL [43] { + } + } + CALL [33] { + function: _==_ + args: { + CALL [34] { function: _+_ args: { - CALL [44] { + CALL [35] { function: _+_ args: { - CALL [45] { + CALL [36] { function: _+_ args: { - IDENT [46] { - name: @index5 + IDENT [37] { + name: @index0 } - IDENT [47] { - name: @index5 + IDENT [38] { + name: @index0 } } } - IDENT [48] { - name: @index11 + IDENT [39] { + name: @index1 } } } - IDENT [49] { - name: @index11 + IDENT [40] { + name: @index1 } } } - } - } - CALL [50] { - function: _==_ - args: { - IDENT [51] { - name: @index12 - } - CONSTANT [52] { value: 4 } + CONSTANT [41] { value: 4 } } } } @@ -1464,187 +1301,157 @@ CALL [1] { elements: { CREATE_LIST [3] { elements: { - CONSTANT [4] { value: 1 } - } - } - CALL [5] { - function: _>_ - args: { - IDENT [6] { - name: @c0:0 - } - CONSTANT [7] { value: 0 } - } - } - CALL [8] { - function: _||_ - args: { - IDENT [9] { - name: @x0:0 - } - IDENT [10] { - name: @index1 - } - } - } - COMPREHENSION [11] { - iter_var: @c0:0 - iter_range: { - IDENT [12] { - name: @index0 - } - } - accu_var: @x0:0 - accu_init: { - CONSTANT [13] { value: false } - } - loop_condition: { - CALL [14] { - function: @not_strictly_false - args: { - CALL [15] { - function: !_ + COMPREHENSION [4] { + iter_var: @c0:0 + iter_range: { + CREATE_LIST [5] { + elements: { + CONSTANT [6] { value: 1 } + } + } + } + accu_var: @x0:0 + accu_init: { + CONSTANT [7] { value: false } + } + loop_condition: { + CALL [8] { + function: @not_strictly_false args: { - IDENT [16] { + CALL [9] { + function: !_ + args: { + IDENT [10] { + name: @x0:0 + } + } + } + } + } + } + loop_step: { + CALL [11] { + function: _||_ + args: { + IDENT [12] { name: @x0:0 } + CALL [13] { + function: _>_ + args: { + IDENT [14] { + name: @c0:0 + } + CONSTANT [15] { value: 0 } + } + } } } } - } - } - loop_step: { - IDENT [17] { - name: @index2 - } - } - result: { - IDENT [18] { - name: @x0:0 - } - } - } - CREATE_LIST [19] { - elements: { - IDENT [20] { - name: @index3 + result: { + IDENT [16] { + name: @x0:0 + } + } } } } - CREATE_LIST [21] { + CREATE_LIST [17] { elements: { - CONSTANT [22] { value: "a" } - } - } - CALL [23] { - function: _==_ - args: { - IDENT [24] { - name: @c0:1 - } - CONSTANT [25] { value: "a" } - } - } - CALL [26] { - function: _||_ - args: { - IDENT [27] { - name: @x0:1 - } - IDENT [28] { - name: @index6 - } - } - } - COMPREHENSION [29] { - iter_var: @c0:1 - iter_range: { - IDENT [30] { - name: @index5 - } - } - accu_var: @x0:1 - accu_init: { - CONSTANT [31] { value: false } - } - loop_condition: { - CALL [32] { - function: @not_strictly_false - args: { - CALL [33] { - function: !_ + COMPREHENSION [18] { + iter_var: @c0:1 + iter_range: { + CREATE_LIST [19] { + elements: { + CONSTANT [20] { value: "a" } + } + } + } + accu_var: @x0:1 + accu_init: { + CONSTANT [21] { value: false } + } + loop_condition: { + CALL [22] { + function: @not_strictly_false args: { - IDENT [34] { - name: @x0:1 + CALL [23] { + function: !_ + args: { + IDENT [24] { + name: @x0:1 + } + } } } } } + loop_step: { + CALL [25] { + function: _||_ + args: { + IDENT [26] { + name: @x0:1 + } + CALL [27] { + function: _==_ + args: { + IDENT [28] { + name: @c0:1 + } + CONSTANT [29] { value: "a" } + } + } + } + } + } + result: { + IDENT [30] { + name: @x0:1 + } + } } } - loop_step: { - IDENT [35] { - name: @index7 - } - } - result: { - IDENT [36] { - name: @x0:1 - } - } - } - CREATE_LIST [37] { - elements: { - IDENT [38] { - name: @index8 - } - } - } - CREATE_LIST [39] { - elements: { - CONSTANT [40] { value: true } - CONSTANT [41] { value: true } - CONSTANT [42] { value: true } - CONSTANT [43] { value: true } - } } - CALL [44] { + } + } + CALL [31] { + function: _==_ + args: { + CALL [32] { function: _+_ args: { - CALL [45] { + CALL [33] { function: _+_ args: { - CALL [46] { + CALL [34] { function: _+_ args: { - IDENT [47] { - name: @index4 + IDENT [35] { + name: @index0 } - IDENT [48] { - name: @index4 + IDENT [36] { + name: @index0 } } } - IDENT [49] { - name: @index9 + IDENT [37] { + name: @index1 } } } - IDENT [50] { - name: @index9 + IDENT [38] { + name: @index1 } } } - } - } - CALL [51] { - function: _==_ - args: { - IDENT [52] { - name: @index11 - } - IDENT [53] { - name: @index10 + CREATE_LIST [39] { + elements: { + CONSTANT [40] { value: true } + CONSTANT [41] { value: true } + CONSTANT [42] { value: true } + CONSTANT [43] { value: true } + } } } } @@ -1672,78 +1479,70 @@ CALL [1] { CONSTANT [10] { value: 4 } } } - CREATE_LIST [11] { - elements: { - IDENT [12] { - name: @index1 - } - IDENT [13] { - name: @index1 - } - IDENT [14] { - name: @index1 - } - } - } - COMPREHENSION [15] { + } + } + CALL [11] { + function: _==_ + args: { + COMPREHENSION [12] { iter_var: @c0:0 iter_range: { - IDENT [16] { + IDENT [13] { name: @index0 } } accu_var: @x0:0 accu_init: { - CREATE_LIST [17] { + CREATE_LIST [14] { elements: { } } } loop_condition: { - CONSTANT [18] { value: true } + CONSTANT [15] { value: true } } loop_step: { - CALL [19] { + CALL [16] { function: _+_ args: { - IDENT [20] { + IDENT [17] { name: @x0:0 } - CREATE_LIST [21] { + CREATE_LIST [18] { elements: { - COMPREHENSION [22] { + COMPREHENSION [19] { iter_var: @c1:0 iter_range: { - IDENT [23] { + IDENT [20] { name: @index0 } } accu_var: @x1:0 accu_init: { - CREATE_LIST [24] { + CREATE_LIST [21] { elements: { } } } loop_condition: { - CONSTANT [25] { value: true } + CONSTANT [22] { value: true } } loop_step: { - CALL [26] { + CALL [23] { function: _+_ args: { - IDENT [27] { + IDENT [24] { name: @x1:0 } - CREATE_LIST [28] { + CREATE_LIST [25] { elements: { - CALL [29] { + CALL [26] { function: _+_ args: { - IDENT [30] { + IDENT [27] { name: @c1:0 } - CONSTANT [31] { value: 1 } + CONSTANT [28] { value: 1 } } } } @@ -1752,7 +1551,7 @@ CALL [1] { } } result: { - IDENT [32] { + IDENT [29] { name: @x1:0 } } @@ -1763,21 +1562,23 @@ CALL [1] { } } result: { - IDENT [33] { + IDENT [30] { name: @x0:0 } } } - } - } - CALL [34] { - function: _==_ - args: { - IDENT [35] { - name: @index3 - } - IDENT [36] { - name: @index2 + CREATE_LIST [31] { + elements: { + IDENT [32] { + name: @index1 + } + IDENT [33] { + name: @index1 + } + IDENT [34] { + name: @index1 + } + } } } } @@ -1786,138 +1587,123 @@ CALL [1] { Test case: NESTED_MACROS_2 Source: [1, 2].map(y, [1, 2, 3].filter(x, x == y)) == [[1], [2]] =====> -CALL [1] { - function: cel.@block +CALL [31] { + function: _==_ args: { - CREATE_LIST [2] { - elements: { - CREATE_LIST [3] { + COMPREHENSION [30] { + iter_var: @c0:0 + iter_range: { + CREATE_LIST [1] { elements: { - CREATE_LIST [4] { - elements: { - CONSTANT [5] { value: 1 } - } - } - CREATE_LIST [6] { - elements: { - CONSTANT [7] { value: 2 } - } - } + CONSTANT [2] { value: 1 } + CONSTANT [3] { value: 2 } } } - COMPREHENSION [8] { - iter_var: @c0:0 - iter_range: { - CREATE_LIST [9] { - elements: { - CONSTANT [10] { value: 1 } - CONSTANT [11] { value: 2 } - } - } + } + accu_var: @x0:0 + accu_init: { + CREATE_LIST [24] { + elements: { } - accu_var: @x0:0 - accu_init: { - CREATE_LIST [12] { - elements: { - } + } + } + loop_condition: { + CONSTANT [25] { value: true } + } + loop_step: { + CALL [28] { + function: _+_ + args: { + IDENT [26] { + name: @x0:0 } - } - loop_condition: { - CONSTANT [13] { value: true } - } - loop_step: { - CALL [14] { - function: _+_ - args: { - IDENT [15] { - name: @x0:0 - } - CREATE_LIST [16] { - elements: { - COMPREHENSION [17] { - iter_var: @c1:0 - iter_range: { - CREATE_LIST [18] { - elements: { - CONSTANT [19] { value: 1 } - CONSTANT [20] { value: 2 } - CONSTANT [21] { value: 3 } - } - } + CREATE_LIST [27] { + elements: { + COMPREHENSION [23] { + iter_var: @c1:0 + iter_range: { + CREATE_LIST [6] { + elements: { + CONSTANT [7] { value: 1 } + CONSTANT [8] { value: 2 } + CONSTANT [9] { value: 3 } } - accu_var: @x1:0 - accu_init: { - CREATE_LIST [22] { - elements: { + } + } + accu_var: @x1:0 + accu_init: { + CREATE_LIST [15] { + elements: { + } + } + } + loop_condition: { + CONSTANT [16] { value: true } + } + loop_step: { + CALL [21] { + function: _?_:_ + args: { + CALL [13] { + function: _==_ + args: { + IDENT [12] { + name: @c1:0 + } + IDENT [14] { + name: @c0:0 + } } } - } - loop_condition: { - CONSTANT [23] { value: true } - } - loop_step: { - CALL [24] { - function: _?_:_ + CALL [19] { + function: _+_ args: { - CALL [25] { - function: _==_ - args: { - IDENT [26] { - name: @c1:0 - } - IDENT [27] { - name: @c0:0 - } - } + IDENT [17] { + name: @x1:0 } - CALL [28] { - function: _+_ - args: { - IDENT [29] { - name: @x1:0 - } - CREATE_LIST [30] { - elements: { - IDENT [31] { - name: @c1:0 - } - } + CREATE_LIST [18] { + elements: { + IDENT [11] { + name: @c1:0 } } } - IDENT [32] { - name: @x1:0 - } } } - } - result: { - IDENT [33] { + IDENT [20] { name: @x1:0 } } } } + result: { + IDENT [22] { + name: @x1:0 + } + } } } } } - result: { - IDENT [34] { - name: @x0:0 - } - } + } + } + result: { + IDENT [29] { + name: @x0:0 } } } - CALL [35] { - function: _==_ - args: { - IDENT [36] { - name: @index1 + CREATE_LIST [32] { + elements: { + CREATE_LIST [33] { + elements: { + CONSTANT [34] { value: 1 } + } } - IDENT [37] { - name: @index0 + CREATE_LIST [35] { + elements: { + CONSTANT [36] { value: 2 } + } } } } @@ -1931,74 +1717,72 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_LIST [3] { - elements: { - CONSTANT [4] { value: 1 } - CONSTANT [5] { value: 2 } - CONSTANT [6] { value: 3 } - } - } - CALL [7] { + CALL [3] { function: @in args: { - CONSTANT [8] { value: 1 } - IDENT [9] { - name: @index0 + CONSTANT [4] { value: 1 } + CREATE_LIST [5] { + elements: { + CONSTANT [6] { value: 1 } + CONSTANT [7] { value: 2 } + CONSTANT [8] { value: 3 } + } } } } - CALL [10] { + CREATE_LIST [9] { + elements: { + CONSTANT [10] { value: 1 } + CONSTANT [11] { value: 2 } + CONSTANT [12] { value: 3 } + } + } + } + } + CALL [13] { + function: _&&_ + args: { + CALL [14] { function: _&&_ args: { - CALL [11] { + IDENT [15] { + name: @index0 + } + CALL [16] { function: @in args: { - CONSTANT [12] { value: 3 } - CREATE_LIST [13] { - elements: { - CONSTANT [14] { value: 3 } - IDENT [15] { - name: @index0 - } - } + CONSTANT [17] { value: 2 } + IDENT [18] { + name: @index1 } } } - IDENT [16] { - name: @index1 - } } } - CALL [17] { + CALL [19] { function: _&&_ args: { - IDENT [18] { - name: @index1 - } - CALL [19] { + CALL [20] { function: @in args: { - CONSTANT [20] { value: 2 } - IDENT [21] { - name: @index0 + CONSTANT [21] { value: 3 } + CREATE_LIST [22] { + elements: { + CONSTANT [23] { value: 3 } + IDENT [24] { + name: @index1 + } + } } } } + IDENT [25] { + name: @index0 + } } } } } - CALL [22] { - function: _&&_ - args: { - IDENT [23] { - name: @index3 - } - IDENT [24] { - name: @index2 - } - } - } } } Test case: INCLUSION_MAP @@ -2019,31 +1803,37 @@ CALL [1] { } } } - CREATE_MAP [7] { - MAP_ENTRY [8] { + } + } + CALL [7] { + function: @in + args: { + CONSTANT [8] { value: 2 } + CREATE_MAP [9] { + MAP_ENTRY [10] { key: { - CONSTANT [9] { value: "a" } + CONSTANT [11] { value: "a" } } value: { - CONSTANT [10] { value: 1 } + CONSTANT [12] { value: 1 } } } - MAP_ENTRY [11] { + MAP_ENTRY [13] { key: { - CONSTANT [12] { value: 2 } + CONSTANT [14] { value: 2 } } value: { - IDENT [13] { + IDENT [15] { name: @index0 } } } - MAP_ENTRY [14] { + MAP_ENTRY [16] { key: { - CONSTANT [15] { value: 3 } + CONSTANT [17] { value: 3 } } value: { - IDENT [16] { + IDENT [18] { name: @index0 } } @@ -2051,15 +1841,6 @@ CALL [1] { } } } - CALL [17] { - function: @in - args: { - CONSTANT [18] { value: 2 } - IDENT [19] { - name: @index1 - } - } - } } } Test case: MACRO_ITER_VAR_NOT_REFERENCED @@ -2072,90 +1853,88 @@ CALL [1] { elements: { CREATE_LIST [3] { elements: { - CONSTANT [4] { value: 1 } - CONSTANT [5] { value: 2 } - } - } - CREATE_LIST [6] { - elements: { - CONSTANT [7] { value: 3 } - CONSTANT [8] { value: 4 } - } - } - CREATE_LIST [9] { - elements: { - IDENT [10] { - name: @index1 + CREATE_LIST [4] { + elements: { + CONSTANT [5] { value: 3 } + CONSTANT [6] { value: 4 } + } } - IDENT [11] { - name: @index1 + CREATE_LIST [7] { + elements: { + CONSTANT [8] { value: 3 } + CONSTANT [9] { value: 4 } + } } } } - CREATE_LIST [12] { + CREATE_LIST [10] { elements: { - IDENT [13] { - name: @index2 - } - IDENT [14] { - name: @index2 - } + CONSTANT [11] { value: 1 } + CONSTANT [12] { value: 2 } } } - COMPREHENSION [15] { + } + } + CALL [13] { + function: _==_ + args: { + COMPREHENSION [14] { iter_var: @c0:0 iter_range: { - IDENT [16] { - name: @index0 + IDENT [15] { + name: @index1 } } accu_var: @x0:0 accu_init: { - CREATE_LIST [17] { + CREATE_LIST [16] { elements: { } } } loop_condition: { - CONSTANT [18] { value: true } + CONSTANT [17] { value: true } } loop_step: { - CALL [19] { + CALL [18] { function: _+_ args: { - IDENT [20] { + IDENT [19] { name: @x0:0 } - CREATE_LIST [21] { + CREATE_LIST [20] { elements: { - COMPREHENSION [22] { + COMPREHENSION [21] { iter_var: @c1:0 iter_range: { - IDENT [23] { - name: @index0 + IDENT [22] { + name: @index1 } } accu_var: @x1:0 accu_init: { - CREATE_LIST [24] { + CREATE_LIST [23] { elements: { } } } loop_condition: { - CONSTANT [25] { value: true } + CONSTANT [24] { value: true } } loop_step: { - CALL [26] { + CALL [25] { function: _+_ args: { - IDENT [27] { + IDENT [26] { name: @x1:0 } - CREATE_LIST [28] { + CREATE_LIST [27] { elements: { - IDENT [29] { - name: @index1 + CREATE_LIST [28] { + elements: { + CONSTANT [29] { value: 3 } + CONSTANT [30] { value: 4 } + } } } } @@ -2163,7 +1942,7 @@ CALL [1] { } } result: { - IDENT [30] { + IDENT [31] { name: @x1:0 } } @@ -2174,21 +1953,20 @@ CALL [1] { } } result: { - IDENT [31] { + IDENT [32] { name: @x0:0 } } } - } - } - CALL [32] { - function: _==_ - args: { - IDENT [33] { - name: @index4 - } - IDENT [34] { - name: @index3 + CREATE_LIST [33] { + elements: { + IDENT [34] { + name: @index0 + } + IDENT [35] { + name: @index0 + } + } } } } @@ -2203,23 +1981,25 @@ CALL [1] { CREATE_LIST [2] { elements: { CALL [3] { - function: _-_ - args: { - IDENT [4] { - name: x - } - CONSTANT [5] { value: 1 } - } - } - CALL [6] { function: _>_ args: { - IDENT [7] { - name: @index0 + CALL [4] { + function: _-_ + args: { + IDENT [5] { + name: x + } + CONSTANT [6] { value: 1 } + } } - CONSTANT [8] { value: 3 } + CONSTANT [7] { value: 3 } } } + } + } + CALL [8] { + function: _||_ + args: { COMPREHENSION [9] { iter_var: @c0:0 iter_range: { @@ -2229,12 +2009,18 @@ CALL [1] { function: _?_:_ args: { IDENT [12] { - name: @index1 - } - IDENT [13] { name: @index0 } - CONSTANT [14] { value: 5 } + CALL [13] { + function: _-_ + args: { + IDENT [14] { + name: x + } + CONSTANT [15] { value: 1 } + } + } + CONSTANT [16] { value: 5 } } } } @@ -2242,16 +2028,16 @@ CALL [1] { } accu_var: @x0:0 accu_init: { - CONSTANT [15] { value: false } + CONSTANT [17] { value: false } } loop_condition: { - CALL [16] { + CALL [18] { function: @not_strictly_false args: { - CALL [17] { + CALL [19] { function: !_ args: { - IDENT [18] { + IDENT [20] { name: @x0:0 } } @@ -2260,46 +2046,38 @@ CALL [1] { } } loop_step: { - CALL [19] { + CALL [21] { function: _||_ args: { - IDENT [20] { + IDENT [22] { name: @x0:0 } - CALL [21] { + CALL [23] { function: _>_ args: { - CALL [22] { + CALL [24] { function: _-_ args: { - IDENT [23] { + IDENT [25] { name: @c0:0 } - CONSTANT [24] { value: 1 } + CONSTANT [26] { value: 1 } } } - CONSTANT [25] { value: 3 } + CONSTANT [27] { value: 3 } } } } } } result: { - IDENT [26] { + IDENT [28] { name: @x0:0 } } } - } - } - CALL [27] { - function: _||_ - args: { - IDENT [28] { - name: @index2 - } IDENT [29] { - name: @index1 + name: @index0 } } } @@ -2335,63 +2113,46 @@ CALL [1] { } } } - CALL [9] { - function: _+_ - args: { - IDENT [10] { - name: @x0:0 - } - CREATE_LIST [11] { - elements: { - CREATE_LIST [12] { - elements: { - IDENT [13] { - name: @index1 - } - IDENT [14] { - name: @index1 - } - } - } - } - } - } - } - COMPREHENSION [15] { + } + } + COMPREHENSION [9] { + iter_var: @c0:0 + iter_range: { + COMPREHENSION [10] { iter_var: @c1:0 iter_range: { - CREATE_LIST [16] { + CREATE_LIST [11] { elements: { - CONSTANT [17] { value: "foo" } - CONSTANT [18] { value: "bar" } + CONSTANT [12] { value: "foo" } + CONSTANT [13] { value: "bar" } } } } accu_var: @x1:0 accu_init: { - CREATE_LIST [19] { + CREATE_LIST [14] { elements: { } } } loop_condition: { - CONSTANT [20] { value: true } + CONSTANT [15] { value: true } } loop_step: { - CALL [21] { + CALL [16] { function: _+_ args: { - IDENT [22] { + IDENT [17] { name: @x1:0 } - CREATE_LIST [23] { + CREATE_LIST [18] { elements: { - CREATE_LIST [24] { + CREATE_LIST [19] { elements: { - IDENT [25] { + IDENT [20] { name: @index0 } - IDENT [26] { + IDENT [21] { name: @index0 } } @@ -2402,37 +2163,48 @@ CALL [1] { } } result: { - IDENT [27] { + IDENT [22] { name: @x1:0 } } } } - } - COMPREHENSION [28] { - iter_var: @c0:0 - iter_range: { - IDENT [29] { - name: @index3 - } - } accu_var: @x0:0 accu_init: { - CREATE_LIST [30] { + CREATE_LIST [23] { elements: { } } } loop_condition: { - CONSTANT [31] { value: true } + CONSTANT [24] { value: true } } loop_step: { - IDENT [32] { - name: @index2 + CALL [25] { + function: _+_ + args: { + IDENT [26] { + name: @x0:0 + } + CREATE_LIST [27] { + elements: { + CREATE_LIST [28] { + elements: { + IDENT [29] { + name: @index1 + } + IDENT [30] { + name: @index1 + } + } + } + } + } + } } } result: { - IDENT [33] { + IDENT [31] { name: @x0:0 } } @@ -2457,27 +2229,24 @@ CALL [1] { } } } - CALL [7] { - function: _[_] - args: { - IDENT [8] { - name: @index0 - } - CONSTANT [9] { value: "a" } - } - } } } - CALL [10] { + CALL [7] { function: _&&_ args: { - SELECT [11] { - IDENT [12] { + SELECT [8] { + IDENT [9] { name: @index0 }.a~presence_test } - IDENT [13] { - name: @index1 + CALL [10] { + function: _[_] + args: { + IDENT [11] { + name: @index0 + } + CONSTANT [12] { value: "a" } + } } } } @@ -2496,33 +2265,30 @@ CALL [1] { name: msg }.oneof_type } - CALL [5] { + } + } + CALL [5] { + function: _==_ + args: { + CALL [6] { function: _?_:_ args: { - SELECT [6] { - IDENT [7] { + SELECT [7] { + IDENT [8] { name: @index0 }.payload~presence_test } - SELECT [8] { - SELECT [9] { - IDENT [10] { + SELECT [9] { + SELECT [10] { + IDENT [11] { name: @index0 }.payload }.single_int64 } - CONSTANT [11] { value: 0 } + CONSTANT [12] { value: 0 } } } - } - } - CALL [12] { - function: _==_ - args: { - IDENT [13] { - name: @index1 - } - CONSTANT [14] { value: 10 } + CONSTANT [13] { value: 10 } } } } @@ -2536,51 +2302,44 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload - } - SELECT [7] { - IDENT [8] { - name: @index1 + SELECT [4] { + SELECT [5] { + IDENT [6] { + name: msg + }.oneof_type + }.payload }.single_int64 } - CALL [9] { + } + } + CALL [7] { + function: _==_ + args: { + CALL [8] { function: _?_:_ args: { - SELECT [10] { - IDENT [11] { - name: @index0 + SELECT [9] { + SELECT [10] { + IDENT [11] { + name: msg + }.oneof_type }.payload~presence_test } IDENT [12] { - name: @index2 + name: @index0 } CALL [13] { function: _*_ args: { IDENT [14] { - name: @index2 + name: @index0 } CONSTANT [15] { value: 0 } } } } } - } - } - CALL [16] { - function: _==_ - args: { - IDENT [17] { - name: @index3 - } - CONSTANT [18] { value: 10 } + CONSTANT [16] { value: 10 } } } } @@ -2594,51 +2353,46 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload - } - SELECT [7] { - IDENT [8] { - name: @index1 + SELECT [4] { + SELECT [5] { + IDENT [6] { + name: msg + }.oneof_type + }.payload }.single_int64 } - CALL [9] { + } + } + CALL [7] { + function: _==_ + args: { + CALL [8] { function: _?_:_ args: { - SELECT [10] { - IDENT [11] { - name: @index1 + SELECT [9] { + SELECT [10] { + SELECT [11] { + IDENT [12] { + name: msg + }.oneof_type + }.payload }.single_int64~presence_test } - IDENT [12] { - name: @index2 + IDENT [13] { + name: @index0 } - CALL [13] { + CALL [14] { function: _*_ args: { - IDENT [14] { - name: @index2 + IDENT [15] { + name: @index0 } - CONSTANT [15] { value: 0 } + CONSTANT [16] { value: 0 } } } } } - } - } - CALL [16] { - function: _==_ - args: { - IDENT [17] { - name: @index3 - } - CONSTANT [18] { value: 10 } + CONSTANT [17] { value: 10 } } } } @@ -2652,88 +2406,85 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload + SELECT [4] { + SELECT [5] { + IDENT [6] { + name: msg + }.oneof_type + }.payload + }.map_string_string } SELECT [7] { - IDENT [8] { - name: @index1 - }.map_string_string + SELECT [8] { + IDENT [9] { + name: msg + }.oneof_type + }.payload } - CALL [9] { - function: _?_:_ + } + } + CALL [10] { + function: _?_:_ + args: { + CALL [11] { + function: _&&_ args: { - CALL [10] { + CALL [12] { function: _&&_ args: { - SELECT [11] { - IDENT [12] { - name: @index1 - }.map_string_string~presence_test - } SELECT [13] { IDENT [14] { - name: @index2 - }.key~presence_test + name: msg + }.oneof_type~presence_test } - } - } - CALL [15] { - function: _==_ - args: { - SELECT [16] { - IDENT [17] { - name: @index2 - }.key + SELECT [15] { + SELECT [16] { + IDENT [17] { + name: msg + }.oneof_type + }.payload~presence_test } - CONSTANT [18] { value: "A" } } } - CONSTANT [19] { value: false } + SELECT [18] { + IDENT [19] { + name: @index1 + }.single_int64~presence_test + } } } CALL [20] { - function: _&&_ + function: _?_:_ args: { CALL [21] { function: _&&_ args: { SELECT [22] { IDENT [23] { - name: msg - }.oneof_type~presence_test + name: @index1 + }.map_string_string~presence_test } SELECT [24] { IDENT [25] { name: @index0 - }.payload~presence_test + }.key~presence_test } } } - SELECT [26] { - IDENT [27] { - name: @index1 - }.single_int64~presence_test + CALL [26] { + function: _==_ + args: { + SELECT [27] { + IDENT [28] { + name: @index0 + }.key + } + CONSTANT [29] { value: "A" } + } } + CONSTANT [30] { value: false } } } - } - } - CALL [28] { - function: _?_:_ - args: { - IDENT [29] { - name: @index4 - } - IDENT [30] { - name: @index3 - } CONSTANT [31] { value: false } } } @@ -2747,44 +2498,49 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CALL [3] { - function: optional.none - args: { - } - } - CREATE_LIST [4] { + CREATE_LIST [3] { elements: { - IDENT [5] { - name: @index0 + CALL [4] { + function: optional.none + args: { + } } - IDENT [6] { + IDENT [5] { name: opt_x } } optional_indices: [0, 1] } - CREATE_LIST [7] { + CREATE_LIST [6] { elements: { - CONSTANT [8] { value: 5 } + CONSTANT [7] { value: 5 } } } + } + } + CALL [8] { + function: _==_ + args: { CREATE_LIST [9] { elements: { CONSTANT [10] { value: 10 } - IDENT [11] { - name: @index2 + CALL [11] { + function: optional.none + args: { + } } IDENT [12] { - name: @index2 + name: @index0 + } + IDENT [13] { + name: @index0 } } + optional_indices: [0] } - CREATE_LIST [13] { + CREATE_LIST [14] { elements: { - CONSTANT [14] { value: 10 } - IDENT [15] { - name: @index0 - } + CONSTANT [15] { value: 10 } IDENT [16] { name: @index1 } @@ -2792,18 +2548,6 @@ CALL [1] { name: @index1 } } - optional_indices: [0] - } - } - } - CALL [18] { - function: _==_ - args: { - IDENT [19] { - name: @index4 - } - IDENT [20] { - name: @index3 } } } @@ -2818,53 +2562,44 @@ CALL [1] { CREATE_LIST [2] { elements: { CALL [3] { - function: optional.of - args: { - CONSTANT [4] { value: "hello" } - } - } - CREATE_MAP [5] { - MAP_ENTRY [6] { - key: { - CONSTANT [7] { value: "hello" } - } - optional_entry: true - value: { - IDENT [8] { - name: @index0 - } - } - } - } - CALL [9] { function: _[_] args: { - IDENT [10] { - name: @index1 + CREATE_MAP [4] { + MAP_ENTRY [5] { + key: { + CONSTANT [6] { value: "hello" } + } + optional_entry: true + value: { + CALL [7] { + function: optional.of + args: { + CONSTANT [8] { value: "hello" } + } + } + } + } } - CONSTANT [11] { value: "hello" } + CONSTANT [9] { value: "hello" } } } - CALL [12] { + } + } + CALL [10] { + function: _==_ + args: { + CALL [11] { function: _+_ args: { - IDENT [13] { - name: @index2 + IDENT [12] { + name: @index0 } - IDENT [14] { - name: @index2 + IDENT [13] { + name: @index0 } } } - } - } - CALL [15] { - function: _==_ - args: { - IDENT [16] { - name: @index3 - } - CONSTANT [17] { value: "hellohello" } + CONSTANT [14] { value: "hellohello" } } } } @@ -2887,69 +2622,66 @@ CALL [1] { } } } - CALL [7] { + } + } + CALL [7] { + function: _==_ + args: { + CALL [8] { function: orValue target: { - CALL [8] { + CALL [9] { function: or target: { - CALL [9] { + CALL [10] { function: _[?_] args: { - CREATE_MAP [10] { - MAP_ENTRY [11] { + CREATE_MAP [11] { + MAP_ENTRY [12] { key: { - CONSTANT [12] { value: "key" } + CONSTANT [13] { value: "key" } } optional_entry: true value: { - CALL [13] { + CALL [14] { function: optional.of args: { - CONSTANT [14] { value: "test" } + CONSTANT [15] { value: "test" } } } } } } - CONSTANT [15] { value: "bogus" } + CONSTANT [16] { value: "bogus" } } } } args: { - CALL [16] { + CALL [17] { function: _[?_] args: { - IDENT [17] { + IDENT [18] { name: @index0 } - CONSTANT [18] { value: "bogus" } + CONSTANT [19] { value: "bogus" } } } } } } args: { - CALL [19] { + CALL [20] { function: _[_] args: { - IDENT [20] { + IDENT [21] { name: @index0 } - CONSTANT [21] { value: "key" } + CONSTANT [22] { value: "key" } } } } } - } - } - CALL [22] { - function: _==_ - args: { - IDENT [23] { - name: @index1 - } - CONSTANT [24] { value: "test" } + CONSTANT [23] { value: "test" } } } } @@ -2962,139 +2694,62 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CALL [3] { - function: optional.ofNonZeroValue - args: { - CONSTANT [4] { value: 1 } - } - } - CALL [5] { - function: optional.of - args: { - CONSTANT [6] { value: 4 } - } - } - CREATE_STRUCT [7] { + CREATE_STRUCT [3] { name: TestAllTypes entries: { - ENTRY [8] { + ENTRY [4] { field_key: single_int64 optional_entry: true value: { - IDENT [9] { - name: @index0 - } - } - } - ENTRY [10] { - field_key: single_int32 - optional_entry: true - value: { - IDENT [11] { - name: @index1 - } - } - } - } - } - CALL [12] { - function: _+_ - args: { - SELECT [13] { - IDENT [14] { - name: @index2 - }.single_int32 - } - SELECT [15] { - IDENT [16] { - name: @index2 - }.single_int64 - } - } - } - } - } - CALL [17] { - function: _==_ - args: { - IDENT [18] { - name: @index3 - } - CONSTANT [19] { value: 5 } - } - } - } -} -Test case: CALL -Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('h' + 'e' + 'l' + 'l' + 'o') -=====> -CALL [1] { - function: cel.@block - args: { - CREATE_LIST [2] { - elements: { - CALL [3] { - function: _+_ - args: { - CONSTANT [4] { value: "h" } - CONSTANT [5] { value: "e" } - } - } - CALL [6] { - function: _+_ - args: { - IDENT [7] { - name: @index0 - } - CONSTANT [8] { value: "l" } - } - } - CALL [9] { - function: _+_ - args: { - IDENT [10] { - name: @index1 + CALL [5] { + function: optional.ofNonZeroValue + args: { + CONSTANT [6] { value: 1 } + } + } + } } - CONSTANT [11] { value: "l" } - } - } - CALL [12] { - function: _+_ - args: { - IDENT [13] { - name: @index2 + ENTRY [7] { + field_key: single_int32 + optional_entry: true + value: { + CALL [8] { + function: optional.of + args: { + CONSTANT [9] { value: 4 } + } + } + } } - CONSTANT [14] { value: "o" } } } - CALL [15] { + } + } + CALL [10] { + function: _==_ + args: { + CALL [11] { function: _+_ args: { - IDENT [16] { - name: @index3 + SELECT [12] { + IDENT [13] { + name: @index0 + }.single_int32 + } + SELECT [14] { + IDENT [15] { + name: @index0 + }.single_int64 } - CONSTANT [17] { value: " world" } } } - } - } - CALL [18] { - function: matches - target: { - IDENT [19] { - name: @index4 - } - } - args: { - IDENT [20] { - name: @index3 - } + CONSTANT [16] { value: 5 } } } } } -Test case: CALL_ARGUMENT_NESTED_NO_COMMON_SUBEXPR -Source: 'hello world'.matches('h' + 'e' + 'l' + 'l' + 'o') +Test case: CALL +Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('h' + 'e' + 'l' + 'l' + 'o') =====> CALL [1] { function: cel.@block @@ -3131,147 +2786,164 @@ CALL [1] { CALL [12] { function: matches target: { - CONSTANT [13] { value: "hello world" } + CALL [13] { + function: _+_ + args: { + IDENT [14] { + name: @index0 + } + CONSTANT [15] { value: " world" } + } + } } args: { - IDENT [14] { + IDENT [16] { name: @index0 } } } } } -Test case: CALL_TARGET_NESTED_NO_COMMON_SUBEXPR -Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('hello') +Test case: CALL_ARGUMENT_NESTED_NO_COMMON_SUBEXPR +Source: 'hello world'.matches('h' + 'e' + 'l' + 'l' + 'o') =====> -CALL [1] { - function: cel.@block +CALL [2] { + function: matches + target: { + CONSTANT [1] { value: "hello world" } + } args: { - CREATE_LIST [2] { - elements: { - CALL [3] { + CALL [10] { + function: _+_ + args: { + CALL [8] { function: _+_ args: { - CALL [4] { + CALL [6] { function: _+_ args: { - CALL [5] { + CALL [4] { function: _+_ args: { - CALL [6] { - function: _+_ - args: { - CALL [7] { - function: _+_ - args: { - CONSTANT [8] { value: "h" } - CONSTANT [9] { value: "e" } - } - } - CONSTANT [10] { value: "l" } - } - } - CONSTANT [11] { value: "l" } + CONSTANT [3] { value: "h" } + CONSTANT [5] { value: "e" } } } - CONSTANT [12] { value: "o" } + CONSTANT [7] { value: "l" } } } - CONSTANT [13] { value: " world" } + CONSTANT [9] { value: "l" } } } - } - } - CALL [14] { - function: matches - target: { - IDENT [15] { - name: @index0 - } - } - args: { - CONSTANT [16] { value: "hello" } + CONSTANT [11] { value: "o" } } } } } -Test case: CALL_BOTH_ARGUMENT_TARGET_NESTED_NO_COMMON_SUBEXPR -Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('w' + 'o' + 'r' + 'l' + 'd') +Test case: CALL_TARGET_NESTED_NO_COMMON_SUBEXPR +Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('hello') =====> -CALL [1] { - function: cel.@block - args: { - CREATE_LIST [2] { - elements: { - CALL [3] { +CALL [12] { + function: matches + target: { + CALL [10] { + function: _+_ + args: { + CALL [8] { function: _+_ args: { - CALL [4] { + CALL [6] { function: _+_ args: { - CALL [5] { + CALL [4] { function: _+_ args: { - CALL [6] { + CALL [2] { function: _+_ args: { - CONSTANT [7] { value: "w" } - CONSTANT [8] { value: "o" } + CONSTANT [1] { value: "h" } + CONSTANT [3] { value: "e" } } } - CONSTANT [9] { value: "r" } + CONSTANT [5] { value: "l" } } } - CONSTANT [10] { value: "l" } + CONSTANT [7] { value: "l" } } } - CONSTANT [11] { value: "d" } + CONSTANT [9] { value: "o" } } } - CALL [12] { + CONSTANT [11] { value: " world" } + } + } + } + args: { + CONSTANT [13] { value: "hello" } + } +} +Test case: CALL_BOTH_ARGUMENT_TARGET_NESTED_NO_COMMON_SUBEXPR +Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('w' + 'o' + 'r' + 'l' + 'd') +=====> +CALL [12] { + function: matches + target: { + CALL [10] { + function: _+_ + args: { + CALL [8] { function: _+_ args: { - CALL [13] { + CALL [6] { function: _+_ args: { - CALL [14] { + CALL [4] { function: _+_ args: { - CALL [15] { + CALL [2] { function: _+_ args: { - CALL [16] { - function: _+_ - args: { - CONSTANT [17] { value: "h" } - CONSTANT [18] { value: "e" } - } - } - CONSTANT [19] { value: "l" } + CONSTANT [1] { value: "h" } + CONSTANT [3] { value: "e" } } } - CONSTANT [20] { value: "l" } + CONSTANT [5] { value: "l" } } } - CONSTANT [21] { value: "o" } + CONSTANT [7] { value: "l" } } } - CONSTANT [22] { value: " world" } + CONSTANT [9] { value: "o" } } } + CONSTANT [11] { value: " world" } } } - CALL [23] { - function: matches - target: { - IDENT [24] { - name: @index1 - } - } + } + args: { + CALL [20] { + function: _+_ args: { - IDENT [25] { - name: @index0 + CALL [18] { + function: _+_ + args: { + CALL [16] { + function: _+_ + args: { + CALL [14] { + function: _+_ + args: { + CONSTANT [13] { value: "w" } + CONSTANT [15] { value: "o" } + } + } + CONSTANT [17] { value: "r" } + } + } + CONSTANT [19] { value: "l" } + } } + CONSTANT [21] { value: "d" } } } } @@ -3285,74 +2957,66 @@ CALL [1] { CREATE_LIST [2] { elements: { SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload - } - SELECT [7] { - IDENT [8] { - name: @index1 - }.single_int64 - } - SELECT [9] { - IDENT [10] { - name: msg + SELECT [4] { + SELECT [5] { + IDENT [6] { + name: msg + }.oneof_type + }.payload }.single_int64 } - SELECT [11] { - IDENT [12] { - name: @index1 - }.single_int32 - } } } - CALL [13] { + CALL [7] { function: _+_ args: { - CALL [14] { + CALL [8] { function: _+_ args: { - CALL [15] { + CALL [9] { function: _+_ args: { - CALL [16] { + CALL [10] { function: non_pure_custom_func args: { - IDENT [17] { - name: @index2 + IDENT [11] { + name: @index0 } } } - CALL [18] { + CALL [12] { function: non_pure_custom_func args: { - IDENT [19] { - name: @index4 + SELECT [13] { + SELECT [14] { + SELECT [15] { + IDENT [16] { + name: msg + }.oneof_type + }.payload + }.single_int32 } } } } } - CALL [20] { + CALL [17] { function: non_pure_custom_func args: { - IDENT [21] { - name: @index2 + IDENT [18] { + name: @index0 } } } } } - CALL [22] { + CALL [19] { function: non_pure_custom_func args: { - IDENT [23] { - name: @index3 + SELECT [20] { + IDENT [21] { + name: msg + }.single_int64 } } } @@ -3368,75 +3032,64 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - SELECT [3] { - IDENT [4] { - name: msg - }.oneof_type - } - SELECT [5] { - IDENT [6] { - name: @index0 - }.payload - } - SELECT [7] { - IDENT [8] { - name: @index1 - }.single_int64 - } - CALL [9] { - function: pure_custom_func - args: { - IDENT [10] { - name: @index2 - } - } - } - CALL [11] { + CALL [3] { function: pure_custom_func args: { - SELECT [12] { - IDENT [13] { - name: msg + SELECT [4] { + SELECT [5] { + SELECT [6] { + IDENT [7] { + name: msg + }.oneof_type + }.payload }.single_int64 } } } - CALL [14] { + } + } + CALL [8] { + function: _+_ + args: { + CALL [9] { function: _+_ args: { - CALL [15] { + CALL [10] { function: _+_ args: { - IDENT [16] { - name: @index3 + IDENT [11] { + name: @index0 } - CALL [17] { + CALL [12] { function: pure_custom_func args: { - SELECT [18] { - IDENT [19] { - name: @index1 + SELECT [13] { + SELECT [14] { + SELECT [15] { + IDENT [16] { + name: msg + }.oneof_type + }.payload }.single_int32 } } } } } - IDENT [20] { - name: @index3 + IDENT [17] { + name: @index0 } } } - } - } - CALL [21] { - function: _+_ - args: { - IDENT [22] { - name: @index5 - } - IDENT [23] { - name: @index4 + CALL [18] { + function: pure_custom_func + args: { + SELECT [19] { + IDENT [20] { + name: msg + }.single_int64 + } + } } } } diff --git a/optimizer/src/test/resources/subexpression_unparsed.baseline b/optimizer/src/test/resources/subexpression_unparsed.baseline index f820ae1e8..28d55996b 100644 --- a/optimizer/src/test/resources/subexpression_unparsed.baseline +++ b/optimizer/src/test/resources/subexpression_unparsed.baseline @@ -5,14 +5,14 @@ Result: true [CASCADED_BINDS]: cel.bind(@r0, size([1, 2]), @r0 + @r0) + 1 == 5 [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([size([1, 2])], @index0 + @index0 + 1 == 5) [BLOCK_RECURSION_DEPTH_1]: cel.@block([[1, 2], size(@index0), @index1 + @index1, @index2 + 1], @index3 == 5) -[BLOCK_RECURSION_DEPTH_2]: cel.@block([[1, 2], size(@index0), @index1 + @index1 + 1], @index2 == 5) -[BLOCK_RECURSION_DEPTH_3]: cel.@block([[1, 2], size(@index0), @index1 + @index1 + 1], @index2 == 5) -[BLOCK_RECURSION_DEPTH_4]: cel.@block([[1, 2], size(@index0), @index1 + @index1 + 1], @index2 == 5) -[BLOCK_RECURSION_DEPTH_5]: cel.@block([[1, 2], size(@index0), @index1 + @index1 + 1], @index2 == 5) -[BLOCK_RECURSION_DEPTH_6]: cel.@block([[1, 2], size(@index0), @index1 + @index1 + 1], @index2 == 5) -[BLOCK_RECURSION_DEPTH_7]: cel.@block([[1, 2], size(@index0), @index1 + @index1 + 1], @index2 == 5) -[BLOCK_RECURSION_DEPTH_8]: cel.@block([[1, 2], size(@index0), @index1 + @index1 + 1], @index2 == 5) -[BLOCK_RECURSION_DEPTH_9]: cel.@block([[1, 2], size(@index0), @index1 + @index1 + 1], @index2 == 5) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([size([1, 2]), @index0 + @index0 + 1], @index1 == 5) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([size([1, 2])], @index0 + @index0 + 1 == 5) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([size([1, 2])], @index0 + @index0 + 1 == 5) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([size([1, 2])], @index0 + @index0 + 1 == 5) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([size([1, 2])], @index0 + @index0 + 1 == 5) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([size([1, 2])], @index0 + @index0 + 1 == 5) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([size([1, 2])], @index0 + @index0 + 1 == 5) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([size([1, 2])], @index0 + @index0 + 1 == 5) Test case: SIZE_2 Source: 2 + size([1,2]) + size([1,2]) + 1 == 7 @@ -21,14 +21,14 @@ Result: true [CASCADED_BINDS]: cel.bind(@r0, size([1, 2]), 2 + @r0 + @r0) + 1 == 7 [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([size([1, 2])], 2 + @index0 + @index0 + 1 == 7) [BLOCK_RECURSION_DEPTH_1]: cel.@block([[1, 2], size(@index0), 2 + @index1, @index2 + @index1, @index3 + 1], @index4 == 7) -[BLOCK_RECURSION_DEPTH_2]: cel.@block([[1, 2], size(@index0), 2 + @index1 + @index1, @index2 + 1], @index3 == 7) -[BLOCK_RECURSION_DEPTH_3]: cel.@block([[1, 2], size(@index0), 2 + @index1 + @index1 + 1], @index2 == 7) -[BLOCK_RECURSION_DEPTH_4]: cel.@block([[1, 2], size(@index0), 2 + @index1 + @index1 + 1], @index2 == 7) -[BLOCK_RECURSION_DEPTH_5]: cel.@block([[1, 2], size(@index0), 2 + @index1 + @index1 + 1], @index2 == 7) -[BLOCK_RECURSION_DEPTH_6]: cel.@block([[1, 2], size(@index0), 2 + @index1 + @index1 + 1], @index2 == 7) -[BLOCK_RECURSION_DEPTH_7]: cel.@block([[1, 2], size(@index0), 2 + @index1 + @index1 + 1], @index2 == 7) -[BLOCK_RECURSION_DEPTH_8]: cel.@block([[1, 2], size(@index0), 2 + @index1 + @index1 + 1], @index2 == 7) -[BLOCK_RECURSION_DEPTH_9]: cel.@block([[1, 2], size(@index0), 2 + @index1 + @index1 + 1], @index2 == 7) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([size([1, 2]), 2 + @index0 + @index0], @index1 + 1 == 7) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([size([1, 2]), 2 + @index0 + @index0 + 1], @index1 == 7) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([size([1, 2])], 2 + @index0 + @index0 + 1 == 7) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([size([1, 2])], 2 + @index0 + @index0 + 1 == 7) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([size([1, 2])], 2 + @index0 + @index0 + 1 == 7) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([size([1, 2])], 2 + @index0 + @index0 + 1 == 7) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([size([1, 2])], 2 + @index0 + @index0 + 1 == 7) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([size([1, 2])], 2 + @index0 + @index0 + 1 == 7) Test case: SIZE_3 Source: size([0]) + size([0]) + size([1,2]) + size([1,2]) == 6 @@ -37,14 +37,14 @@ Result: true [CASCADED_BINDS]: cel.bind(@r1, size([1, 2]), cel.bind(@r0, size([0]), @r0 + @r0) + @r1 + @r1) == 6 [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([size([0]), size([1, 2])], @index0 + @index0 + @index1 + @index1 == 6) [BLOCK_RECURSION_DEPTH_1]: cel.@block([[0], size(@index0), [1, 2], size(@index2), @index1 + @index1, @index4 + @index3, @index5 + @index3], @index6 == 6) -[BLOCK_RECURSION_DEPTH_2]: cel.@block([[0], size(@index0), [1, 2], size(@index2), @index1 + @index1 + @index3, @index4 + @index3], @index5 == 6) -[BLOCK_RECURSION_DEPTH_3]: cel.@block([[0], size(@index0), [1, 2], size(@index2), @index1 + @index1 + @index3 + @index3], @index4 == 6) -[BLOCK_RECURSION_DEPTH_4]: cel.@block([[0], size(@index0), [1, 2], size(@index2), @index1 + @index1 + @index3 + @index3], @index4 == 6) -[BLOCK_RECURSION_DEPTH_5]: cel.@block([[0], size(@index0), [1, 2], size(@index2), @index1 + @index1 + @index3 + @index3], @index4 == 6) -[BLOCK_RECURSION_DEPTH_6]: cel.@block([[0], size(@index0), [1, 2], size(@index2), @index1 + @index1 + @index3 + @index3], @index4 == 6) -[BLOCK_RECURSION_DEPTH_7]: cel.@block([[0], size(@index0), [1, 2], size(@index2), @index1 + @index1 + @index3 + @index3], @index4 == 6) -[BLOCK_RECURSION_DEPTH_8]: cel.@block([[0], size(@index0), [1, 2], size(@index2), @index1 + @index1 + @index3 + @index3], @index4 == 6) -[BLOCK_RECURSION_DEPTH_9]: cel.@block([[0], size(@index0), [1, 2], size(@index2), @index1 + @index1 + @index3 + @index3], @index4 == 6) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([size([0]), size([1, 2]), @index0 + @index0 + @index1], @index2 + @index1 == 6) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([size([0]), size([1, 2]), @index0 + @index0 + @index1 + @index1], @index2 == 6) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([size([0]), size([1, 2])], @index0 + @index0 + @index1 + @index1 == 6) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([size([0]), size([1, 2])], @index0 + @index0 + @index1 + @index1 == 6) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([size([0]), size([1, 2])], @index0 + @index0 + @index1 + @index1 == 6) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([size([0]), size([1, 2])], @index0 + @index0 + @index1 + @index1 == 6) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([size([0]), size([1, 2])], @index0 + @index0 + @index1 + @index1 == 6) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([size([0]), size([1, 2])], @index0 + @index0 + @index1 + @index1 == 6) Test case: SIZE_4 Source: 5 + size([0]) + size([0]) + size([1,2]) + size([1,2]) + size([1,2,3]) + size([1,2,3]) == 17 @@ -53,14 +53,14 @@ Result: true [CASCADED_BINDS]: cel.bind(@r2, size([1, 2, 3]), cel.bind(@r1, size([1, 2]), cel.bind(@r0, size([0]), 5 + @r0 + @r0) + @r1 + @r1) + @r2 + @r2) == 17 [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([size([0]), size([1, 2]), size([1, 2, 3])], 5 + @index0 + @index0 + @index1 + @index1 + @index2 + @index2 == 17) [BLOCK_RECURSION_DEPTH_1]: cel.@block([[0], size(@index0), [1, 2], size(@index2), [1, 2, 3], size(@index4), 5 + @index1, @index6 + @index1, @index7 + @index3, @index8 + @index3, @index9 + @index5, @index10 + @index5], @index11 == 17) -[BLOCK_RECURSION_DEPTH_2]: cel.@block([[0], size(@index0), [1, 2], size(@index2), [1, 2, 3], size(@index4), 5 + @index1 + @index1, @index6 + @index3 + @index3, @index7 + @index5 + @index5], @index8 == 17) -[BLOCK_RECURSION_DEPTH_3]: cel.@block([[0], size(@index0), [1, 2], size(@index2), [1, 2, 3], size(@index4), 5 + @index1 + @index1 + @index3, @index6 + @index3 + @index5 + @index5], @index7 == 17) -[BLOCK_RECURSION_DEPTH_4]: cel.@block([[0], size(@index0), [1, 2], size(@index2), [1, 2, 3], size(@index4), 5 + @index1 + @index1 + @index3 + @index3, @index6 + @index5 + @index5], @index7 == 17) -[BLOCK_RECURSION_DEPTH_5]: cel.@block([[0], size(@index0), [1, 2], size(@index2), [1, 2, 3], size(@index4), 5 + @index1 + @index1 + @index3 + @index3 + @index5, @index6 + @index5], @index7 == 17) -[BLOCK_RECURSION_DEPTH_6]: cel.@block([[0], size(@index0), [1, 2], size(@index2), [1, 2, 3], size(@index4), 5 + @index1 + @index1 + @index3 + @index3 + @index5 + @index5], @index6 == 17) -[BLOCK_RECURSION_DEPTH_7]: cel.@block([[0], size(@index0), [1, 2], size(@index2), [1, 2, 3], size(@index4), 5 + @index1 + @index1 + @index3 + @index3 + @index5 + @index5], @index6 == 17) -[BLOCK_RECURSION_DEPTH_8]: cel.@block([[0], size(@index0), [1, 2], size(@index2), [1, 2, 3], size(@index4), 5 + @index1 + @index1 + @index3 + @index3 + @index5 + @index5], @index6 == 17) -[BLOCK_RECURSION_DEPTH_9]: cel.@block([[0], size(@index0), [1, 2], size(@index2), [1, 2, 3], size(@index4), 5 + @index1 + @index1 + @index3 + @index3 + @index5 + @index5], @index6 == 17) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([size([0]), size([1, 2]), size([1, 2, 3]), 5 + @index0 + @index0, @index3 + @index1 + @index1, @index4 + @index2 + @index2], @index5 == 17) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([size([0]), size([1, 2]), size([1, 2, 3]), 5 + @index0 + @index0 + @index1, @index3 + @index1 + @index2 + @index2], @index4 == 17) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([size([0]), size([1, 2]), size([1, 2, 3]), 5 + @index0 + @index0 + @index1 + @index1], @index3 + @index2 + @index2 == 17) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([size([0]), size([1, 2]), size([1, 2, 3]), 5 + @index0 + @index0 + @index1 + @index1 + @index2], @index3 + @index2 == 17) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([size([0]), size([1, 2]), size([1, 2, 3]), 5 + @index0 + @index0 + @index1 + @index1 + @index2 + @index2], @index3 == 17) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([size([0]), size([1, 2]), size([1, 2, 3])], 5 + @index0 + @index0 + @index1 + @index1 + @index2 + @index2 == 17) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([size([0]), size([1, 2]), size([1, 2, 3])], 5 + @index0 + @index0 + @index1 + @index1 + @index2 + @index2 == 17) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([size([0]), size([1, 2]), size([1, 2, 3])], 5 + @index0 + @index0 + @index1 + @index1 + @index2 + @index2 == 17) Test case: TIMESTAMP Source: timestamp(int(timestamp(1000000000))).getFullYear() + timestamp(int(timestamp(75))).getFullYear() + timestamp(int(timestamp(50))).getFullYear() + timestamp(int(timestamp(1000000000))).getFullYear() + timestamp(int(timestamp(50))).getSeconds() + timestamp(int(timestamp(200))).getFullYear() + timestamp(int(timestamp(200))).getFullYear() + timestamp(int(timestamp(75))).getMinutes() + timestamp(int(timestamp(1000000000))).getFullYear() == 13934 @@ -68,15 +68,15 @@ Source: timestamp(int(timestamp(1000000000))).getFullYear() + timestamp(int(time Result: true [CASCADED_BINDS]: cel.bind(@r0, timestamp(int(timestamp(1000000000))).getFullYear(), cel.bind(@r3, timestamp(int(timestamp(75))), cel.bind(@r2, timestamp(int(timestamp(200))).getFullYear(), cel.bind(@r1, timestamp(int(timestamp(50))), @r0 + @r3.getFullYear() + @r1.getFullYear() + @r0 + @r1.getSeconds()) + @r2 + @r2) + @r3.getMinutes()) + @r0) == 13934 [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([timestamp(int(timestamp(1000000000))).getFullYear(), timestamp(int(timestamp(50))), timestamp(int(timestamp(200))).getFullYear(), timestamp(int(timestamp(75)))], @index0 + @index3.getFullYear() + @index1.getFullYear() + @index0 + @index1.getSeconds() + @index2 + @index2 + @index3.getMinutes() + @index0 == 13934) -[BLOCK_RECURSION_DEPTH_1]: cel.@block([timestamp(1000000000), int(@index0), timestamp(@index1), @index2.getFullYear(), timestamp(50), int(@index4), timestamp(@index5), timestamp(200), int(@index7), timestamp(@index8), @index9.getFullYear(), timestamp(75), int(@index11), timestamp(@index12), @index13.getMinutes(), @index6.getSeconds(), @index6.getFullYear(), @index13.getFullYear(), @index3 + @index17, @index18 + @index16, @index19 + @index3, @index20 + @index15, @index21 + @index10, @index22 + @index10, @index23 + @index14, @index24 + @index3], @index25 == 13934) -[BLOCK_RECURSION_DEPTH_2]: cel.@block([timestamp(1000000000), int(@index0), timestamp(@index1), @index2.getFullYear(), timestamp(50), int(@index4), timestamp(@index5), timestamp(200), int(@index7), timestamp(@index8), @index9.getFullYear(), timestamp(75), int(@index11), timestamp(@index12), @index13.getMinutes(), @index6.getSeconds(), @index6.getFullYear(), @index3 + @index13.getFullYear(), @index17 + @index16 + @index3, @index18 + @index15 + @index10, @index19 + @index10 + @index14, @index20 + @index3], @index21 == 13934) -[BLOCK_RECURSION_DEPTH_3]: cel.@block([timestamp(1000000000), int(@index0), timestamp(@index1), @index2.getFullYear(), timestamp(50), int(@index4), timestamp(@index5), timestamp(200), int(@index7), timestamp(@index8), @index9.getFullYear(), timestamp(75), int(@index11), timestamp(@index12), @index13.getMinutes(), @index6.getSeconds(), @index3 + @index13.getFullYear() + @index6.getFullYear(), @index16 + @index3 + @index15 + @index10, @index17 + @index10 + @index14 + @index3], @index18 == 13934) -[BLOCK_RECURSION_DEPTH_4]: cel.@block([timestamp(1000000000), int(@index0), timestamp(@index1), @index2.getFullYear(), timestamp(50), int(@index4), timestamp(@index5), timestamp(200), int(@index7), timestamp(@index8), @index9.getFullYear(), timestamp(75), int(@index11), timestamp(@index12), @index13.getMinutes(), @index6.getSeconds(), @index3 + @index13.getFullYear() + @index6.getFullYear() + @index3, @index16 + @index15 + @index10 + @index10 + @index14, @index17 + @index3], @index18 == 13934) -[BLOCK_RECURSION_DEPTH_5]: cel.@block([timestamp(1000000000), int(@index0), timestamp(@index1), @index2.getFullYear(), timestamp(50), int(@index4), timestamp(@index5), timestamp(200), int(@index7), timestamp(@index8), @index9.getFullYear(), timestamp(75), int(@index11), timestamp(@index12), @index13.getMinutes(), @index3 + @index13.getFullYear() + @index6.getFullYear() + @index3 + @index6.getSeconds(), @index15 + @index10 + @index10 + @index14 + @index3], @index16 == 13934) -[BLOCK_RECURSION_DEPTH_6]: cel.@block([timestamp(1000000000), int(@index0), timestamp(@index1), @index2.getFullYear(), timestamp(50), int(@index4), timestamp(@index5), timestamp(200), int(@index7), timestamp(@index8), @index9.getFullYear(), timestamp(75), int(@index11), timestamp(@index12), @index13.getMinutes(), @index3 + @index13.getFullYear() + @index6.getFullYear() + @index3 + @index6.getSeconds() + @index10, @index15 + @index10 + @index14 + @index3], @index16 == 13934) -[BLOCK_RECURSION_DEPTH_7]: cel.@block([timestamp(1000000000), int(@index0), timestamp(@index1), @index2.getFullYear(), timestamp(50), int(@index4), timestamp(@index5), timestamp(200), int(@index7), timestamp(@index8), @index9.getFullYear(), timestamp(75), int(@index11), timestamp(@index12), @index13.getMinutes(), @index3 + @index13.getFullYear() + @index6.getFullYear() + @index3 + @index6.getSeconds() + @index10 + @index10, @index15 + @index14 + @index3], @index16 == 13934) -[BLOCK_RECURSION_DEPTH_8]: cel.@block([timestamp(1000000000), int(@index0), timestamp(@index1), @index2.getFullYear(), timestamp(50), int(@index4), timestamp(@index5), timestamp(200), int(@index7), timestamp(@index8), @index9.getFullYear(), timestamp(75), int(@index11), timestamp(@index12), @index3 + @index13.getFullYear() + @index6.getFullYear() + @index3 + @index6.getSeconds() + @index10 + @index10 + @index13.getMinutes(), @index14 + @index3], @index15 == 13934) -[BLOCK_RECURSION_DEPTH_9]: cel.@block([timestamp(1000000000), int(@index0), timestamp(@index1), @index2.getFullYear(), timestamp(50), int(@index4), timestamp(@index5), timestamp(200), int(@index7), timestamp(@index8), @index9.getFullYear(), timestamp(75), int(@index11), timestamp(@index12), @index3 + @index13.getFullYear() + @index6.getFullYear() + @index3 + @index6.getSeconds() + @index10 + @index10 + @index13.getMinutes() + @index3], @index14 == 13934) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([timestamp(1000000000), int(@index0), timestamp(@index1), @index2.getFullYear(), timestamp(50), int(@index4), timestamp(@index5), timestamp(200), int(@index7), timestamp(@index8), @index9.getFullYear(), timestamp(75), int(@index11), timestamp(@index12), @index13.getFullYear(), @index3 + @index14, @index6.getFullYear(), @index15 + @index16, @index17 + @index3, @index6.getSeconds(), @index18 + @index19, @index20 + @index10, @index21 + @index10, @index13.getMinutes(), @index22 + @index23, @index24 + @index3], @index25 == 13934) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([int(timestamp(1000000000)), timestamp(@index0).getFullYear(), int(timestamp(50)), int(timestamp(200)), timestamp(@index3).getFullYear(), int(timestamp(75)), timestamp(@index2), timestamp(@index5), @index1 + @index7.getFullYear(), @index8 + @index6.getFullYear(), @index9 + @index1 + @index6.getSeconds(), @index10 + @index4 + @index4, @index11 + @index7.getMinutes()], @index12 + @index1 == 13934) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([timestamp(int(timestamp(1000000000))), timestamp(int(timestamp(50))), timestamp(int(timestamp(200))), timestamp(int(timestamp(75))), @index0.getFullYear(), @index2.getFullYear(), @index4 + @index3.getFullYear() + @index1.getFullYear(), @index6 + @index4 + @index1.getSeconds() + @index5, @index7 + @index5 + @index3.getMinutes() + @index4], @index8 == 13934) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([timestamp(int(timestamp(1000000000))).getFullYear(), timestamp(int(timestamp(200))).getFullYear(), timestamp(int(timestamp(50))), timestamp(int(timestamp(75))), @index0 + @index3.getFullYear() + @index2.getFullYear() + @index0, @index4 + @index2.getSeconds() + @index1 + @index1], @index5 + @index3.getMinutes() + @index0 == 13934) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([timestamp(int(timestamp(1000000000))).getFullYear(), timestamp(int(timestamp(200))).getFullYear(), timestamp(int(timestamp(50))), timestamp(int(timestamp(75))), @index0 + @index3.getFullYear() + @index2.getFullYear() + @index0 + @index2.getSeconds()], @index4 + @index1 + @index1 + @index3.getMinutes() + @index0 == 13934) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([timestamp(int(timestamp(1000000000))).getFullYear(), timestamp(int(timestamp(200))).getFullYear(), timestamp(int(timestamp(50))), timestamp(int(timestamp(75))), @index0 + @index3.getFullYear() + @index2.getFullYear() + @index0 + @index2.getSeconds() + @index1], @index4 + @index1 + @index3.getMinutes() + @index0 == 13934) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([timestamp(int(timestamp(1000000000))).getFullYear(), timestamp(int(timestamp(200))).getFullYear(), timestamp(int(timestamp(50))), timestamp(int(timestamp(75))), @index0 + @index3.getFullYear() + @index2.getFullYear() + @index0 + @index2.getSeconds() + @index1 + @index1], @index4 + @index3.getMinutes() + @index0 == 13934) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([timestamp(int(timestamp(1000000000))).getFullYear(), timestamp(int(timestamp(200))).getFullYear(), timestamp(int(timestamp(50))), timestamp(int(timestamp(75))), @index0 + @index3.getFullYear() + @index2.getFullYear() + @index0 + @index2.getSeconds() + @index1 + @index1 + @index3.getMinutes()], @index4 + @index0 == 13934) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([timestamp(int(timestamp(1000000000))).getFullYear(), timestamp(int(timestamp(200))).getFullYear(), timestamp(int(timestamp(50))), timestamp(int(timestamp(75))), @index0 + @index3.getFullYear() + @index2.getFullYear() + @index0 + @index2.getSeconds() + @index1 + @index1 + @index3.getMinutes() + @index0], @index4 == 13934) Test case: MAP_INDEX Source: {"a": 2}["a"] + {"a": 2}["a"] * {"a": 2}["a"] == 6 @@ -85,14 +85,14 @@ Result: true [CASCADED_BINDS]: cel.bind(@r0, {"a": 2}["a"], @r0 + @r0 * @r0) == 6 [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([{"a": 2}["a"]], @index0 + @index0 * @index0 == 6) [BLOCK_RECURSION_DEPTH_1]: cel.@block([{"a": 2}, @index0["a"], @index1 * @index1, @index1 + @index2], @index3 == 6) -[BLOCK_RECURSION_DEPTH_2]: cel.@block([{"a": 2}, @index0["a"], @index1 + @index1 * @index1], @index2 == 6) -[BLOCK_RECURSION_DEPTH_3]: cel.@block([{"a": 2}, @index0["a"], @index1 + @index1 * @index1], @index2 == 6) -[BLOCK_RECURSION_DEPTH_4]: cel.@block([{"a": 2}, @index0["a"], @index1 + @index1 * @index1], @index2 == 6) -[BLOCK_RECURSION_DEPTH_5]: cel.@block([{"a": 2}, @index0["a"], @index1 + @index1 * @index1], @index2 == 6) -[BLOCK_RECURSION_DEPTH_6]: cel.@block([{"a": 2}, @index0["a"], @index1 + @index1 * @index1], @index2 == 6) -[BLOCK_RECURSION_DEPTH_7]: cel.@block([{"a": 2}, @index0["a"], @index1 + @index1 * @index1], @index2 == 6) -[BLOCK_RECURSION_DEPTH_8]: cel.@block([{"a": 2}, @index0["a"], @index1 + @index1 * @index1], @index2 == 6) -[BLOCK_RECURSION_DEPTH_9]: cel.@block([{"a": 2}, @index0["a"], @index1 + @index1 * @index1], @index2 == 6) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([{"a": 2}["a"], @index0 + @index0 * @index0], @index1 == 6) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([{"a": 2}["a"]], @index0 + @index0 * @index0 == 6) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([{"a": 2}["a"]], @index0 + @index0 * @index0 == 6) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([{"a": 2}["a"]], @index0 + @index0 * @index0 == 6) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([{"a": 2}["a"]], @index0 + @index0 * @index0 == 6) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([{"a": 2}["a"]], @index0 + @index0 * @index0 == 6) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([{"a": 2}["a"]], @index0 + @index0 * @index0 == 6) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([{"a": 2}["a"]], @index0 + @index0 * @index0 == 6) Test case: NESTED_MAP_CONSTRUCTION Source: {'a': {'b': 1}, 'c': {'b': 1}, 'd': {'e': {'b': 1}}, 'e': {'e': {'b': 1}}} @@ -101,14 +101,14 @@ Result: {a={b=1}, c={b=1}, d={e={b=1}}, e={e={b=1}}} [CASCADED_BINDS]: cel.bind(@r0, {"b": 1}, cel.bind(@r1, {"e": @r0}, {"a": @r0, "c": @r0, "d": @r1, "e": @r1})) [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([{"b": 1}, {"e": @index0}], {"a": @index0, "c": @index0, "d": @index1, "e": @index1}) [BLOCK_RECURSION_DEPTH_1]: cel.@block([{"b": 1}, {"e": @index0}], {"a": @index0, "c": @index0, "d": @index1, "e": @index1}) -[BLOCK_RECURSION_DEPTH_2]: cel.@block([{"b": 1}, {"e": @index0}], {"a": @index0, "c": @index0, "d": @index1, "e": @index1}) -[BLOCK_RECURSION_DEPTH_3]: cel.@block([{"b": 1}, {"e": @index0}], {"a": @index0, "c": @index0, "d": @index1, "e": @index1}) -[BLOCK_RECURSION_DEPTH_4]: cel.@block([{"b": 1}, {"e": @index0}], {"a": @index0, "c": @index0, "d": @index1, "e": @index1}) -[BLOCK_RECURSION_DEPTH_5]: cel.@block([{"b": 1}, {"e": @index0}], {"a": @index0, "c": @index0, "d": @index1, "e": @index1}) -[BLOCK_RECURSION_DEPTH_6]: cel.@block([{"b": 1}, {"e": @index0}], {"a": @index0, "c": @index0, "d": @index1, "e": @index1}) -[BLOCK_RECURSION_DEPTH_7]: cel.@block([{"b": 1}, {"e": @index0}], {"a": @index0, "c": @index0, "d": @index1, "e": @index1}) -[BLOCK_RECURSION_DEPTH_8]: cel.@block([{"b": 1}, {"e": @index0}], {"a": @index0, "c": @index0, "d": @index1, "e": @index1}) -[BLOCK_RECURSION_DEPTH_9]: cel.@block([{"b": 1}, {"e": @index0}], {"a": @index0, "c": @index0, "d": @index1, "e": @index1}) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([{"e": {"b": 1}}, {"b": 1}], {"a": @index1, "c": @index1, "d": @index0, "e": @index0}) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([{"e": {"b": 1}}, {"b": 1}], {"a": @index1, "c": @index1, "d": @index0, "e": @index0}) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([{"e": {"b": 1}}, {"b": 1}], {"a": @index1, "c": @index1, "d": @index0, "e": @index0}) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([{"e": {"b": 1}}, {"b": 1}], {"a": @index1, "c": @index1, "d": @index0, "e": @index0}) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([{"e": {"b": 1}}, {"b": 1}], {"a": @index1, "c": @index1, "d": @index0, "e": @index0}) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([{"e": {"b": 1}}, {"b": 1}], {"a": @index1, "c": @index1, "d": @index0, "e": @index0}) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([{"e": {"b": 1}}, {"b": 1}], {"a": @index1, "c": @index1, "d": @index0, "e": @index0}) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([{"e": {"b": 1}}, {"b": 1}], {"a": @index1, "c": @index1, "d": @index0, "e": @index0}) Test case: NESTED_LIST_CONSTRUCTION Source: [1, [1,2,3,4], 2, [1,2,3,4], 5, [1,2,3,4], 7, [[1,2], [1,2,3,4]], [1,2]] @@ -117,14 +117,14 @@ Result: [1, [1, 2, 3, 4], 2, [1, 2, 3, 4], 5, [1, 2, 3, 4], 7, [[1, 2], [1, 2, 3 [CASCADED_BINDS]: cel.bind(@r0, [1, 2, 3, 4], cel.bind(@r1, [1, 2], [1, @r0, 2, @r0, 5, @r0, 7, [@r1, @r0], @r1])) [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([[1, 2, 3, 4], [1, 2]], [1, @index0, 2, @index0, 5, @index0, 7, [@index1, @index0], @index1]) [BLOCK_RECURSION_DEPTH_1]: cel.@block([[1, 2, 3, 4], [1, 2], [@index1, @index0]], [1, @index0, 2, @index0, 5, @index0, 7, @index2, @index1]) -[BLOCK_RECURSION_DEPTH_2]: cel.@block([[1, 2, 3, 4], [1, 2], [@index1, @index0]], [1, @index0, 2, @index0, 5, @index0, 7, @index2, @index1]) -[BLOCK_RECURSION_DEPTH_3]: cel.@block([[1, 2, 3, 4], [1, 2], [@index1, @index0]], [1, @index0, 2, @index0, 5, @index0, 7, @index2, @index1]) -[BLOCK_RECURSION_DEPTH_4]: cel.@block([[1, 2, 3, 4], [1, 2], [@index1, @index0]], [1, @index0, 2, @index0, 5, @index0, 7, @index2, @index1]) -[BLOCK_RECURSION_DEPTH_5]: cel.@block([[1, 2, 3, 4], [1, 2], [@index1, @index0]], [1, @index0, 2, @index0, 5, @index0, 7, @index2, @index1]) -[BLOCK_RECURSION_DEPTH_6]: cel.@block([[1, 2, 3, 4], [1, 2], [@index1, @index0]], [1, @index0, 2, @index0, 5, @index0, 7, @index2, @index1]) -[BLOCK_RECURSION_DEPTH_7]: cel.@block([[1, 2, 3, 4], [1, 2], [@index1, @index0]], [1, @index0, 2, @index0, 5, @index0, 7, @index2, @index1]) -[BLOCK_RECURSION_DEPTH_8]: cel.@block([[1, 2, 3, 4], [1, 2], [@index1, @index0]], [1, @index0, 2, @index0, 5, @index0, 7, @index2, @index1]) -[BLOCK_RECURSION_DEPTH_9]: cel.@block([[1, 2, 3, 4], [1, 2], [@index1, @index0]], [1, @index0, 2, @index0, 5, @index0, 7, @index2, @index1]) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([[1, 2, 3, 4], [1, 2]], [1, @index0, 2, @index0, 5, @index0, 7, [@index1, @index0], @index1]) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([[1, 2, 3, 4], [1, 2]], [1, @index0, 2, @index0, 5, @index0, 7, [@index1, @index0], @index1]) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([[1, 2, 3, 4], [1, 2]], [1, @index0, 2, @index0, 5, @index0, 7, [@index1, @index0], @index1]) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([[1, 2, 3, 4], [1, 2]], [1, @index0, 2, @index0, 5, @index0, 7, [@index1, @index0], @index1]) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([[1, 2, 3, 4], [1, 2]], [1, @index0, 2, @index0, 5, @index0, 7, [@index1, @index0], @index1]) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([[1, 2, 3, 4], [1, 2]], [1, @index0, 2, @index0, 5, @index0, 7, [@index1, @index0], @index1]) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([[1, 2, 3, 4], [1, 2]], [1, @index0, 2, @index0, 5, @index0, 7, [@index1, @index0], @index1]) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([[1, 2, 3, 4], [1, 2]], [1, @index0, 2, @index0, 5, @index0, 7, [@index1, @index0], @index1]) Test case: SELECT Source: msg.single_int64 + msg.single_int64 == 6 @@ -133,14 +133,14 @@ Result: true [CASCADED_BINDS]: cel.bind(@r0, msg.single_int64, @r0 + @r0) == 6 [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.single_int64], @index0 + @index0 == 6) [BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.single_int64, @index0 + @index0], @index1 == 6) -[BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.single_int64, @index0 + @index0], @index1 == 6) -[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.single_int64, @index0 + @index0], @index1 == 6) -[BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.single_int64, @index0 + @index0], @index1 == 6) -[BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.single_int64, @index0 + @index0], @index1 == 6) -[BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.single_int64, @index0 + @index0], @index1 == 6) -[BLOCK_RECURSION_DEPTH_7]: cel.@block([msg.single_int64, @index0 + @index0], @index1 == 6) -[BLOCK_RECURSION_DEPTH_8]: cel.@block([msg.single_int64, @index0 + @index0], @index1 == 6) -[BLOCK_RECURSION_DEPTH_9]: cel.@block([msg.single_int64, @index0 + @index0], @index1 == 6) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.single_int64], @index0 + @index0 == 6) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.single_int64], @index0 + @index0 == 6) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.single_int64], @index0 + @index0 == 6) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.single_int64], @index0 + @index0 == 6) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.single_int64], @index0 + @index0 == 6) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([msg.single_int64], @index0 + @index0 == 6) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([msg.single_int64], @index0 + @index0 == 6) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([msg.single_int64], @index0 + @index0 == 6) Test case: SELECT_NESTED_1 Source: msg.oneof_type.payload.single_int64 + msg.oneof_type.payload.single_int32 + msg.oneof_type.payload.single_int64 + msg.single_int64 + msg.oneof_type.payload.oneof_type.payload.single_int64 == 31 @@ -148,15 +148,15 @@ Source: msg.oneof_type.payload.single_int64 + msg.oneof_type.payload.single_int3 Result: true [CASCADED_BINDS]: cel.bind(@r0, msg.oneof_type.payload, cel.bind(@r1, @r0.single_int64, @r1 + @r0.single_int32 + @r1) + msg.single_int64 + @r0.oneof_type.payload.single_int64) == 31 [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.oneof_type.payload, @index0.single_int64], @index1 + @index0.single_int32 + @index1 + msg.single_int64 + @index0.oneof_type.payload.single_int64 == 31) -[BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, @index1.oneof_type, @index3.payload, @index4.single_int64, msg.single_int64, @index1.single_int32, @index2 + @index7, @index8 + @index2, @index9 + @index6, @index10 + @index5], @index11 == 31) -[BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, @index1.oneof_type.payload, @index3.single_int64, msg.single_int64, @index2 + @index1.single_int32, @index6 + @index2 + @index5, @index7 + @index4], @index8 == 31) -[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, @index1.oneof_type.payload.single_int64, msg.single_int64, @index2 + @index1.single_int32 + @index2, @index5 + @index4 + @index3], @index6 == 31) -[BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, @index1.oneof_type.payload.single_int64, @index2 + @index1.single_int32 + @index2 + msg.single_int64, @index4 + @index3], @index5 == 31) -[BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, @index2 + @index1.single_int32 + @index2 + msg.single_int64 + @index1.oneof_type.payload.single_int64], @index3 == 31) -[BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, @index2 + @index1.single_int32 + @index2 + msg.single_int64 + @index1.oneof_type.payload.single_int64], @index3 == 31) -[BLOCK_RECURSION_DEPTH_7]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, @index2 + @index1.single_int32 + @index2 + msg.single_int64 + @index1.oneof_type.payload.single_int64], @index3 == 31) -[BLOCK_RECURSION_DEPTH_8]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, @index2 + @index1.single_int32 + @index2 + msg.single_int64 + @index1.oneof_type.payload.single_int64], @index3 == 31) -[BLOCK_RECURSION_DEPTH_9]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, @index2 + @index1.single_int32 + @index2 + msg.single_int64 + @index1.oneof_type.payload.single_int64], @index3 == 31) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, @index1.single_int32, @index2 + @index3, @index4 + @index2, msg.single_int64, @index5 + @index6, @index1.oneof_type, @index8.payload, @index9.single_int64, @index7 + @index10], @index11 == 31) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type.payload, @index0.single_int64, @index1 + @index0.single_int32, @index2 + @index1 + msg.single_int64, @index0.oneof_type.payload, @index3 + @index4.single_int64], @index5 == 31) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type.payload.single_int64, msg.oneof_type.payload, @index0 + @index1.single_int32 + @index0, @index1.oneof_type.payload.single_int64, @index2 + msg.single_int64 + @index3], @index4 == 31) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.oneof_type.payload.single_int64, msg.oneof_type.payload, @index0 + @index1.single_int32 + @index0 + msg.single_int64, @index2 + @index1.oneof_type.payload.single_int64], @index3 == 31) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.oneof_type.payload.single_int64, msg.oneof_type.payload, @index0 + @index1.single_int32 + @index0 + msg.single_int64 + @index1.oneof_type.payload.single_int64], @index2 == 31) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.oneof_type.payload.single_int64, msg.oneof_type.payload], @index0 + @index1.single_int32 + @index0 + msg.single_int64 + @index1.oneof_type.payload.single_int64 == 31) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([msg.oneof_type.payload.single_int64, msg.oneof_type.payload], @index0 + @index1.single_int32 + @index0 + msg.single_int64 + @index1.oneof_type.payload.single_int64 == 31) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([msg.oneof_type.payload.single_int64, msg.oneof_type.payload], @index0 + @index1.single_int32 + @index0 + msg.single_int64 + @index1.oneof_type.payload.single_int64 == 31) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([msg.oneof_type.payload.single_int64, msg.oneof_type.payload], @index0 + @index1.single_int32 + @index0 + msg.single_int64 + @index1.oneof_type.payload.single_int64 == 31) Test case: SELECT_NESTED_2 Source: true || msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload.single_bool || msg.oneof_type.payload.oneof_type.payload.oneof_type.child.child.payload.single_bool @@ -164,15 +164,15 @@ Source: true || msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.one Result: true [CASCADED_BINDS]: cel.bind(@r0, msg.oneof_type.payload.oneof_type.payload.oneof_type, true || @r0.payload.oneof_type.payload.single_bool || @r0.child.child.payload.single_bool) [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.oneof_type.payload.oneof_type.payload.oneof_type], true || @index0.payload.oneof_type.payload.single_bool || @index0.child.child.payload.single_bool) -[BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.oneof_type, @index2.payload, @index3.oneof_type, @index4.child, @index5.child, @index6.payload, @index7.single_bool, @index4.payload, @index9.oneof_type, @index10.payload, @index11.single_bool, true || @index12], @index13 || @index8) -[BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type, @index0.payload, @index1.oneof_type, @index2.payload, @index3.oneof_type, @index4.child.child, @index5.payload.single_bool, @index4.payload.oneof_type, @index7.payload.single_bool, true || @index8], @index9 || @index6) -[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type, @index0.payload, @index1.oneof_type, @index2.payload, @index3.oneof_type, @index4.child.child.payload, @index5.single_bool, @index4.payload.oneof_type.payload, true || @index7.single_bool], @index8 || @index6) -[BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.oneof_type, @index0.payload, @index1.oneof_type, @index2.payload, @index3.oneof_type, @index4.child.child.payload.single_bool, @index4.payload.oneof_type.payload.single_bool, true || @index6], @index7 || @index5) -[BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.oneof_type, @index0.payload, @index1.oneof_type, @index2.payload, @index3.oneof_type, @index4.child.child.payload.single_bool, true || @index4.payload.oneof_type.payload.single_bool], @index6 || @index5) -[BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.oneof_type, @index0.payload, @index1.oneof_type, @index2.payload, @index3.oneof_type, @index4.child.child.payload.single_bool, true || @index4.payload.oneof_type.payload.single_bool], @index6 || @index5) -[BLOCK_RECURSION_DEPTH_7]: cel.@block([msg.oneof_type, @index0.payload, @index1.oneof_type, @index2.payload, @index3.oneof_type, @index4.child.child.payload.single_bool, true || @index4.payload.oneof_type.payload.single_bool], @index6 || @index5) -[BLOCK_RECURSION_DEPTH_8]: cel.@block([msg.oneof_type, @index0.payload, @index1.oneof_type, @index2.payload, @index3.oneof_type, @index4.child.child.payload.single_bool, true || @index4.payload.oneof_type.payload.single_bool], @index6 || @index5) -[BLOCK_RECURSION_DEPTH_9]: cel.@block([msg.oneof_type, @index0.payload, @index1.oneof_type, @index2.payload, @index3.oneof_type, @index4.child.child.payload.single_bool, true || @index4.payload.oneof_type.payload.single_bool], @index6 || @index5) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.oneof_type, @index2.payload, @index3.oneof_type, @index4.payload, @index5.oneof_type, @index6.payload, @index7.single_bool, true || @index8, @index4.child, @index10.child, @index11.payload, @index12.single_bool], @index9 || @index13) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type.payload, @index0.oneof_type.payload, @index1.oneof_type, @index2.payload.oneof_type, @index3.payload.single_bool, @index2.child.child, @index5.payload.single_bool], true || @index4 || @index6) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type.payload.oneof_type, @index0.payload.oneof_type, @index1.payload.oneof_type.payload, @index1.child.child.payload], true || @index2.single_bool || @index3.single_bool) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.oneof_type.payload.oneof_type.payload, @index0.oneof_type, @index1.payload.oneof_type.payload.single_bool, @index1.child.child.payload.single_bool], true || @index2 || @index3) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.oneof_type.payload.oneof_type.payload.oneof_type, true || @index0.payload.oneof_type.payload.single_bool], @index1 || @index0.child.child.payload.single_bool) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.oneof_type.payload.oneof_type.payload.oneof_type], true || @index0.payload.oneof_type.payload.single_bool || @index0.child.child.payload.single_bool) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([msg.oneof_type.payload.oneof_type.payload.oneof_type], true || @index0.payload.oneof_type.payload.single_bool || @index0.child.child.payload.single_bool) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([msg.oneof_type.payload.oneof_type.payload.oneof_type], true || @index0.payload.oneof_type.payload.single_bool || @index0.child.child.payload.single_bool) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([msg.oneof_type.payload.oneof_type.payload.oneof_type], true || @index0.payload.oneof_type.payload.single_bool || @index0.child.child.payload.single_bool) Test case: SELECT_NESTED_MESSAGE_MAP_INDEX_1 Source: msg.oneof_type.payload.map_int32_int64[1] + msg.oneof_type.payload.map_int32_int64[1] + msg.oneof_type.payload.map_int32_int64[1] == 15 @@ -181,14 +181,14 @@ Result: true [CASCADED_BINDS]: cel.bind(@r0, msg.oneof_type.payload.map_int32_int64[1], @r0 + @r0 + @r0) == 15 [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.oneof_type.payload.map_int32_int64[1]], @index0 + @index0 + @index0 == 15) [BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_int32_int64, @index2[1], @index3 + @index3, @index4 + @index3], @index5 == 15) -[BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_int32_int64, @index2[1], @index3 + @index3 + @index3], @index4 == 15) -[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_int32_int64, @index2[1], @index3 + @index3 + @index3], @index4 == 15) -[BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_int32_int64, @index2[1], @index3 + @index3 + @index3], @index4 == 15) -[BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_int32_int64, @index2[1], @index3 + @index3 + @index3], @index4 == 15) -[BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_int32_int64, @index2[1], @index3 + @index3 + @index3], @index4 == 15) -[BLOCK_RECURSION_DEPTH_7]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_int32_int64, @index2[1], @index3 + @index3 + @index3], @index4 == 15) -[BLOCK_RECURSION_DEPTH_8]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_int32_int64, @index2[1], @index3 + @index3 + @index3], @index4 == 15) -[BLOCK_RECURSION_DEPTH_9]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_int32_int64, @index2[1], @index3 + @index3 + @index3], @index4 == 15) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type.payload, @index0.map_int32_int64[1], @index1 + @index1 + @index1], @index2 == 15) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type.payload.map_int32_int64, @index0[1]], @index1 + @index1 + @index1 == 15) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.oneof_type.payload.map_int32_int64[1]], @index0 + @index0 + @index0 == 15) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.oneof_type.payload.map_int32_int64[1]], @index0 + @index0 + @index0 == 15) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.oneof_type.payload.map_int32_int64[1]], @index0 + @index0 + @index0 == 15) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([msg.oneof_type.payload.map_int32_int64[1]], @index0 + @index0 + @index0 == 15) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([msg.oneof_type.payload.map_int32_int64[1]], @index0 + @index0 + @index0 == 15) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([msg.oneof_type.payload.map_int32_int64[1]], @index0 + @index0 + @index0 == 15) Test case: SELECT_NESTED_MESSAGE_MAP_INDEX_2 Source: msg.oneof_type.payload.map_int32_int64[0] + msg.oneof_type.payload.map_int32_int64[1] + msg.oneof_type.payload.map_int32_int64[2] == 8 @@ -196,15 +196,15 @@ Source: msg.oneof_type.payload.map_int32_int64[0] + msg.oneof_type.payload.map_i Result: true [CASCADED_BINDS]: cel.bind(@r0, msg.oneof_type.payload.map_int32_int64, @r0[0] + @r0[1] + @r0[2]) == 8 [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.oneof_type.payload.map_int32_int64], @index0[0] + @index0[1] + @index0[2] == 8) -[BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_int32_int64, @index2[2], @index2[1], @index2[0], @index5 + @index4, @index6 + @index3], @index7 == 8) -[BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_int32_int64, @index2[2], @index2[0] + @index2[1], @index4 + @index3], @index5 == 8) -[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_int32_int64, @index2[0] + @index2[1] + @index2[2]], @index3 == 8) -[BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_int32_int64, @index2[0] + @index2[1] + @index2[2]], @index3 == 8) -[BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_int32_int64, @index2[0] + @index2[1] + @index2[2]], @index3 == 8) -[BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_int32_int64, @index2[0] + @index2[1] + @index2[2]], @index3 == 8) -[BLOCK_RECURSION_DEPTH_7]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_int32_int64, @index2[0] + @index2[1] + @index2[2]], @index3 == 8) -[BLOCK_RECURSION_DEPTH_8]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_int32_int64, @index2[0] + @index2[1] + @index2[2]], @index3 == 8) -[BLOCK_RECURSION_DEPTH_9]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_int32_int64, @index2[0] + @index2[1] + @index2[2]], @index3 == 8) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_int32_int64, @index2[0], @index2[1], @index3 + @index4, @index2[2], @index5 + @index6], @index7 == 8) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type.payload, @index0.map_int32_int64, @index1[0] + @index1[1], @index2 + @index1[2]], @index3 == 8) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type.payload.map_int32_int64, @index0[0] + @index0[1] + @index0[2]], @index1 == 8) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.oneof_type.payload.map_int32_int64], @index0[0] + @index0[1] + @index0[2] == 8) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.oneof_type.payload.map_int32_int64], @index0[0] + @index0[1] + @index0[2] == 8) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.oneof_type.payload.map_int32_int64], @index0[0] + @index0[1] + @index0[2] == 8) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([msg.oneof_type.payload.map_int32_int64], @index0[0] + @index0[1] + @index0[2] == 8) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([msg.oneof_type.payload.map_int32_int64], @index0[0] + @index0[1] + @index0[2] == 8) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([msg.oneof_type.payload.map_int32_int64], @index0[0] + @index0[1] + @index0[2] == 8) Test case: SELECT_NESTED_NO_COMMON_SUBEXPR Source: msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload.single_int64 @@ -214,13 +214,13 @@ Result: 0 [BLOCK_COMMON_SUBEXPR_ONLY]: msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload.single_int64 [BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.oneof_type, @index2.payload, @index3.oneof_type, @index4.payload, @index5.oneof_type, @index6.payload], @index7.single_int64) [BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type.payload, @index0.oneof_type.payload, @index1.oneof_type.payload, @index2.oneof_type.payload], @index3.single_int64) -[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type.payload.oneof_type, @index0.payload.oneof_type.payload, @index1.oneof_type.payload], @index2.single_int64) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type.payload.oneof_type, @index0.payload.oneof_type.payload], @index1.oneof_type.payload.single_int64) [BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.oneof_type.payload.oneof_type.payload, @index0.oneof_type.payload.oneof_type.payload], @index1.single_int64) -[BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.oneof_type.payload.oneof_type.payload.oneof_type, @index0.payload.oneof_type.payload], @index1.single_int64) -[BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.oneof_type.payload.oneof_type.payload.oneof_type.payload, @index0.oneof_type.payload], @index1.single_int64) -[BLOCK_RECURSION_DEPTH_7]: cel.@block([msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type, @index0.payload], @index1.single_int64) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.oneof_type.payload.oneof_type.payload.oneof_type], @index0.payload.oneof_type.payload.single_int64) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.oneof_type.payload.oneof_type.payload.oneof_type.payload], @index0.oneof_type.payload.single_int64) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type], @index0.payload.single_int64) [BLOCK_RECURSION_DEPTH_8]: cel.@block([msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload], @index0.single_int64) -[BLOCK_RECURSION_DEPTH_9]: cel.@block([msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload], @index0.single_int64) +[BLOCK_RECURSION_DEPTH_9]: msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload.single_int64 Test case: TERNARY Source: (msg.single_int64 > 0 ? msg.single_int64 : 0) == 3 @@ -230,13 +230,13 @@ Result: true [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.single_int64], ((@index0 > 0) ? @index0 : 0) == 3) [BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.single_int64, @index0 > 0, @index1 ? @index0 : 0], @index2 == 3) [BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.single_int64, (@index0 > 0) ? @index0 : 0], @index1 == 3) -[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.single_int64, (@index0 > 0) ? @index0 : 0], @index1 == 3) -[BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.single_int64, (@index0 > 0) ? @index0 : 0], @index1 == 3) -[BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.single_int64, (@index0 > 0) ? @index0 : 0], @index1 == 3) -[BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.single_int64, (@index0 > 0) ? @index0 : 0], @index1 == 3) -[BLOCK_RECURSION_DEPTH_7]: cel.@block([msg.single_int64, (@index0 > 0) ? @index0 : 0], @index1 == 3) -[BLOCK_RECURSION_DEPTH_8]: cel.@block([msg.single_int64, (@index0 > 0) ? @index0 : 0], @index1 == 3) -[BLOCK_RECURSION_DEPTH_9]: cel.@block([msg.single_int64, (@index0 > 0) ? @index0 : 0], @index1 == 3) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.single_int64], ((@index0 > 0) ? @index0 : 0) == 3) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.single_int64], ((@index0 > 0) ? @index0 : 0) == 3) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.single_int64], ((@index0 > 0) ? @index0 : 0) == 3) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.single_int64], ((@index0 > 0) ? @index0 : 0) == 3) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([msg.single_int64], ((@index0 > 0) ? @index0 : 0) == 3) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([msg.single_int64], ((@index0 > 0) ? @index0 : 0) == 3) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([msg.single_int64], ((@index0 > 0) ? @index0 : 0) == 3) Test case: TERNARY_BIND_RHS_ONLY Source: false ? false : (msg.single_int64) + ((msg.single_int64 + 1) * 2) == 11 @@ -246,13 +246,13 @@ Result: true [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.single_int64], false ? false : (@index0 + (@index0 + 1) * 2 == 11)) [BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.single_int64, @index0 + 1, @index1 * 2, @index0 + @index2, @index3 == 11], false ? false : @index4) [BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.single_int64, (@index0 + 1) * 2, @index0 + @index1 == 11], false ? false : @index2) -[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.single_int64, @index0 + (@index0 + 1) * 2, @index1 == 11], false ? false : @index2) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.single_int64, @index0 + (@index0 + 1) * 2], false ? false : (@index1 == 11)) [BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.single_int64, @index0 + (@index0 + 1) * 2 == 11], false ? false : @index1) -[BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.single_int64, @index0 + (@index0 + 1) * 2 == 11], false ? false : @index1) -[BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.single_int64, @index0 + (@index0 + 1) * 2 == 11], false ? false : @index1) -[BLOCK_RECURSION_DEPTH_7]: cel.@block([msg.single_int64, @index0 + (@index0 + 1) * 2 == 11], false ? false : @index1) -[BLOCK_RECURSION_DEPTH_8]: cel.@block([msg.single_int64, @index0 + (@index0 + 1) * 2 == 11], false ? false : @index1) -[BLOCK_RECURSION_DEPTH_9]: cel.@block([msg.single_int64, @index0 + (@index0 + 1) * 2 == 11], false ? false : @index1) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.single_int64], false ? false : (@index0 + (@index0 + 1) * 2 == 11)) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.single_int64], false ? false : (@index0 + (@index0 + 1) * 2 == 11)) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([msg.single_int64], false ? false : (@index0 + (@index0 + 1) * 2 == 11)) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([msg.single_int64], false ? false : (@index0 + (@index0 + 1) * 2 == 11)) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([msg.single_int64], false ? false : (@index0 + (@index0 + 1) * 2 == 11)) Test case: NESTED_TERNARY Source: (msg.single_int64 > 0 ? (msg.single_int32 > 0 ? msg.single_int64 + msg.single_int32 : 0) : 0) == 8 @@ -260,15 +260,15 @@ Source: (msg.single_int64 > 0 ? (msg.single_int32 > 0 ? msg.single_int64 + msg.s Result: true [CASCADED_BINDS]: cel.bind(@r0, msg.single_int64, (@r0 > 0) ? cel.bind(@r1, msg.single_int32, (@r1 > 0) ? (@r0 + @r1) : 0) : 0) == 8 [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.single_int64, msg.single_int32], ((@index0 > 0) ? ((@index1 > 0) ? (@index0 + @index1) : 0) : 0) == 8) -[BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.single_int64, msg.single_int32, @index0 + @index1, @index1 > 0, @index3 ? @index2 : 0, @index0 > 0, @index5 ? @index4 : 0], @index6 == 8) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.single_int64, msg.single_int32, @index0 > 0, @index1 > 0, @index0 + @index1, @index3 ? @index4 : 0, @index2 ? @index5 : 0], @index6 == 8) [BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.single_int64, msg.single_int32, (@index1 > 0) ? (@index0 + @index1) : 0, (@index0 > 0) ? @index2 : 0], @index3 == 8) [BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.single_int64, msg.single_int32, (@index0 > 0) ? ((@index1 > 0) ? (@index0 + @index1) : 0) : 0], @index2 == 8) -[BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.single_int64, msg.single_int32, (@index0 > 0) ? ((@index1 > 0) ? (@index0 + @index1) : 0) : 0], @index2 == 8) -[BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.single_int64, msg.single_int32, (@index0 > 0) ? ((@index1 > 0) ? (@index0 + @index1) : 0) : 0], @index2 == 8) -[BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.single_int64, msg.single_int32, (@index0 > 0) ? ((@index1 > 0) ? (@index0 + @index1) : 0) : 0], @index2 == 8) -[BLOCK_RECURSION_DEPTH_7]: cel.@block([msg.single_int64, msg.single_int32, (@index0 > 0) ? ((@index1 > 0) ? (@index0 + @index1) : 0) : 0], @index2 == 8) -[BLOCK_RECURSION_DEPTH_8]: cel.@block([msg.single_int64, msg.single_int32, (@index0 > 0) ? ((@index1 > 0) ? (@index0 + @index1) : 0) : 0], @index2 == 8) -[BLOCK_RECURSION_DEPTH_9]: cel.@block([msg.single_int64, msg.single_int32, (@index0 > 0) ? ((@index1 > 0) ? (@index0 + @index1) : 0) : 0], @index2 == 8) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.single_int64, msg.single_int32], ((@index0 > 0) ? ((@index1 > 0) ? (@index0 + @index1) : 0) : 0) == 8) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.single_int64, msg.single_int32], ((@index0 > 0) ? ((@index1 > 0) ? (@index0 + @index1) : 0) : 0) == 8) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.single_int64, msg.single_int32], ((@index0 > 0) ? ((@index1 > 0) ? (@index0 + @index1) : 0) : 0) == 8) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([msg.single_int64, msg.single_int32], ((@index0 > 0) ? ((@index1 > 0) ? (@index0 + @index1) : 0) : 0) == 8) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([msg.single_int64, msg.single_int32], ((@index0 > 0) ? ((@index1 > 0) ? (@index0 + @index1) : 0) : 0) == 8) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([msg.single_int64, msg.single_int32], ((@index0 > 0) ? ((@index1 > 0) ? (@index0 + @index1) : 0) : 0) == 8) Test case: MULTIPLE_MACROS_1 Source: size([[1].exists(i, i > 0)]) + size([[1].exists(j, j > 0)]) + size([[2].exists(k, k > 1)]) + size([[2].exists(l, l > 1)]) == 4 @@ -277,14 +277,14 @@ Result: true [CASCADED_BINDS]: cel.bind(@r1, size([[2].exists(@c0:0, @c0:0 > 1)]), cel.bind(@r0, size([[1].exists(@c0:0, @c0:0 > 0)]), @r0 + @r0) + @r1 + @r1) == 4 [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([size([[1].exists(@c0:0, @c0:0 > 0)]), size([[2].exists(@c0:0, @c0:0 > 1)])], @index0 + @index0 + @index1 + @index1 == 4) [BLOCK_RECURSION_DEPTH_1]: cel.@block([[1], @c0:0 > 0, @x0:0 || @index1, [2], @c0:0 > 1, @x0:0 || @index4], size([@index0.exists(@c0:0, @index1)]) + size([@index0.exists(@c0:0, @index1)]) + size([@index3.exists(@c0:0, @index4)]) + size([@index3.exists(@c0:0, @index4)]) == 4) -[BLOCK_RECURSION_DEPTH_2]: cel.@block([[1], @c0:0 > 0, @x0:0 || @index1, [2], @c0:0 > 1, @x0:0 || @index4], size([@index0.exists(@c0:0, @index1)]) + size([@index0.exists(@c0:0, @index1)]) + size([@index3.exists(@c0:0, @index4)]) + size([@index3.exists(@c0:0, @index4)]) == 4) -[BLOCK_RECURSION_DEPTH_3]: cel.@block([[1], @c0:0 > 0, @x0:0 || @index1, @index0.exists(@c0:0, @index1), [@index3], size(@index4), [2], @c0:0 > 1, @x0:0 || @index7, @index6.exists(@c0:0, @index7), [@index9], size(@index10), @index5 + @index5 + @index11 + @index11], @index12 == 4) -[BLOCK_RECURSION_DEPTH_4]: cel.@block([[1], @c0:0 > 0, @x0:0 || @index1, @index0.exists(@c0:0, @index1), [@index3], size(@index4), [2], @c0:0 > 1, @x0:0 || @index7, @index6.exists(@c0:0, @index7), [@index9], size(@index10), @index5 + @index5 + @index11 + @index11], @index12 == 4) -[BLOCK_RECURSION_DEPTH_5]: cel.@block([[1], @c0:0 > 0, @x0:0 || @index1, @index0.exists(@c0:0, @index1), [@index3], size(@index4), [2], @c0:0 > 1, @x0:0 || @index7, @index6.exists(@c0:0, @index7), [@index9], size(@index10), @index5 + @index5 + @index11 + @index11], @index12 == 4) -[BLOCK_RECURSION_DEPTH_6]: cel.@block([[1], @c0:0 > 0, @x0:0 || @index1, @index0.exists(@c0:0, @index1), [@index3], size(@index4), [2], @c0:0 > 1, @x0:0 || @index7, @index6.exists(@c0:0, @index7), [@index9], size(@index10), @index5 + @index5 + @index11 + @index11], @index12 == 4) -[BLOCK_RECURSION_DEPTH_7]: cel.@block([[1], @c0:0 > 0, @x0:0 || @index1, @index0.exists(@c0:0, @index1), [@index3], size(@index4), [2], @c0:0 > 1, @x0:0 || @index7, @index6.exists(@c0:0, @index7), [@index9], size(@index10), @index5 + @index5 + @index11 + @index11], @index12 == 4) -[BLOCK_RECURSION_DEPTH_8]: cel.@block([[1], @c0:0 > 0, @x0:0 || @index1, @index0.exists(@c0:0, @index1), [@index3], size(@index4), [2], @c0:0 > 1, @x0:0 || @index7, @index6.exists(@c0:0, @index7), [@index9], size(@index10), @index5 + @index5 + @index11 + @index11], @index12 == 4) -[BLOCK_RECURSION_DEPTH_9]: cel.@block([[1], @c0:0 > 0, @x0:0 || @index1, @index0.exists(@c0:0, @index1), [@index3], size(@index4), [2], @c0:0 > 1, @x0:0 || @index7, @index6.exists(@c0:0, @index7), [@index9], size(@index10), @index5 + @index5 + @index11 + @index11], @index12 == 4) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([@x0:0 || @c0:0 > 0, @x0:0 || @c0:0 > 1, [1], [2]], size([@index2.exists(@c0:0, @c0:0 > 0)]) + size([@index2.exists(@c0:0, @c0:0 > 0)]) + size([@index3.exists(@c0:0, @c0:0 > 1)]) + size([@index3.exists(@c0:0, @c0:0 > 1)]) == 4) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([[1].exists(@c0:0, @c0:0 > 0), [2].exists(@c0:0, @c0:0 > 1), size([@index0]), size([@index1]), @index2 + @index2 + @index3 + @index3], @index4 == 4) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([[[1].exists(@c0:0, @c0:0 > 0)], [[2].exists(@c0:0, @c0:0 > 1)], size(@index0), size(@index1)], @index2 + @index2 + @index3 + @index3 == 4) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([size([[1].exists(@c0:0, @c0:0 > 0)]), size([[2].exists(@c0:0, @c0:0 > 1)])], @index0 + @index0 + @index1 + @index1 == 4) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([size([[1].exists(@c0:0, @c0:0 > 0)]), size([[2].exists(@c0:0, @c0:0 > 1)])], @index0 + @index0 + @index1 + @index1 == 4) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([size([[1].exists(@c0:0, @c0:0 > 0)]), size([[2].exists(@c0:0, @c0:0 > 1)])], @index0 + @index0 + @index1 + @index1 == 4) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([size([[1].exists(@c0:0, @c0:0 > 0)]), size([[2].exists(@c0:0, @c0:0 > 1)])], @index0 + @index0 + @index1 + @index1 == 4) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([size([[1].exists(@c0:0, @c0:0 > 0)]), size([[2].exists(@c0:0, @c0:0 > 1)])], @index0 + @index0 + @index1 + @index1 == 4) Test case: MULTIPLE_MACROS_2 Source: [[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == 'a')] + [['a'].exists(l, l == 'a')] == [true, true, true, true] @@ -293,14 +293,14 @@ Result: true [CASCADED_BINDS]: cel.bind(@r1, [["a"].exists(@c0:1, @c0:1 == "a")], cel.bind(@r0, [[1].exists(@c0:0, @c0:0 > 0)], @r0 + @r0) + @r1 + @r1) == [true, true, true, true] [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([[[1].exists(@c0:0, @c0:0 > 0)], [["a"].exists(@c0:1, @c0:1 == "a")]], @index0 + @index0 + @index1 + @index1 == [true, true, true, true]) [BLOCK_RECURSION_DEPTH_1]: cel.@block([[1], @c0:0 > 0, @x0:0 || @index1, ["a"], @c0:1 == "a", @x0:1 || @index4, [true, true, true, true]], [@index0.exists(@c0:0, @index1)] + [@index0.exists(@c0:0, @index1)] + [@index3.exists(@c0:1, @index4)] + [@index3.exists(@c0:1, @index4)] == @index6) -[BLOCK_RECURSION_DEPTH_2]: cel.@block([[1], @c0:0 > 0, @x0:0 || @index1, ["a"], @c0:1 == "a", @x0:1 || @index4, [true, true, true, true]], [@index0.exists(@c0:0, @index1)] + [@index0.exists(@c0:0, @index1)] + [@index3.exists(@c0:1, @index4)] + [@index3.exists(@c0:1, @index4)] == @index6) -[BLOCK_RECURSION_DEPTH_3]: cel.@block([[1], @c0:0 > 0, @x0:0 || @index1, @index0.exists(@c0:0, @index1), [@index3], ["a"], @c0:1 == "a", @x0:1 || @index6, @index5.exists(@c0:1, @index6), [@index8], [true, true, true, true], @index4 + @index4 + @index9 + @index9], @index11 == @index10) -[BLOCK_RECURSION_DEPTH_4]: cel.@block([[1], @c0:0 > 0, @x0:0 || @index1, @index0.exists(@c0:0, @index1), [@index3], ["a"], @c0:1 == "a", @x0:1 || @index6, @index5.exists(@c0:1, @index6), [@index8], [true, true, true, true], @index4 + @index4 + @index9 + @index9], @index11 == @index10) -[BLOCK_RECURSION_DEPTH_5]: cel.@block([[1], @c0:0 > 0, @x0:0 || @index1, @index0.exists(@c0:0, @index1), [@index3], ["a"], @c0:1 == "a", @x0:1 || @index6, @index5.exists(@c0:1, @index6), [@index8], [true, true, true, true], @index4 + @index4 + @index9 + @index9], @index11 == @index10) -[BLOCK_RECURSION_DEPTH_6]: cel.@block([[1], @c0:0 > 0, @x0:0 || @index1, @index0.exists(@c0:0, @index1), [@index3], ["a"], @c0:1 == "a", @x0:1 || @index6, @index5.exists(@c0:1, @index6), [@index8], [true, true, true, true], @index4 + @index4 + @index9 + @index9], @index11 == @index10) -[BLOCK_RECURSION_DEPTH_7]: cel.@block([[1], @c0:0 > 0, @x0:0 || @index1, @index0.exists(@c0:0, @index1), [@index3], ["a"], @c0:1 == "a", @x0:1 || @index6, @index5.exists(@c0:1, @index6), [@index8], [true, true, true, true], @index4 + @index4 + @index9 + @index9], @index11 == @index10) -[BLOCK_RECURSION_DEPTH_8]: cel.@block([[1], @c0:0 > 0, @x0:0 || @index1, @index0.exists(@c0:0, @index1), [@index3], ["a"], @c0:1 == "a", @x0:1 || @index6, @index5.exists(@c0:1, @index6), [@index8], [true, true, true, true], @index4 + @index4 + @index9 + @index9], @index11 == @index10) -[BLOCK_RECURSION_DEPTH_9]: cel.@block([[1], @c0:0 > 0, @x0:0 || @index1, @index0.exists(@c0:0, @index1), [@index3], ["a"], @c0:1 == "a", @x0:1 || @index6, @index5.exists(@c0:1, @index6), [@index8], [true, true, true, true], @index4 + @index4 + @index9 + @index9], @index11 == @index10) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([@x0:0 || @c0:0 > 0, @x0:1 || @c0:1 == "a", [1], ["a"], [true, true, true, true]], [@index2.exists(@c0:0, @c0:0 > 0)] + [@index2.exists(@c0:0, @c0:0 > 0)] + [@index3.exists(@c0:1, @c0:1 == "a")] + [@index3.exists(@c0:1, @c0:1 == "a")] == @index4) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([[1].exists(@c0:0, @c0:0 > 0), ["a"].exists(@c0:1, @c0:1 == "a"), [@index0], [@index1], @index2 + @index2 + @index3 + @index3], @index4 == [true, true, true, true]) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([[[1].exists(@c0:0, @c0:0 > 0)], [["a"].exists(@c0:1, @c0:1 == "a")]], @index0 + @index0 + @index1 + @index1 == [true, true, true, true]) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([[[1].exists(@c0:0, @c0:0 > 0)], [["a"].exists(@c0:1, @c0:1 == "a")]], @index0 + @index0 + @index1 + @index1 == [true, true, true, true]) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([[[1].exists(@c0:0, @c0:0 > 0)], [["a"].exists(@c0:1, @c0:1 == "a")]], @index0 + @index0 + @index1 + @index1 == [true, true, true, true]) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([[[1].exists(@c0:0, @c0:0 > 0)], [["a"].exists(@c0:1, @c0:1 == "a")]], @index0 + @index0 + @index1 + @index1 == [true, true, true, true]) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([[[1].exists(@c0:0, @c0:0 > 0)], [["a"].exists(@c0:1, @c0:1 == "a")]], @index0 + @index0 + @index1 + @index1 == [true, true, true, true]) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([[[1].exists(@c0:0, @c0:0 > 0)], [["a"].exists(@c0:1, @c0:1 == "a")]], @index0 + @index0 + @index1 + @index1 == [true, true, true, true]) Test case: NESTED_MACROS Source: [1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [[2, 3, 4], [2, 3, 4], [2, 3, 4]] @@ -308,15 +308,15 @@ Source: [1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [[2, 3, 4], [2, 3, 4], [2, 3, Result: true [CASCADED_BINDS]: cel.bind(@r0, [1, 2, 3], @r0.map(@c0:0, @r0.map(@c1:0, @c1:0 + 1))) == cel.bind(@r1, [2, 3, 4], [@r1, @r1, @r1]) [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([[1, 2, 3], [2, 3, 4]], @index0.map(@c0:0, @index0.map(@c1:0, @c1:0 + 1)) == [@index1, @index1, @index1]) -[BLOCK_RECURSION_DEPTH_1]: cel.@block([[1, 2, 3], [2, 3, 4], [@index1, @index1, @index1], @c1:0 + 1, [@index3], @x1:0 + @index4], @index0.map(@c0:0, @index0.map(@c1:0, @index3)) == @index2) -[BLOCK_RECURSION_DEPTH_2]: cel.@block([[1, 2, 3], [2, 3, 4], [@index1, @index1, @index1], [@c1:0 + 1], @index0.map(@c1:0, @c1:0 + 1), @x0:0 + [@index4], @index0.map(@c0:0, @index4)], @index6 == @index2) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([[1, 2, 3], [2, 3, 4], @c1:0 + 1, [@index2], @x1:0 + @index3, [@index1, @index1, @index1]], @index0.map(@c0:0, @index0.map(@c1:0, @index2)) == @index5) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([[1, 2, 3], [2, 3, 4], [@c1:0 + 1], @index0.map(@c1:0, @c1:0 + 1), @x0:0 + [@index3], @index0.map(@c0:0, @index3)], @index5 == [@index1, @index1, @index1]) [BLOCK_RECURSION_DEPTH_3]: Unparse Error: java.lang.IllegalArgumentException: unexpected expr kind: NOT_SET -[BLOCK_RECURSION_DEPTH_4]: cel.@block([[1, 2, 3], [2, 3, 4], [@index1, @index1, @index1], @index0.map(@c1:0, @c1:0 + 1), @index0.map(@c0:0, @index3)], @index4 == @index2) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([[1, 2, 3], [2, 3, 4], @index0.map(@c1:0, @c1:0 + 1)], @index0.map(@c0:0, @index2) == [@index1, @index1, @index1]) [BLOCK_RECURSION_DEPTH_5]: Unparse Error: java.lang.IllegalArgumentException: unexpected expr kind: NOT_SET [BLOCK_RECURSION_DEPTH_6]: Unparse Error: java.lang.IllegalArgumentException: unexpected expr kind: NOT_SET -[BLOCK_RECURSION_DEPTH_7]: cel.@block([[1, 2, 3], [2, 3, 4], [@index1, @index1, @index1], @index0.map(@c0:0, @index0.map(@c1:0, @c1:0 + 1))], @index3 == @index2) -[BLOCK_RECURSION_DEPTH_8]: cel.@block([[1, 2, 3], [2, 3, 4], [@index1, @index1, @index1], @index0.map(@c0:0, @index0.map(@c1:0, @c1:0 + 1))], @index3 == @index2) -[BLOCK_RECURSION_DEPTH_9]: cel.@block([[1, 2, 3], [2, 3, 4], [@index1, @index1, @index1], @index0.map(@c0:0, @index0.map(@c1:0, @c1:0 + 1))], @index3 == @index2) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([[1, 2, 3], [2, 3, 4], @index0.map(@c0:0, @index0.map(@c1:0, @c1:0 + 1))], @index2 == [@index1, @index1, @index1]) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([[1, 2, 3], [2, 3, 4]], @index0.map(@c0:0, @index0.map(@c1:0, @c1:0 + 1)) == [@index1, @index1, @index1]) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([[1, 2, 3], [2, 3, 4]], @index0.map(@c0:0, @index0.map(@c1:0, @c1:0 + 1)) == [@index1, @index1, @index1]) Test case: NESTED_MACROS_2 Source: [1, 2].map(y, [1, 2, 3].filter(x, x == y)) == [[1], [2]] @@ -324,15 +324,15 @@ Source: [1, 2].map(y, [1, 2, 3].filter(x, x == y)) == [[1], [2]] Result: true [CASCADED_BINDS]: [1, 2].map(@c0:0, [1, 2, 3].filter(@c1:0, @c1:0 == @c0:0)) == [[1], [2]] [BLOCK_COMMON_SUBEXPR_ONLY]: [1, 2].map(@c0:0, [1, 2, 3].filter(@c1:0, @c1:0 == @c0:0)) == [[1], [2]] -[BLOCK_RECURSION_DEPTH_1]: cel.@block([[2], [1], [@index1, @index0], [@c1:0], @x1:0 + @index3, @c1:0 == @c0:0, @index5 ? @index4 : @x1:0, [1, 2, 3], [1, 2]], @index8.map(@c0:0, @index7.filter(@c1:0, @index5)) == @index2) -[BLOCK_RECURSION_DEPTH_2]: cel.@block([[[1], [2]], @x1:0 + [@c1:0], (@c1:0 == @c0:0) ? @index1 : @x1:0, [1, 2, 3].filter(@c1:0, @c1:0 == @c0:0), @x0:0 + [@index3], [1, 2].map(@c0:0, @index3)], @index5 == @index0) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([[1, 2], [1, 2, 3], @c1:0 == @c0:0, [@c1:0], @x1:0 + @index3, @index2 ? @index4 : @x1:0, [1], [2], [@index6, @index7]], @index0.map(@c0:0, @index1.filter(@c1:0, @index2)) == @index8) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([@x1:0 + [@c1:0], (@c1:0 == @c0:0) ? @index0 : @x1:0, [1, 2, 3].filter(@c1:0, @c1:0 == @c0:0), @x0:0 + [@index2], [1, 2].map(@c0:0, @index2), [[1], [2]]], @index4 == @index5) [BLOCK_RECURSION_DEPTH_3]: Unparse Error: java.lang.IllegalArgumentException: unexpected expr kind: NOT_SET -[BLOCK_RECURSION_DEPTH_4]: cel.@block([[[1], [2]], [1, 2, 3].filter(@c1:0, @c1:0 == @c0:0), [1, 2].map(@c0:0, @index1)], @index2 == @index0) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([[1, 2, 3].filter(@c1:0, @c1:0 == @c0:0)], [1, 2].map(@c0:0, @index0) == [[1], [2]]) [BLOCK_RECURSION_DEPTH_5]: Unparse Error: java.lang.IllegalArgumentException: unexpected expr kind: NOT_SET [BLOCK_RECURSION_DEPTH_6]: Unparse Error: java.lang.IllegalArgumentException: unexpected expr kind: NOT_SET -[BLOCK_RECURSION_DEPTH_7]: cel.@block([[[1], [2]], [1, 2].map(@c0:0, [1, 2, 3].filter(@c1:0, @c1:0 == @c0:0))], @index1 == @index0) -[BLOCK_RECURSION_DEPTH_8]: cel.@block([[[1], [2]], [1, 2].map(@c0:0, [1, 2, 3].filter(@c1:0, @c1:0 == @c0:0))], @index1 == @index0) -[BLOCK_RECURSION_DEPTH_9]: cel.@block([[[1], [2]], [1, 2].map(@c0:0, [1, 2, 3].filter(@c1:0, @c1:0 == @c0:0))], @index1 == @index0) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([[1, 2].map(@c0:0, [1, 2, 3].filter(@c1:0, @c1:0 == @c0:0))], @index0 == [[1], [2]]) +[BLOCK_RECURSION_DEPTH_8]: [1, 2].map(@c0:0, [1, 2, 3].filter(@c1:0, @c1:0 == @c0:0)) == [[1], [2]] +[BLOCK_RECURSION_DEPTH_9]: [1, 2].map(@c0:0, [1, 2, 3].filter(@c1:0, @c1:0 == @c0:0)) == [[1], [2]] Test case: INCLUSION_LIST Source: 1 in [1,2,3] && 2 in [1,2,3] && 3 in [3, [1,2,3]] && 1 in [1,2,3] @@ -340,15 +340,15 @@ Source: 1 in [1,2,3] && 2 in [1,2,3] && 3 in [3, [1,2,3]] && 1 in [1,2,3] Result: true [CASCADED_BINDS]: cel.bind(@r0, [1, 2, 3], cel.bind(@r1, 1 in @r0, @r1 && 2 in @r0 && 3 in [3, @r0] && @r1)) [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([[1, 2, 3], 1 in @index0], @index1 && 2 in @index0 && 3 in [3, @index0] && @index1) -[BLOCK_RECURSION_DEPTH_1]: cel.@block([[1, 2, 3], 1 in @index0, [3, @index0], 3 in @index2, @index3 && @index1, 2 in @index0, @index1 && @index5], @index6 && @index4) -[BLOCK_RECURSION_DEPTH_2]: cel.@block([[1, 2, 3], 1 in @index0, 3 in [3, @index0], @index2 && @index1, @index1 && 2 in @index0], @index4 && @index3) -[BLOCK_RECURSION_DEPTH_3]: cel.@block([[1, 2, 3], 1 in @index0, 3 in [3, @index0] && @index1, @index1 && 2 in @index0], @index3 && @index2) -[BLOCK_RECURSION_DEPTH_4]: cel.@block([[1, 2, 3], 1 in @index0, 3 in [3, @index0] && @index1, @index1 && 2 in @index0], @index3 && @index2) -[BLOCK_RECURSION_DEPTH_5]: cel.@block([[1, 2, 3], 1 in @index0, 3 in [3, @index0] && @index1, @index1 && 2 in @index0], @index3 && @index2) -[BLOCK_RECURSION_DEPTH_6]: cel.@block([[1, 2, 3], 1 in @index0, 3 in [3, @index0] && @index1, @index1 && 2 in @index0], @index3 && @index2) -[BLOCK_RECURSION_DEPTH_7]: cel.@block([[1, 2, 3], 1 in @index0, 3 in [3, @index0] && @index1, @index1 && 2 in @index0], @index3 && @index2) -[BLOCK_RECURSION_DEPTH_8]: cel.@block([[1, 2, 3], 1 in @index0, 3 in [3, @index0] && @index1, @index1 && 2 in @index0], @index3 && @index2) -[BLOCK_RECURSION_DEPTH_9]: cel.@block([[1, 2, 3], 1 in @index0, 3 in [3, @index0] && @index1, @index1 && 2 in @index0], @index3 && @index2) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([[1, 2, 3], 1 in @index0, 2 in @index0, @index1 && @index2, [3, @index0], 3 in @index4, @index5 && @index1], @index3 && @index6) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([1 in [1, 2, 3], [1, 2, 3], @index0 && 2 in @index1, 3 in [3, @index1]], @index2 && @index3 && @index0) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([1 in [1, 2, 3], [1, 2, 3], 3 in [3, @index1] && @index0], @index0 && 2 in @index1 && @index2) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([1 in [1, 2, 3], [1, 2, 3]], @index0 && 2 in @index1 && 3 in [3, @index1] && @index0) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([1 in [1, 2, 3], [1, 2, 3]], @index0 && 2 in @index1 && 3 in [3, @index1] && @index0) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([1 in [1, 2, 3], [1, 2, 3]], @index0 && 2 in @index1 && 3 in [3, @index1] && @index0) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([1 in [1, 2, 3], [1, 2, 3]], @index0 && 2 in @index1 && 3 in [3, @index1] && @index0) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([1 in [1, 2, 3], [1, 2, 3]], @index0 && 2 in @index1 && 3 in [3, @index1] && @index0) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([1 in [1, 2, 3], [1, 2, 3]], @index0 && 2 in @index1 && 3 in [3, @index1] && @index0) Test case: INCLUSION_MAP Source: 2 in {'a': 1, 2: {true: false}, 3: {true: false}} @@ -357,14 +357,14 @@ Result: true [CASCADED_BINDS]: 2 in cel.bind(@r0, {true: false}, {"a": 1, 2: @r0, 3: @r0}) [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([{true: false}], 2 in {"a": 1, 2: @index0, 3: @index0}) [BLOCK_RECURSION_DEPTH_1]: cel.@block([{true: false}, {"a": 1, 2: @index0, 3: @index0}], 2 in @index1) -[BLOCK_RECURSION_DEPTH_2]: cel.@block([{true: false}, {"a": 1, 2: @index0, 3: @index0}], 2 in @index1) -[BLOCK_RECURSION_DEPTH_3]: cel.@block([{true: false}, {"a": 1, 2: @index0, 3: @index0}], 2 in @index1) -[BLOCK_RECURSION_DEPTH_4]: cel.@block([{true: false}, {"a": 1, 2: @index0, 3: @index0}], 2 in @index1) -[BLOCK_RECURSION_DEPTH_5]: cel.@block([{true: false}, {"a": 1, 2: @index0, 3: @index0}], 2 in @index1) -[BLOCK_RECURSION_DEPTH_6]: cel.@block([{true: false}, {"a": 1, 2: @index0, 3: @index0}], 2 in @index1) -[BLOCK_RECURSION_DEPTH_7]: cel.@block([{true: false}, {"a": 1, 2: @index0, 3: @index0}], 2 in @index1) -[BLOCK_RECURSION_DEPTH_8]: cel.@block([{true: false}, {"a": 1, 2: @index0, 3: @index0}], 2 in @index1) -[BLOCK_RECURSION_DEPTH_9]: cel.@block([{true: false}, {"a": 1, 2: @index0, 3: @index0}], 2 in @index1) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([{true: false}], 2 in {"a": 1, 2: @index0, 3: @index0}) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([{true: false}], 2 in {"a": 1, 2: @index0, 3: @index0}) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([{true: false}], 2 in {"a": 1, 2: @index0, 3: @index0}) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([{true: false}], 2 in {"a": 1, 2: @index0, 3: @index0}) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([{true: false}], 2 in {"a": 1, 2: @index0, 3: @index0}) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([{true: false}], 2 in {"a": 1, 2: @index0, 3: @index0}) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([{true: false}], 2 in {"a": 1, 2: @index0, 3: @index0}) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([{true: false}], 2 in {"a": 1, 2: @index0, 3: @index0}) Test case: MACRO_ITER_VAR_NOT_REFERENCED Source: [1,2].map(i, [1, 2].map(i, [3,4])) == [[[3, 4], [3, 4]], [[3, 4], [3, 4]]] @@ -372,15 +372,15 @@ Source: [1,2].map(i, [1, 2].map(i, [3,4])) == [[[3, 4], [3, 4]], [[3, 4], [3, 4] Result: true [CASCADED_BINDS]: cel.bind(@r1, [3, 4], cel.bind(@r0, [1, 2], @r0.map(@c0:0, @r0.map(@c1:0, @r1))) == cel.bind(@r2, [@r1, @r1], [@r2, @r2])) [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([[1, 2], [3, 4], [@index1, @index1]], @index0.map(@c0:0, @index0.map(@c1:0, @index1)) == [@index2, @index2]) -[BLOCK_RECURSION_DEPTH_1]: cel.@block([[1, 2], [3, 4], [@index1, @index1], [@index2, @index2], [@index1], @x1:0 + @index4], @index0.map(@c0:0, @index0.map(@c1:0, @index1)) == @index3) -[BLOCK_RECURSION_DEPTH_2]: cel.@block([[1, 2], [3, 4], [@index1, @index1], [@index2, @index2], @x1:0 + [@index1], @index0.map(@c1:0, @index1), @x0:0 + [@index5], @index0.map(@c0:0, @index5)], @index7 == @index3) -[BLOCK_RECURSION_DEPTH_3]: cel.@block([[1, 2], [3, 4], [@index1, @index1], [@index2, @index2], @index0.map(@c1:0, @index1), @index0.map(@c0:0, @index4)], @index5 == @index3) -[BLOCK_RECURSION_DEPTH_4]: Unparse Error: java.lang.IllegalArgumentException: unexpected expr kind: NOT_SET +[BLOCK_RECURSION_DEPTH_1]: cel.@block([[1, 2], [3, 4], [@index1, @index1], [@index1], @x1:0 + @index3, [@index2, @index2]], @index0.map(@c0:0, @index0.map(@c1:0, @index1)) == @index5) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([[[3, 4], [3, 4]], [1, 2], [[3, 4]], @index1.map(@c1:0, [3, 4]), @x0:0 + [@index3], @index1.map(@c0:0, @index3)], @index5 == [@index0, @index0]) +[BLOCK_RECURSION_DEPTH_3]: Unparse Error: java.lang.IllegalArgumentException: unexpected expr kind: NOT_SET +[BLOCK_RECURSION_DEPTH_4]: cel.@block([[[3, 4], [3, 4]], [1, 2], @index1.map(@c1:0, [3, 4])], @index1.map(@c0:0, @index2) == [@index0, @index0]) [BLOCK_RECURSION_DEPTH_5]: Unparse Error: java.lang.IllegalArgumentException: unexpected expr kind: NOT_SET -[BLOCK_RECURSION_DEPTH_6]: cel.@block([[1, 2], [3, 4], [@index1, @index1], [@index2, @index2], @index0.map(@c0:0, @index0.map(@c1:0, @index1))], @index4 == @index3) -[BLOCK_RECURSION_DEPTH_7]: cel.@block([[1, 2], [3, 4], [@index1, @index1], [@index2, @index2], @index0.map(@c0:0, @index0.map(@c1:0, @index1))], @index4 == @index3) -[BLOCK_RECURSION_DEPTH_8]: cel.@block([[1, 2], [3, 4], [@index1, @index1], [@index2, @index2], @index0.map(@c0:0, @index0.map(@c1:0, @index1))], @index4 == @index3) -[BLOCK_RECURSION_DEPTH_9]: cel.@block([[1, 2], [3, 4], [@index1, @index1], [@index2, @index2], @index0.map(@c0:0, @index0.map(@c1:0, @index1))], @index4 == @index3) +[BLOCK_RECURSION_DEPTH_6]: Unparse Error: java.lang.IllegalArgumentException: unexpected expr kind: NOT_SET +[BLOCK_RECURSION_DEPTH_7]: cel.@block([[[3, 4], [3, 4]], [1, 2], @index1.map(@c0:0, @index1.map(@c1:0, [3, 4]))], @index2 == [@index0, @index0]) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([[[3, 4], [3, 4]], [1, 2]], @index1.map(@c0:0, @index1.map(@c1:0, [3, 4])) == [@index0, @index0]) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([[[3, 4], [3, 4]], [1, 2]], @index1.map(@c0:0, @index1.map(@c1:0, [3, 4])) == [@index0, @index0]) Test case: MACRO_SHADOWED_VARIABLE Source: [x - 1 > 3 ? x - 1 : 5].exists(x, x - 1 > 3) || x - 1 > 3 @@ -388,15 +388,15 @@ Source: [x - 1 > 3 ? x - 1 : 5].exists(x, x - 1 > 3) || x - 1 > 3 Result: true [CASCADED_BINDS]: cel.bind(@r0, x - 1, cel.bind(@r1, @r0 > 3, [@r1 ? @r0 : 5].exists(@c0:0, @c0:0 - 1 > 3) || @r1)) [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([x - 1, @index0 > 3], [@index1 ? @index0 : 5].exists(@c0:0, @c0:0 - 1 > 3) || @index1) -[BLOCK_RECURSION_DEPTH_1]: cel.@block([x - 1, @index0 > 3, @c0:0 - 1, @index2 > 3, @x0:0 || @index3, @index1 ? @index0 : 5, [@index5]], @index6.exists(@c0:0, @index3) || @index1) -[BLOCK_RECURSION_DEPTH_2]: cel.@block([x - 1, @index0 > 3, @c0:0 - 1 > 3, @x0:0 || @index2, [@index1 ? @index0 : 5]], @index4.exists(@c0:0, @index2) || @index1) -[BLOCK_RECURSION_DEPTH_3]: cel.@block([x - 1, @index0 > 3, @x0:0 || @c0:0 - 1 > 3, [@index1 ? @index0 : 5].exists(@c0:0, @c0:0 - 1 > 3)], @index3 || @index1) -[BLOCK_RECURSION_DEPTH_4]: cel.@block([x - 1, @index0 > 3, [@index1 ? @index0 : 5].exists(@c0:0, @c0:0 - 1 > 3)], @index2 || @index1) -[BLOCK_RECURSION_DEPTH_5]: cel.@block([x - 1, @index0 > 3, [@index1 ? @index0 : 5].exists(@c0:0, @c0:0 - 1 > 3)], @index2 || @index1) -[BLOCK_RECURSION_DEPTH_6]: cel.@block([x - 1, @index0 > 3, [@index1 ? @index0 : 5].exists(@c0:0, @c0:0 - 1 > 3)], @index2 || @index1) -[BLOCK_RECURSION_DEPTH_7]: cel.@block([x - 1, @index0 > 3, [@index1 ? @index0 : 5].exists(@c0:0, @c0:0 - 1 > 3)], @index2 || @index1) -[BLOCK_RECURSION_DEPTH_8]: cel.@block([x - 1, @index0 > 3, [@index1 ? @index0 : 5].exists(@c0:0, @c0:0 - 1 > 3)], @index2 || @index1) -[BLOCK_RECURSION_DEPTH_9]: cel.@block([x - 1, @index0 > 3, [@index1 ? @index0 : 5].exists(@c0:0, @c0:0 - 1 > 3)], @index2 || @index1) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([x - 1, @index0 > 3, @index1 ? @index0 : 5, [@index2], @c0:0 - 1, @index4 > 3, @x0:0 || @index5], @index3.exists(@c0:0, @index5) || @index1) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([x - 1 > 3, @index0 ? (x - 1) : 5, @c0:0 - 1 > 3, [@index1], @x0:0 || @index2], @index3.exists(@c0:0, @index2) || @index0) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([x - 1 > 3, [@index0 ? (x - 1) : 5], @x0:0 || @c0:0 - 1 > 3, @index1.exists(@c0:0, @c0:0 - 1 > 3)], @index3 || @index0) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([x - 1 > 3, [@index0 ? (x - 1) : 5].exists(@c0:0, @c0:0 - 1 > 3)], @index1 || @index0) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([x - 1 > 3], [@index0 ? (x - 1) : 5].exists(@c0:0, @c0:0 - 1 > 3) || @index0) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([x - 1 > 3], [@index0 ? (x - 1) : 5].exists(@c0:0, @c0:0 - 1 > 3) || @index0) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([x - 1 > 3], [@index0 ? (x - 1) : 5].exists(@c0:0, @c0:0 - 1 > 3) || @index0) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([x - 1 > 3], [@index0 ? (x - 1) : 5].exists(@c0:0, @c0:0 - 1 > 3) || @index0) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([x - 1 > 3], [@index0 ? (x - 1) : 5].exists(@c0:0, @c0:0 - 1 > 3) || @index0) Test case: MACRO_SHADOWED_VARIABLE_2 Source: ["foo", "bar"].map(x, [x + x, x + x]).map(x, [x + x, x + x]) @@ -404,15 +404,15 @@ Source: ["foo", "bar"].map(x, [x + x, x + x]).map(x, [x + x, x + x]) Result: [[[foofoo, foofoo, foofoo, foofoo], [foofoo, foofoo, foofoo, foofoo]], [[barbar, barbar, barbar, barbar], [barbar, barbar, barbar, barbar]]] [CASCADED_BINDS]: ["foo", "bar"].map(@c1:0, cel.bind(@r0, @c1:0 + @c1:0, [@r0, @r0])).map(@c0:0, cel.bind(@r1, @c0:0 + @c0:0, [@r1, @r1])) [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([@c1:0 + @c1:0, @c0:0 + @c0:0], ["foo", "bar"].map(@c1:0, [@index0, @index0]).map(@c0:0, [@index1, @index1])) -[BLOCK_RECURSION_DEPTH_1]: cel.@block([@c1:0 + @c1:0, @c0:0 + @c0:0, [@index1, @index1], [@index2], @x0:0 + @index3, [@index0, @index0], [@index5], @x1:0 + @index6, ["foo", "bar"]], @index8.map(@c1:0, @index5).map(@c0:0, @index2)) -[BLOCK_RECURSION_DEPTH_2]: cel.@block([@c1:0 + @c1:0, @c0:0 + @c0:0, [[@index1, @index1]], @x0:0 + @index2, [[@index0, @index0]], ["foo", "bar"].map(@c1:0, [@index0, @index0])], @index5.map(@c0:0, [@index1, @index1])) -[BLOCK_RECURSION_DEPTH_3]: cel.@block([@c1:0 + @c1:0, @c0:0 + @c0:0, @x0:0 + [[@index1, @index1]], @x1:0 + [[@index0, @index0]], ["foo", "bar"].map(@c1:0, [@index0, @index0])], @index4.map(@c0:0, [@index1, @index1])) -[BLOCK_RECURSION_DEPTH_4]: cel.@block([@c1:0 + @c1:0, @c0:0 + @c0:0, @x0:0 + [[@index1, @index1]], ["foo", "bar"].map(@c1:0, [@index0, @index0])], @index3.map(@c0:0, [@index1, @index1])) -[BLOCK_RECURSION_DEPTH_5]: cel.@block([@c1:0 + @c1:0, @c0:0 + @c0:0, @x0:0 + [[@index1, @index1]], ["foo", "bar"].map(@c1:0, [@index0, @index0])], @index3.map(@c0:0, [@index1, @index1])) -[BLOCK_RECURSION_DEPTH_6]: cel.@block([@c1:0 + @c1:0, @c0:0 + @c0:0, @x0:0 + [[@index1, @index1]], ["foo", "bar"].map(@c1:0, [@index0, @index0])], @index3.map(@c0:0, [@index1, @index1])) -[BLOCK_RECURSION_DEPTH_7]: cel.@block([@c1:0 + @c1:0, @c0:0 + @c0:0, @x0:0 + [[@index1, @index1]], ["foo", "bar"].map(@c1:0, [@index0, @index0])], @index3.map(@c0:0, [@index1, @index1])) -[BLOCK_RECURSION_DEPTH_8]: cel.@block([@c1:0 + @c1:0, @c0:0 + @c0:0, @x0:0 + [[@index1, @index1]], ["foo", "bar"].map(@c1:0, [@index0, @index0])], @index3.map(@c0:0, [@index1, @index1])) -[BLOCK_RECURSION_DEPTH_9]: cel.@block([@c1:0 + @c1:0, @c0:0 + @c0:0, @x0:0 + [[@index1, @index1]], ["foo", "bar"].map(@c1:0, [@index0, @index0])], @index3.map(@c0:0, [@index1, @index1])) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([@c1:0 + @c1:0, @c0:0 + @c0:0, ["foo", "bar"], [@index0, @index0], [@index3], @x1:0 + @index4, [@index1, @index1], [@index6], @x0:0 + @index7], @index2.map(@c1:0, @index3).map(@c0:0, @index6)) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([@c1:0 + @c1:0, @c0:0 + @c0:0, [[@index0, @index0]], ["foo", "bar"].map(@c1:0, [@index0, @index0]), [[@index1, @index1]]], @index3.map(@c0:0, [@index1, @index1])) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([@c1:0 + @c1:0, @c0:0 + @c0:0, @x1:0 + [[@index0, @index0]], @x0:0 + [[@index1, @index1]]], ["foo", "bar"].map(@c1:0, [@index0, @index0]).map(@c0:0, [@index1, @index1])) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([@c1:0 + @c1:0, @c0:0 + @c0:0, ["foo", "bar"].map(@c1:0, [@index0, @index0])], @index2.map(@c0:0, [@index1, @index1])) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([@c1:0 + @c1:0, @c0:0 + @c0:0], ["foo", "bar"].map(@c1:0, [@index0, @index0]).map(@c0:0, [@index1, @index1])) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([@c1:0 + @c1:0, @c0:0 + @c0:0], ["foo", "bar"].map(@c1:0, [@index0, @index0]).map(@c0:0, [@index1, @index1])) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([@c1:0 + @c1:0, @c0:0 + @c0:0], ["foo", "bar"].map(@c1:0, [@index0, @index0]).map(@c0:0, [@index1, @index1])) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([@c1:0 + @c1:0, @c0:0 + @c0:0], ["foo", "bar"].map(@c1:0, [@index0, @index0]).map(@c0:0, [@index1, @index1])) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([@c1:0 + @c1:0, @c0:0 + @c0:0], ["foo", "bar"].map(@c1:0, [@index0, @index0]).map(@c0:0, [@index1, @index1])) Test case: PRESENCE_TEST Source: has({'a': true}.a) && {'a':true}['a'] @@ -421,14 +421,14 @@ Result: true [CASCADED_BINDS]: cel.bind(@r0, {"a": true}, has(@r0.a) && @r0["a"]) [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([{"a": true}], has(@index0.a) && @index0["a"]) [BLOCK_RECURSION_DEPTH_1]: cel.@block([{"a": true}, @index0["a"]], has(@index0.a) && @index1) -[BLOCK_RECURSION_DEPTH_2]: cel.@block([{"a": true}, @index0["a"]], has(@index0.a) && @index1) -[BLOCK_RECURSION_DEPTH_3]: cel.@block([{"a": true}, @index0["a"]], has(@index0.a) && @index1) -[BLOCK_RECURSION_DEPTH_4]: cel.@block([{"a": true}, @index0["a"]], has(@index0.a) && @index1) -[BLOCK_RECURSION_DEPTH_5]: cel.@block([{"a": true}, @index0["a"]], has(@index0.a) && @index1) -[BLOCK_RECURSION_DEPTH_6]: cel.@block([{"a": true}, @index0["a"]], has(@index0.a) && @index1) -[BLOCK_RECURSION_DEPTH_7]: cel.@block([{"a": true}, @index0["a"]], has(@index0.a) && @index1) -[BLOCK_RECURSION_DEPTH_8]: cel.@block([{"a": true}, @index0["a"]], has(@index0.a) && @index1) -[BLOCK_RECURSION_DEPTH_9]: cel.@block([{"a": true}, @index0["a"]], has(@index0.a) && @index1) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([{"a": true}], has(@index0.a) && @index0["a"]) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([{"a": true}], has(@index0.a) && @index0["a"]) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([{"a": true}], has(@index0.a) && @index0["a"]) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([{"a": true}], has(@index0.a) && @index0["a"]) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([{"a": true}], has(@index0.a) && @index0["a"]) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([{"a": true}], has(@index0.a) && @index0["a"]) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([{"a": true}], has(@index0.a) && @index0["a"]) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([{"a": true}], has(@index0.a) && @index0["a"]) Test case: PRESENCE_TEST_WITH_TERNARY Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : 0) == 10 @@ -439,12 +439,12 @@ Result: true [BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64], (has(@index0.payload) ? @index2 : 0) == 10) [BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type, @index0.payload.single_int64, has(@index0.payload) ? @index1 : 0], @index2 == 10) [BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type, has(@index0.payload) ? @index0.payload.single_int64 : 0], @index1 == 10) -[BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.oneof_type, has(@index0.payload) ? @index0.payload.single_int64 : 0], @index1 == 10) -[BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.oneof_type, has(@index0.payload) ? @index0.payload.single_int64 : 0], @index1 == 10) -[BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.oneof_type, has(@index0.payload) ? @index0.payload.single_int64 : 0], @index1 == 10) -[BLOCK_RECURSION_DEPTH_7]: cel.@block([msg.oneof_type, has(@index0.payload) ? @index0.payload.single_int64 : 0], @index1 == 10) -[BLOCK_RECURSION_DEPTH_8]: cel.@block([msg.oneof_type, has(@index0.payload) ? @index0.payload.single_int64 : 0], @index1 == 10) -[BLOCK_RECURSION_DEPTH_9]: cel.@block([msg.oneof_type, has(@index0.payload) ? @index0.payload.single_int64 : 0], @index1 == 10) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.oneof_type], (has(@index0.payload) ? @index0.payload.single_int64 : 0) == 10) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.oneof_type], (has(@index0.payload) ? @index0.payload.single_int64 : 0) == 10) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.oneof_type], (has(@index0.payload) ? @index0.payload.single_int64 : 0) == 10) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([msg.oneof_type], (has(@index0.payload) ? @index0.payload.single_int64 : 0) == 10) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([msg.oneof_type], (has(@index0.payload) ? @index0.payload.single_int64 : 0) == 10) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([msg.oneof_type], (has(@index0.payload) ? @index0.payload.single_int64 : 0) == 10) Test case: PRESENCE_TEST_WITH_TERNARY_2 Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : msg.oneof_type.payload.single_int64 * 0) == 10 @@ -453,14 +453,14 @@ Result: true [CASCADED_BINDS]: cel.bind(@r0, msg.oneof_type, cel.bind(@r1, @r0.payload.single_int64, has(@r0.payload) ? @r1 : (@r1 * 0))) == 10 [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.oneof_type, @index0.payload.single_int64], (has(@index0.payload) ? @index1 : (@index1 * 0)) == 10) [BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, @index2 * 0], (has(@index0.payload) ? @index2 : @index3) == 10) -[BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, has(@index0.payload) ? @index2 : (@index2 * 0)], @index3 == 10) -[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, has(@index0.payload) ? @index2 : (@index2 * 0)], @index3 == 10) -[BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, has(@index0.payload) ? @index2 : (@index2 * 0)], @index3 == 10) -[BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, has(@index0.payload) ? @index2 : (@index2 * 0)], @index3 == 10) -[BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, has(@index0.payload) ? @index2 : (@index2 * 0)], @index3 == 10) -[BLOCK_RECURSION_DEPTH_7]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, has(@index0.payload) ? @index2 : (@index2 * 0)], @index3 == 10) -[BLOCK_RECURSION_DEPTH_8]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, has(@index0.payload) ? @index2 : (@index2 * 0)], @index3 == 10) -[BLOCK_RECURSION_DEPTH_9]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, has(@index0.payload) ? @index2 : (@index2 * 0)], @index3 == 10) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type.payload, @index0.single_int64, msg.oneof_type, has(@index2.payload) ? @index1 : (@index1 * 0)], @index3 == 10) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type.payload.single_int64, has(msg.oneof_type.payload) ? @index0 : (@index0 * 0)], @index1 == 10) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.oneof_type.payload.single_int64], (has(msg.oneof_type.payload) ? @index0 : (@index0 * 0)) == 10) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.oneof_type.payload.single_int64], (has(msg.oneof_type.payload) ? @index0 : (@index0 * 0)) == 10) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.oneof_type.payload.single_int64], (has(msg.oneof_type.payload) ? @index0 : (@index0 * 0)) == 10) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([msg.oneof_type.payload.single_int64], (has(msg.oneof_type.payload) ? @index0 : (@index0 * 0)) == 10) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([msg.oneof_type.payload.single_int64], (has(msg.oneof_type.payload) ? @index0 : (@index0 * 0)) == 10) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([msg.oneof_type.payload.single_int64], (has(msg.oneof_type.payload) ? @index0 : (@index0 * 0)) == 10) Test case: PRESENCE_TEST_WITH_TERNARY_3 Source: (has(msg.oneof_type.payload.single_int64) ? msg.oneof_type.payload.single_int64 : msg.oneof_type.payload.single_int64 * 0) == 10 @@ -469,14 +469,14 @@ Result: true [CASCADED_BINDS]: cel.bind(@r0, msg.oneof_type.payload, cel.bind(@r1, @r0.single_int64, has(@r0.single_int64) ? @r1 : (@r1 * 0))) == 10 [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.oneof_type.payload, @index0.single_int64], (has(@index0.single_int64) ? @index1 : (@index1 * 0)) == 10) [BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, @index2 * 0], (has(@index1.single_int64) ? @index2 : @index3) == 10) -[BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, has(@index1.single_int64) ? @index2 : (@index2 * 0)], @index3 == 10) -[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, has(@index1.single_int64) ? @index2 : (@index2 * 0)], @index3 == 10) -[BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, has(@index1.single_int64) ? @index2 : (@index2 * 0)], @index3 == 10) -[BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, has(@index1.single_int64) ? @index2 : (@index2 * 0)], @index3 == 10) -[BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, has(@index1.single_int64) ? @index2 : (@index2 * 0)], @index3 == 10) -[BLOCK_RECURSION_DEPTH_7]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, has(@index1.single_int64) ? @index2 : (@index2 * 0)], @index3 == 10) -[BLOCK_RECURSION_DEPTH_8]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, has(@index1.single_int64) ? @index2 : (@index2 * 0)], @index3 == 10) -[BLOCK_RECURSION_DEPTH_9]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, has(@index1.single_int64) ? @index2 : (@index2 * 0)], @index3 == 10) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type.payload, @index0.single_int64, has(@index0.single_int64) ? @index1 : (@index1 * 0)], @index2 == 10) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type.payload.single_int64, msg.oneof_type.payload], (has(@index1.single_int64) ? @index0 : (@index0 * 0)) == 10) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.oneof_type.payload.single_int64, has(msg.oneof_type.payload.single_int64) ? @index0 : (@index0 * 0)], @index1 == 10) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.oneof_type.payload.single_int64], (has(msg.oneof_type.payload.single_int64) ? @index0 : (@index0 * 0)) == 10) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.oneof_type.payload.single_int64], (has(msg.oneof_type.payload.single_int64) ? @index0 : (@index0 * 0)) == 10) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([msg.oneof_type.payload.single_int64], (has(msg.oneof_type.payload.single_int64) ? @index0 : (@index0 * 0)) == 10) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([msg.oneof_type.payload.single_int64], (has(msg.oneof_type.payload.single_int64) ? @index0 : (@index0 * 0)) == 10) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([msg.oneof_type.payload.single_int64], (has(msg.oneof_type.payload.single_int64) ? @index0 : (@index0 * 0)) == 10) Test case: PRESENCE_TEST_WITH_TERNARY_NESTED Source: (has(msg.oneof_type) && has(msg.oneof_type.payload) && has(msg.oneof_type.payload.single_int64)) ? ((has(msg.oneof_type.payload.map_string_string) && has(msg.oneof_type.payload.map_string_string.key)) ? msg.oneof_type.payload.map_string_string.key == 'A' : false) : false @@ -485,14 +485,14 @@ Result: true [CASCADED_BINDS]: cel.bind(@r0, msg.oneof_type, cel.bind(@r1, @r0.payload, (has(msg.oneof_type) && has(@r0.payload) && has(@r1.single_int64)) ? cel.bind(@r2, @r1.map_string_string, (has(@r1.map_string_string) && has(@r2.key)) ? (@r2.key == "A") : false) : false)) [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_string_string], (has(msg.oneof_type) && has(@index0.payload) && has(@index1.single_int64)) ? ((has(@index1.map_string_string) && has(@index2.key)) ? (@index2.key == "A") : false) : false) [BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_string_string, @index2.key, @index3 == "A"], (has(msg.oneof_type) && has(@index0.payload) && has(@index1.single_int64)) ? ((has(@index1.map_string_string) && has(@index2.key)) ? @index4 : false) : false) -[BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_string_string, @index2.key == "A", has(@index1.map_string_string) && has(@index2.key), @index4 ? @index3 : false, has(msg.oneof_type) && has(@index0.payload), @index6 && has(@index1.single_int64)], @index7 ? @index5 : false) -[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_string_string, (has(@index1.map_string_string) && has(@index2.key)) ? (@index2.key == "A") : false, has(msg.oneof_type) && has(@index0.payload) && has(@index1.single_int64)], @index4 ? @index3 : false) -[BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_string_string, (has(@index1.map_string_string) && has(@index2.key)) ? (@index2.key == "A") : false, has(msg.oneof_type) && has(@index0.payload) && has(@index1.single_int64)], @index4 ? @index3 : false) -[BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_string_string, (has(@index1.map_string_string) && has(@index2.key)) ? (@index2.key == "A") : false, has(msg.oneof_type) && has(@index0.payload) && has(@index1.single_int64)], @index4 ? @index3 : false) -[BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_string_string, (has(@index1.map_string_string) && has(@index2.key)) ? (@index2.key == "A") : false, has(msg.oneof_type) && has(@index0.payload) && has(@index1.single_int64)], @index4 ? @index3 : false) -[BLOCK_RECURSION_DEPTH_7]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_string_string, (has(@index1.map_string_string) && has(@index2.key)) ? (@index2.key == "A") : false, has(msg.oneof_type) && has(@index0.payload) && has(@index1.single_int64)], @index4 ? @index3 : false) -[BLOCK_RECURSION_DEPTH_8]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_string_string, (has(@index1.map_string_string) && has(@index2.key)) ? (@index2.key == "A") : false, has(msg.oneof_type) && has(@index0.payload) && has(@index1.single_int64)], @index4 ? @index3 : false) -[BLOCK_RECURSION_DEPTH_9]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_string_string, (has(@index1.map_string_string) && has(@index2.key)) ? (@index2.key == "A") : false, has(msg.oneof_type) && has(@index0.payload) && has(@index1.single_int64)], @index4 ? @index3 : false) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type.payload, @index0.map_string_string, has(@index0.map_string_string) && has(@index1.key), @index1.key == "A", msg.oneof_type, has(msg.oneof_type) && has(@index4.payload), @index5 && has(@index0.single_int64)], @index6 ? (@index2 ? @index3 : false) : false) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type.payload.map_string_string, msg.oneof_type.payload, has(msg.oneof_type) && has(msg.oneof_type.payload), (has(@index1.map_string_string) && has(@index0.key)) ? (@index0.key == "A") : false], (@index2 && has(@index1.single_int64)) ? @index3 : false) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.oneof_type.payload.map_string_string, msg.oneof_type.payload, has(msg.oneof_type) && has(msg.oneof_type.payload) && has(@index1.single_int64)], @index2 ? ((has(@index1.map_string_string) && has(@index0.key)) ? (@index0.key == "A") : false) : false) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.oneof_type.payload.map_string_string, msg.oneof_type.payload], (has(msg.oneof_type) && has(msg.oneof_type.payload) && has(@index1.single_int64)) ? ((has(@index1.map_string_string) && has(@index0.key)) ? (@index0.key == "A") : false) : false) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.oneof_type.payload.map_string_string, msg.oneof_type.payload], (has(msg.oneof_type) && has(msg.oneof_type.payload) && has(@index1.single_int64)) ? ((has(@index1.map_string_string) && has(@index0.key)) ? (@index0.key == "A") : false) : false) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([msg.oneof_type.payload.map_string_string, msg.oneof_type.payload], (has(msg.oneof_type) && has(msg.oneof_type.payload) && has(@index1.single_int64)) ? ((has(@index1.map_string_string) && has(@index0.key)) ? (@index0.key == "A") : false) : false) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([msg.oneof_type.payload.map_string_string, msg.oneof_type.payload], (has(msg.oneof_type) && has(msg.oneof_type.payload) && has(@index1.single_int64)) ? ((has(@index1.map_string_string) && has(@index0.key)) ? (@index0.key == "A") : false) : false) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([msg.oneof_type.payload.map_string_string, msg.oneof_type.payload], (has(msg.oneof_type) && has(msg.oneof_type.payload) && has(@index1.single_int64)) ? ((has(@index1.map_string_string) && has(@index0.key)) ? (@index0.key == "A") : false) : false) Test case: OPTIONAL_LIST Source: [10, ?optional.none(), [?optional.none(), ?opt_x], [?optional.none(), ?opt_x]] == [10, [5], [5]] @@ -500,15 +500,15 @@ Source: [10, ?optional.none(), [?optional.none(), ?opt_x], [?optional.none(), ?o Result: true [CASCADED_BINDS]: cel.bind(@r0, optional.none(), cel.bind(@r1, [?@r0, ?opt_x], [10, ?@r0, @r1, @r1])) == cel.bind(@r2, [5], [10, @r2, @r2]) [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([optional.none(), [?@index0, ?opt_x], [5]], [10, ?@index0, @index1, @index1] == [10, @index2, @index2]) -[BLOCK_RECURSION_DEPTH_1]: cel.@block([optional.none(), [?@index0, ?opt_x], [5], [10, @index2, @index2], [10, ?@index0, @index1, @index1]], @index4 == @index3) -[BLOCK_RECURSION_DEPTH_2]: cel.@block([optional.none(), [?@index0, ?opt_x], [5], [10, @index2, @index2], [10, ?@index0, @index1, @index1]], @index4 == @index3) -[BLOCK_RECURSION_DEPTH_3]: cel.@block([optional.none(), [?@index0, ?opt_x], [5], [10, @index2, @index2], [10, ?@index0, @index1, @index1]], @index4 == @index3) -[BLOCK_RECURSION_DEPTH_4]: cel.@block([optional.none(), [?@index0, ?opt_x], [5], [10, @index2, @index2], [10, ?@index0, @index1, @index1]], @index4 == @index3) -[BLOCK_RECURSION_DEPTH_5]: cel.@block([optional.none(), [?@index0, ?opt_x], [5], [10, @index2, @index2], [10, ?@index0, @index1, @index1]], @index4 == @index3) -[BLOCK_RECURSION_DEPTH_6]: cel.@block([optional.none(), [?@index0, ?opt_x], [5], [10, @index2, @index2], [10, ?@index0, @index1, @index1]], @index4 == @index3) -[BLOCK_RECURSION_DEPTH_7]: cel.@block([optional.none(), [?@index0, ?opt_x], [5], [10, @index2, @index2], [10, ?@index0, @index1, @index1]], @index4 == @index3) -[BLOCK_RECURSION_DEPTH_8]: cel.@block([optional.none(), [?@index0, ?opt_x], [5], [10, @index2, @index2], [10, ?@index0, @index1, @index1]], @index4 == @index3) -[BLOCK_RECURSION_DEPTH_9]: cel.@block([optional.none(), [?@index0, ?opt_x], [5], [10, @index2, @index2], [10, ?@index0, @index1, @index1]], @index4 == @index3) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([optional.none(), [?@index0, ?opt_x], [5], [10, ?@index0, @index1, @index1], [10, @index2, @index2]], @index3 == @index4) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([[?optional.none(), ?opt_x], [5], [10, ?optional.none(), @index0, @index0]], @index2 == [10, @index1, @index1]) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([[?optional.none(), ?opt_x], [5]], [10, ?optional.none(), @index0, @index0] == [10, @index1, @index1]) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([[?optional.none(), ?opt_x], [5]], [10, ?optional.none(), @index0, @index0] == [10, @index1, @index1]) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([[?optional.none(), ?opt_x], [5]], [10, ?optional.none(), @index0, @index0] == [10, @index1, @index1]) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([[?optional.none(), ?opt_x], [5]], [10, ?optional.none(), @index0, @index0] == [10, @index1, @index1]) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([[?optional.none(), ?opt_x], [5]], [10, ?optional.none(), @index0, @index0] == [10, @index1, @index1]) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([[?optional.none(), ?opt_x], [5]], [10, ?optional.none(), @index0, @index0] == [10, @index1, @index1]) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([[?optional.none(), ?opt_x], [5]], [10, ?optional.none(), @index0, @index0] == [10, @index1, @index1]) Test case: OPTIONAL_MAP Source: {?'hello': optional.of('hello')}['hello'] + {?'hello': optional.of('hello')}['hello'] == 'hellohello' @@ -517,14 +517,14 @@ Result: true [CASCADED_BINDS]: cel.bind(@r0, {?"hello": optional.of("hello")}["hello"], @r0 + @r0) == "hellohello" [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([{?"hello": optional.of("hello")}["hello"]], @index0 + @index0 == "hellohello") [BLOCK_RECURSION_DEPTH_1]: cel.@block([optional.of("hello"), {?"hello": @index0}, @index1["hello"], @index2 + @index2], @index3 == "hellohello") -[BLOCK_RECURSION_DEPTH_2]: cel.@block([optional.of("hello"), {?"hello": @index0}, @index1["hello"], @index2 + @index2], @index3 == "hellohello") -[BLOCK_RECURSION_DEPTH_3]: cel.@block([optional.of("hello"), {?"hello": @index0}, @index1["hello"], @index2 + @index2], @index3 == "hellohello") -[BLOCK_RECURSION_DEPTH_4]: cel.@block([optional.of("hello"), {?"hello": @index0}, @index1["hello"], @index2 + @index2], @index3 == "hellohello") -[BLOCK_RECURSION_DEPTH_5]: cel.@block([optional.of("hello"), {?"hello": @index0}, @index1["hello"], @index2 + @index2], @index3 == "hellohello") -[BLOCK_RECURSION_DEPTH_6]: cel.@block([optional.of("hello"), {?"hello": @index0}, @index1["hello"], @index2 + @index2], @index3 == "hellohello") -[BLOCK_RECURSION_DEPTH_7]: cel.@block([optional.of("hello"), {?"hello": @index0}, @index1["hello"], @index2 + @index2], @index3 == "hellohello") -[BLOCK_RECURSION_DEPTH_8]: cel.@block([optional.of("hello"), {?"hello": @index0}, @index1["hello"], @index2 + @index2], @index3 == "hellohello") -[BLOCK_RECURSION_DEPTH_9]: cel.@block([optional.of("hello"), {?"hello": @index0}, @index1["hello"], @index2 + @index2], @index3 == "hellohello") +[BLOCK_RECURSION_DEPTH_2]: cel.@block([{?"hello": optional.of("hello")}, @index0["hello"]], @index1 + @index1 == "hellohello") +[BLOCK_RECURSION_DEPTH_3]: cel.@block([{?"hello": optional.of("hello")}["hello"]], @index0 + @index0 == "hellohello") +[BLOCK_RECURSION_DEPTH_4]: cel.@block([{?"hello": optional.of("hello")}["hello"]], @index0 + @index0 == "hellohello") +[BLOCK_RECURSION_DEPTH_5]: cel.@block([{?"hello": optional.of("hello")}["hello"]], @index0 + @index0 == "hellohello") +[BLOCK_RECURSION_DEPTH_6]: cel.@block([{?"hello": optional.of("hello")}["hello"]], @index0 + @index0 == "hellohello") +[BLOCK_RECURSION_DEPTH_7]: cel.@block([{?"hello": optional.of("hello")}["hello"]], @index0 + @index0 == "hellohello") +[BLOCK_RECURSION_DEPTH_8]: cel.@block([{?"hello": optional.of("hello")}["hello"]], @index0 + @index0 == "hellohello") +[BLOCK_RECURSION_DEPTH_9]: cel.@block([{?"hello": optional.of("hello")}["hello"]], @index0 + @index0 == "hellohello") Test case: OPTIONAL_MAP_CHAINED Source: {?'key': optional.of('test')}[?'bogus'].or({'key': 'test'}[?'bogus']).orValue({'key': 'test'}['key']) == 'test' @@ -532,15 +532,15 @@ Source: {?'key': optional.of('test')}[?'bogus'].or({'key': 'test'}[?'bogus']).or Result: true [CASCADED_BINDS]: cel.bind(@r0, {"key": "test"}, {?"key": optional.of("test")}[?"bogus"].or(@r0[?"bogus"]).orValue(@r0["key"])) == "test" [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([{"key": "test"}], {?"key": optional.of("test")}[?"bogus"].or(@index0[?"bogus"]).orValue(@index0["key"]) == "test") -[BLOCK_RECURSION_DEPTH_1]: cel.@block([{"key": "test"}, @index0["key"], @index0[?"bogus"], optional.of("test"), {?"key": @index3}, @index4[?"bogus"], @index5.or(@index2), @index6.orValue(@index1)], @index7 == "test") -[BLOCK_RECURSION_DEPTH_2]: cel.@block([{"key": "test"}, @index0["key"], @index0[?"bogus"], {?"key": optional.of("test")}, @index3[?"bogus"].or(@index2), @index4.orValue(@index1)], @index5 == "test") -[BLOCK_RECURSION_DEPTH_3]: cel.@block([{"key": "test"}, @index0["key"], @index0[?"bogus"], {?"key": optional.of("test")}[?"bogus"], @index3.or(@index2).orValue(@index1)], @index4 == "test") -[BLOCK_RECURSION_DEPTH_4]: cel.@block([{"key": "test"}, @index0["key"], {?"key": optional.of("test")}[?"bogus"].or(@index0[?"bogus"]), @index2.orValue(@index1)], @index3 == "test") +[BLOCK_RECURSION_DEPTH_1]: cel.@block([{"key": "test"}, optional.of("test"), {?"key": @index1}, @index2[?"bogus"], @index0[?"bogus"], @index3.or(@index4), @index0["key"], @index5.orValue(@index6)], @index7 == "test") +[BLOCK_RECURSION_DEPTH_2]: cel.@block([{"key": "test"}, {?"key": optional.of("test")}, @index1[?"bogus"].or(@index0[?"bogus"]), @index2.orValue(@index0["key"])], @index3 == "test") +[BLOCK_RECURSION_DEPTH_3]: cel.@block([{"key": "test"}, {?"key": optional.of("test")}[?"bogus"], @index1.or(@index0[?"bogus"]).orValue(@index0["key"])], @index2 == "test") +[BLOCK_RECURSION_DEPTH_4]: cel.@block([{"key": "test"}, {?"key": optional.of("test")}[?"bogus"].or(@index0[?"bogus"])], @index1.orValue(@index0["key"]) == "test") [BLOCK_RECURSION_DEPTH_5]: cel.@block([{"key": "test"}, {?"key": optional.of("test")}[?"bogus"].or(@index0[?"bogus"]).orValue(@index0["key"])], @index1 == "test") -[BLOCK_RECURSION_DEPTH_6]: cel.@block([{"key": "test"}, {?"key": optional.of("test")}[?"bogus"].or(@index0[?"bogus"]).orValue(@index0["key"])], @index1 == "test") -[BLOCK_RECURSION_DEPTH_7]: cel.@block([{"key": "test"}, {?"key": optional.of("test")}[?"bogus"].or(@index0[?"bogus"]).orValue(@index0["key"])], @index1 == "test") -[BLOCK_RECURSION_DEPTH_8]: cel.@block([{"key": "test"}, {?"key": optional.of("test")}[?"bogus"].or(@index0[?"bogus"]).orValue(@index0["key"])], @index1 == "test") -[BLOCK_RECURSION_DEPTH_9]: cel.@block([{"key": "test"}, {?"key": optional.of("test")}[?"bogus"].or(@index0[?"bogus"]).orValue(@index0["key"])], @index1 == "test") +[BLOCK_RECURSION_DEPTH_6]: cel.@block([{"key": "test"}], {?"key": optional.of("test")}[?"bogus"].or(@index0[?"bogus"]).orValue(@index0["key"]) == "test") +[BLOCK_RECURSION_DEPTH_7]: cel.@block([{"key": "test"}], {?"key": optional.of("test")}[?"bogus"].or(@index0[?"bogus"]).orValue(@index0["key"]) == "test") +[BLOCK_RECURSION_DEPTH_8]: cel.@block([{"key": "test"}], {?"key": optional.of("test")}[?"bogus"].or(@index0[?"bogus"]).orValue(@index0["key"]) == "test") +[BLOCK_RECURSION_DEPTH_9]: cel.@block([{"key": "test"}], {?"key": optional.of("test")}[?"bogus"].or(@index0[?"bogus"]).orValue(@index0["key"]) == "test") Test case: OPTIONAL_MESSAGE Source: TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}.single_int32 + TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}.single_int64 == 5 @@ -548,15 +548,15 @@ Source: TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: o Result: true [CASCADED_BINDS]: cel.bind(@r0, TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}, @r0.single_int32 + @r0.single_int64) == 5 [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}], @index0.single_int32 + @index0.single_int64 == 5) -[BLOCK_RECURSION_DEPTH_1]: cel.@block([optional.ofNonZeroValue(1), optional.of(4), TestAllTypes{?single_int64: @index0, ?single_int32: @index1}, @index2.single_int64, @index2.single_int32, @index4 + @index3], @index5 == 5) -[BLOCK_RECURSION_DEPTH_2]: cel.@block([optional.ofNonZeroValue(1), optional.of(4), TestAllTypes{?single_int64: @index0, ?single_int32: @index1}, @index2.single_int32 + @index2.single_int64], @index3 == 5) -[BLOCK_RECURSION_DEPTH_3]: cel.@block([optional.ofNonZeroValue(1), optional.of(4), TestAllTypes{?single_int64: @index0, ?single_int32: @index1}, @index2.single_int32 + @index2.single_int64], @index3 == 5) -[BLOCK_RECURSION_DEPTH_4]: cel.@block([optional.ofNonZeroValue(1), optional.of(4), TestAllTypes{?single_int64: @index0, ?single_int32: @index1}, @index2.single_int32 + @index2.single_int64], @index3 == 5) -[BLOCK_RECURSION_DEPTH_5]: cel.@block([optional.ofNonZeroValue(1), optional.of(4), TestAllTypes{?single_int64: @index0, ?single_int32: @index1}, @index2.single_int32 + @index2.single_int64], @index3 == 5) -[BLOCK_RECURSION_DEPTH_6]: cel.@block([optional.ofNonZeroValue(1), optional.of(4), TestAllTypes{?single_int64: @index0, ?single_int32: @index1}, @index2.single_int32 + @index2.single_int64], @index3 == 5) -[BLOCK_RECURSION_DEPTH_7]: cel.@block([optional.ofNonZeroValue(1), optional.of(4), TestAllTypes{?single_int64: @index0, ?single_int32: @index1}, @index2.single_int32 + @index2.single_int64], @index3 == 5) -[BLOCK_RECURSION_DEPTH_8]: cel.@block([optional.ofNonZeroValue(1), optional.of(4), TestAllTypes{?single_int64: @index0, ?single_int32: @index1}, @index2.single_int32 + @index2.single_int64], @index3 == 5) -[BLOCK_RECURSION_DEPTH_9]: cel.@block([optional.ofNonZeroValue(1), optional.of(4), TestAllTypes{?single_int64: @index0, ?single_int32: @index1}, @index2.single_int32 + @index2.single_int64], @index3 == 5) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([optional.ofNonZeroValue(1), optional.of(4), TestAllTypes{?single_int64: @index0, ?single_int32: @index1}, @index2.single_int32, @index2.single_int64, @index3 + @index4], @index5 == 5) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}, @index0.single_int32 + @index0.single_int64], @index1 == 5) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}], @index0.single_int32 + @index0.single_int64 == 5) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}], @index0.single_int32 + @index0.single_int64 == 5) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}], @index0.single_int32 + @index0.single_int64 == 5) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}], @index0.single_int32 + @index0.single_int64 == 5) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}], @index0.single_int32 + @index0.single_int64 == 5) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}], @index0.single_int32 + @index0.single_int64 == 5) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}], @index0.single_int32 + @index0.single_int64 == 5) Test case: CALL Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('h' + 'e' + 'l' + 'l' + 'o') @@ -565,14 +565,14 @@ Result: true [CASCADED_BINDS]: cel.bind(@r0, "h" + "e" + "l" + "l" + "o", (@r0 + " world").matches(@r0)) [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block(["h" + "e" + "l" + "l" + "o"], (@index0 + " world").matches(@index0)) [BLOCK_RECURSION_DEPTH_1]: cel.@block(["h" + "e", @index0 + "l", @index1 + "l", @index2 + "o", @index3 + " world"], @index4.matches(@index3)) -[BLOCK_RECURSION_DEPTH_2]: cel.@block(["h" + "e", @index0 + "l", @index1 + "l", @index2 + "o", @index3 + " world"], @index4.matches(@index3)) -[BLOCK_RECURSION_DEPTH_3]: cel.@block(["h" + "e", @index0 + "l", @index1 + "l", @index2 + "o", @index3 + " world"], @index4.matches(@index3)) -[BLOCK_RECURSION_DEPTH_4]: cel.@block(["h" + "e", @index0 + "l", @index1 + "l", @index2 + "o", @index3 + " world"], @index4.matches(@index3)) -[BLOCK_RECURSION_DEPTH_5]: cel.@block(["h" + "e", @index0 + "l", @index1 + "l", @index2 + "o", @index3 + " world"], @index4.matches(@index3)) -[BLOCK_RECURSION_DEPTH_6]: cel.@block(["h" + "e", @index0 + "l", @index1 + "l", @index2 + "o", @index3 + " world"], @index4.matches(@index3)) -[BLOCK_RECURSION_DEPTH_7]: cel.@block(["h" + "e", @index0 + "l", @index1 + "l", @index2 + "o", @index3 + " world"], @index4.matches(@index3)) -[BLOCK_RECURSION_DEPTH_8]: cel.@block(["h" + "e", @index0 + "l", @index1 + "l", @index2 + "o", @index3 + " world"], @index4.matches(@index3)) -[BLOCK_RECURSION_DEPTH_9]: cel.@block(["h" + "e", @index0 + "l", @index1 + "l", @index2 + "o", @index3 + " world"], @index4.matches(@index3)) +[BLOCK_RECURSION_DEPTH_2]: cel.@block(["h" + "e" + "l", @index0 + "l" + "o"], (@index1 + " world").matches(@index1)) +[BLOCK_RECURSION_DEPTH_3]: cel.@block(["h" + "e" + "l" + "l", @index0 + "o"], (@index1 + " world").matches(@index1)) +[BLOCK_RECURSION_DEPTH_4]: cel.@block(["h" + "e" + "l" + "l" + "o"], (@index0 + " world").matches(@index0)) +[BLOCK_RECURSION_DEPTH_5]: cel.@block(["h" + "e" + "l" + "l" + "o"], (@index0 + " world").matches(@index0)) +[BLOCK_RECURSION_DEPTH_6]: cel.@block(["h" + "e" + "l" + "l" + "o"], (@index0 + " world").matches(@index0)) +[BLOCK_RECURSION_DEPTH_7]: cel.@block(["h" + "e" + "l" + "l" + "o"], (@index0 + " world").matches(@index0)) +[BLOCK_RECURSION_DEPTH_8]: cel.@block(["h" + "e" + "l" + "l" + "o"], (@index0 + " world").matches(@index0)) +[BLOCK_RECURSION_DEPTH_9]: cel.@block(["h" + "e" + "l" + "l" + "o"], (@index0 + " world").matches(@index0)) Test case: CALL_ARGUMENT_NESTED_NO_COMMON_SUBEXPR Source: 'hello world'.matches('h' + 'e' + 'l' + 'l' + 'o') @@ -582,13 +582,13 @@ Result: true [BLOCK_COMMON_SUBEXPR_ONLY]: "hello world".matches("h" + "e" + "l" + "l" + "o") [BLOCK_RECURSION_DEPTH_1]: cel.@block(["h" + "e", @index0 + "l", @index1 + "l", @index2 + "o"], "hello world".matches(@index3)) [BLOCK_RECURSION_DEPTH_2]: cel.@block(["h" + "e" + "l", @index0 + "l" + "o"], "hello world".matches(@index1)) -[BLOCK_RECURSION_DEPTH_3]: cel.@block(["h" + "e" + "l" + "l", @index0 + "o"], "hello world".matches(@index1)) +[BLOCK_RECURSION_DEPTH_3]: cel.@block(["h" + "e" + "l" + "l"], "hello world".matches(@index0 + "o")) [BLOCK_RECURSION_DEPTH_4]: cel.@block(["h" + "e" + "l" + "l" + "o"], "hello world".matches(@index0)) -[BLOCK_RECURSION_DEPTH_5]: cel.@block(["h" + "e" + "l" + "l" + "o"], "hello world".matches(@index0)) -[BLOCK_RECURSION_DEPTH_6]: cel.@block(["h" + "e" + "l" + "l" + "o"], "hello world".matches(@index0)) -[BLOCK_RECURSION_DEPTH_7]: cel.@block(["h" + "e" + "l" + "l" + "o"], "hello world".matches(@index0)) -[BLOCK_RECURSION_DEPTH_8]: cel.@block(["h" + "e" + "l" + "l" + "o"], "hello world".matches(@index0)) -[BLOCK_RECURSION_DEPTH_9]: cel.@block(["h" + "e" + "l" + "l" + "o"], "hello world".matches(@index0)) +[BLOCK_RECURSION_DEPTH_5]: "hello world".matches("h" + "e" + "l" + "l" + "o") +[BLOCK_RECURSION_DEPTH_6]: "hello world".matches("h" + "e" + "l" + "l" + "o") +[BLOCK_RECURSION_DEPTH_7]: "hello world".matches("h" + "e" + "l" + "l" + "o") +[BLOCK_RECURSION_DEPTH_8]: "hello world".matches("h" + "e" + "l" + "l" + "o") +[BLOCK_RECURSION_DEPTH_9]: "hello world".matches("h" + "e" + "l" + "l" + "o") Test case: CALL_TARGET_NESTED_NO_COMMON_SUBEXPR Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('hello') @@ -597,14 +597,14 @@ Result: true [CASCADED_BINDS]: ("h" + "e" + "l" + "l" + "o" + " world").matches("hello") [BLOCK_COMMON_SUBEXPR_ONLY]: ("h" + "e" + "l" + "l" + "o" + " world").matches("hello") [BLOCK_RECURSION_DEPTH_1]: cel.@block(["h" + "e", @index0 + "l", @index1 + "l", @index2 + "o", @index3 + " world"], @index4.matches("hello")) -[BLOCK_RECURSION_DEPTH_2]: cel.@block(["h" + "e" + "l", @index0 + "l" + "o", @index1 + " world"], @index2.matches("hello")) -[BLOCK_RECURSION_DEPTH_3]: cel.@block(["h" + "e" + "l" + "l", @index0 + "o" + " world"], @index1.matches("hello")) -[BLOCK_RECURSION_DEPTH_4]: cel.@block(["h" + "e" + "l" + "l" + "o", @index0 + " world"], @index1.matches("hello")) +[BLOCK_RECURSION_DEPTH_2]: cel.@block(["h" + "e" + "l", @index0 + "l" + "o"], (@index1 + " world").matches("hello")) +[BLOCK_RECURSION_DEPTH_3]: cel.@block(["h" + "e" + "l" + "l"], (@index0 + "o" + " world").matches("hello")) +[BLOCK_RECURSION_DEPTH_4]: cel.@block(["h" + "e" + "l" + "l" + "o"], (@index0 + " world").matches("hello")) [BLOCK_RECURSION_DEPTH_5]: cel.@block(["h" + "e" + "l" + "l" + "o" + " world"], @index0.matches("hello")) -[BLOCK_RECURSION_DEPTH_6]: cel.@block(["h" + "e" + "l" + "l" + "o" + " world"], @index0.matches("hello")) -[BLOCK_RECURSION_DEPTH_7]: cel.@block(["h" + "e" + "l" + "l" + "o" + " world"], @index0.matches("hello")) -[BLOCK_RECURSION_DEPTH_8]: cel.@block(["h" + "e" + "l" + "l" + "o" + " world"], @index0.matches("hello")) -[BLOCK_RECURSION_DEPTH_9]: cel.@block(["h" + "e" + "l" + "l" + "o" + " world"], @index0.matches("hello")) +[BLOCK_RECURSION_DEPTH_6]: ("h" + "e" + "l" + "l" + "o" + " world").matches("hello") +[BLOCK_RECURSION_DEPTH_7]: ("h" + "e" + "l" + "l" + "o" + " world").matches("hello") +[BLOCK_RECURSION_DEPTH_8]: ("h" + "e" + "l" + "l" + "o" + " world").matches("hello") +[BLOCK_RECURSION_DEPTH_9]: ("h" + "e" + "l" + "l" + "o" + " world").matches("hello") Test case: CALL_BOTH_ARGUMENT_TARGET_NESTED_NO_COMMON_SUBEXPR Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('w' + 'o' + 'r' + 'l' + 'd') @@ -612,15 +612,15 @@ Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('w' + 'o' + 'r' + 'l' + Result: true [CASCADED_BINDS]: ("h" + "e" + "l" + "l" + "o" + " world").matches("w" + "o" + "r" + "l" + "d") [BLOCK_COMMON_SUBEXPR_ONLY]: ("h" + "e" + "l" + "l" + "o" + " world").matches("w" + "o" + "r" + "l" + "d") -[BLOCK_RECURSION_DEPTH_1]: cel.@block(["w" + "o", @index0 + "r", @index1 + "l", @index2 + "d", "h" + "e", @index4 + "l", @index5 + "l", @index6 + "o", @index7 + " world"], @index8.matches(@index3)) -[BLOCK_RECURSION_DEPTH_2]: cel.@block(["w" + "o" + "r", @index0 + "l" + "d", "h" + "e" + "l", @index2 + "l" + "o", @index3 + " world"], @index4.matches(@index1)) -[BLOCK_RECURSION_DEPTH_3]: cel.@block(["w" + "o" + "r" + "l", @index0 + "d", "h" + "e" + "l" + "l", @index2 + "o" + " world"], @index3.matches(@index1)) -[BLOCK_RECURSION_DEPTH_4]: cel.@block(["w" + "o" + "r" + "l" + "d", "h" + "e" + "l" + "l" + "o", @index1 + " world"], @index2.matches(@index0)) -[BLOCK_RECURSION_DEPTH_5]: cel.@block(["w" + "o" + "r" + "l" + "d", "h" + "e" + "l" + "l" + "o" + " world"], @index1.matches(@index0)) -[BLOCK_RECURSION_DEPTH_6]: cel.@block(["w" + "o" + "r" + "l" + "d", "h" + "e" + "l" + "l" + "o" + " world"], @index1.matches(@index0)) -[BLOCK_RECURSION_DEPTH_7]: cel.@block(["w" + "o" + "r" + "l" + "d", "h" + "e" + "l" + "l" + "o" + " world"], @index1.matches(@index0)) -[BLOCK_RECURSION_DEPTH_8]: cel.@block(["w" + "o" + "r" + "l" + "d", "h" + "e" + "l" + "l" + "o" + " world"], @index1.matches(@index0)) -[BLOCK_RECURSION_DEPTH_9]: cel.@block(["w" + "o" + "r" + "l" + "d", "h" + "e" + "l" + "l" + "o" + " world"], @index1.matches(@index0)) +[BLOCK_RECURSION_DEPTH_1]: cel.@block(["h" + "e", @index0 + "l", @index1 + "l", @index2 + "o", @index3 + " world", "w" + "o", @index5 + "r", @index6 + "l", @index7 + "d"], @index4.matches(@index8)) +[BLOCK_RECURSION_DEPTH_2]: cel.@block(["h" + "e" + "l", @index0 + "l" + "o", "w" + "o" + "r", @index2 + "l" + "d"], (@index1 + " world").matches(@index3)) +[BLOCK_RECURSION_DEPTH_3]: cel.@block(["h" + "e" + "l" + "l", "w" + "o" + "r" + "l"], (@index0 + "o" + " world").matches(@index1 + "d")) +[BLOCK_RECURSION_DEPTH_4]: cel.@block(["h" + "e" + "l" + "l" + "o", "w" + "o" + "r" + "l" + "d"], (@index0 + " world").matches(@index1)) +[BLOCK_RECURSION_DEPTH_5]: cel.@block(["h" + "e" + "l" + "l" + "o" + " world"], @index0.matches("w" + "o" + "r" + "l" + "d")) +[BLOCK_RECURSION_DEPTH_6]: ("h" + "e" + "l" + "l" + "o" + " world").matches("w" + "o" + "r" + "l" + "d") +[BLOCK_RECURSION_DEPTH_7]: ("h" + "e" + "l" + "l" + "o" + " world").matches("w" + "o" + "r" + "l" + "d") +[BLOCK_RECURSION_DEPTH_8]: ("h" + "e" + "l" + "l" + "o" + " world").matches("w" + "o" + "r" + "l" + "d") +[BLOCK_RECURSION_DEPTH_9]: ("h" + "e" + "l" + "l" + "o" + " world").matches("w" + "o" + "r" + "l" + "d") Test case: CUSTOM_FUNCTION_INELIMINABLE Source: non_pure_custom_func(msg.oneof_type.payload.single_int64) + non_pure_custom_func(msg.oneof_type.payload.single_int32) + non_pure_custom_func(msg.oneof_type.payload.single_int64) + non_pure_custom_func(msg.single_int64) @@ -628,15 +628,15 @@ Source: non_pure_custom_func(msg.oneof_type.payload.single_int64) + non_pure_cus Result: 31 [CASCADED_BINDS]: cel.bind(@r0, msg.oneof_type.payload, cel.bind(@r1, @r0.single_int64, non_pure_custom_func(@r1) + non_pure_custom_func(@r0.single_int32) + non_pure_custom_func(@r1))) + non_pure_custom_func(msg.single_int64) [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.oneof_type.payload, @index0.single_int64], non_pure_custom_func(@index1) + non_pure_custom_func(@index0.single_int32) + non_pure_custom_func(@index1) + non_pure_custom_func(msg.single_int64)) -[BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, msg.single_int64, @index1.single_int32], non_pure_custom_func(@index2) + non_pure_custom_func(@index4) + non_pure_custom_func(@index2) + non_pure_custom_func(@index3)) -[BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, msg.single_int64, @index1.single_int32], non_pure_custom_func(@index2) + non_pure_custom_func(@index4) + non_pure_custom_func(@index2) + non_pure_custom_func(@index3)) -[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, msg.single_int64, @index1.single_int32], non_pure_custom_func(@index2) + non_pure_custom_func(@index4) + non_pure_custom_func(@index2) + non_pure_custom_func(@index3)) -[BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, msg.single_int64, @index1.single_int32], non_pure_custom_func(@index2) + non_pure_custom_func(@index4) + non_pure_custom_func(@index2) + non_pure_custom_func(@index3)) -[BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, msg.single_int64, @index1.single_int32], non_pure_custom_func(@index2) + non_pure_custom_func(@index4) + non_pure_custom_func(@index2) + non_pure_custom_func(@index3)) -[BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, msg.single_int64, @index1.single_int32], non_pure_custom_func(@index2) + non_pure_custom_func(@index4) + non_pure_custom_func(@index2) + non_pure_custom_func(@index3)) -[BLOCK_RECURSION_DEPTH_7]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, msg.single_int64, @index1.single_int32], non_pure_custom_func(@index2) + non_pure_custom_func(@index4) + non_pure_custom_func(@index2) + non_pure_custom_func(@index3)) -[BLOCK_RECURSION_DEPTH_8]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, msg.single_int64, @index1.single_int32], non_pure_custom_func(@index2) + non_pure_custom_func(@index4) + non_pure_custom_func(@index2) + non_pure_custom_func(@index3)) -[BLOCK_RECURSION_DEPTH_9]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, msg.single_int64, @index1.single_int32], non_pure_custom_func(@index2) + non_pure_custom_func(@index4) + non_pure_custom_func(@index2) + non_pure_custom_func(@index3)) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64], non_pure_custom_func(@index2) + non_pure_custom_func(@index1.single_int32) + non_pure_custom_func(@index2) + non_pure_custom_func(msg.single_int64)) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type.payload, @index0.single_int64], non_pure_custom_func(@index1) + non_pure_custom_func(@index0.single_int32) + non_pure_custom_func(@index1) + non_pure_custom_func(msg.single_int64)) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type.payload.single_int64], non_pure_custom_func(@index0) + non_pure_custom_func(msg.oneof_type.payload.single_int32) + non_pure_custom_func(@index0) + non_pure_custom_func(msg.single_int64)) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.oneof_type.payload.single_int64], non_pure_custom_func(@index0) + non_pure_custom_func(msg.oneof_type.payload.single_int32) + non_pure_custom_func(@index0) + non_pure_custom_func(msg.single_int64)) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.oneof_type.payload.single_int64], non_pure_custom_func(@index0) + non_pure_custom_func(msg.oneof_type.payload.single_int32) + non_pure_custom_func(@index0) + non_pure_custom_func(msg.single_int64)) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.oneof_type.payload.single_int64], non_pure_custom_func(@index0) + non_pure_custom_func(msg.oneof_type.payload.single_int32) + non_pure_custom_func(@index0) + non_pure_custom_func(msg.single_int64)) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([msg.oneof_type.payload.single_int64], non_pure_custom_func(@index0) + non_pure_custom_func(msg.oneof_type.payload.single_int32) + non_pure_custom_func(@index0) + non_pure_custom_func(msg.single_int64)) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([msg.oneof_type.payload.single_int64], non_pure_custom_func(@index0) + non_pure_custom_func(msg.oneof_type.payload.single_int32) + non_pure_custom_func(@index0) + non_pure_custom_func(msg.single_int64)) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([msg.oneof_type.payload.single_int64], non_pure_custom_func(@index0) + non_pure_custom_func(msg.oneof_type.payload.single_int32) + non_pure_custom_func(@index0) + non_pure_custom_func(msg.single_int64)) Test case: CUSTOM_FUNCTION_ELIMINABLE Source: pure_custom_func(msg.oneof_type.payload.single_int64) + pure_custom_func(msg.oneof_type.payload.single_int32) + pure_custom_func(msg.oneof_type.payload.single_int64) + pure_custom_func(msg.single_int64) @@ -644,12 +644,12 @@ Source: pure_custom_func(msg.oneof_type.payload.single_int64) + pure_custom_func Result: 31 [CASCADED_BINDS]: cel.bind(@r0, msg.oneof_type.payload, cel.bind(@r1, pure_custom_func(@r0.single_int64), @r1 + pure_custom_func(@r0.single_int32) + @r1)) + pure_custom_func(msg.single_int64) [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.oneof_type.payload, pure_custom_func(@index0.single_int64)], @index1 + pure_custom_func(@index0.single_int32) + @index1 + pure_custom_func(msg.single_int64)) -[BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, pure_custom_func(@index2), msg.single_int64, pure_custom_func(@index4), @index1.single_int32, pure_custom_func(@index6), @index3 + @index7, @index8 + @index3], @index9 + @index5) -[BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, pure_custom_func(@index2), pure_custom_func(msg.single_int64), pure_custom_func(@index1.single_int32), @index3 + @index5 + @index3], @index6 + @index4) -[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, pure_custom_func(@index2), pure_custom_func(msg.single_int64), @index3 + pure_custom_func(@index1.single_int32), @index5 + @index3], @index6 + @index4) -[BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, pure_custom_func(@index2), pure_custom_func(msg.single_int64), @index3 + pure_custom_func(@index1.single_int32) + @index3], @index5 + @index4) -[BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, pure_custom_func(@index2), pure_custom_func(msg.single_int64), @index3 + pure_custom_func(@index1.single_int32) + @index3], @index5 + @index4) -[BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, pure_custom_func(@index2), pure_custom_func(msg.single_int64), @index3 + pure_custom_func(@index1.single_int32) + @index3], @index5 + @index4) -[BLOCK_RECURSION_DEPTH_7]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, pure_custom_func(@index2), pure_custom_func(msg.single_int64), @index3 + pure_custom_func(@index1.single_int32) + @index3], @index5 + @index4) -[BLOCK_RECURSION_DEPTH_8]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, pure_custom_func(@index2), pure_custom_func(msg.single_int64), @index3 + pure_custom_func(@index1.single_int32) + @index3], @index5 + @index4) -[BLOCK_RECURSION_DEPTH_9]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, pure_custom_func(@index2), pure_custom_func(msg.single_int64), @index3 + pure_custom_func(@index1.single_int32) + @index3], @index5 + @index4) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, pure_custom_func(@index2), @index1.single_int32, pure_custom_func(@index4), @index3 + @index5, @index6 + @index3, msg.single_int64, pure_custom_func(@index8)], @index7 + @index9) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type.payload, pure_custom_func(@index0.single_int64), pure_custom_func(@index0.single_int32), @index1 + @index2 + @index1, pure_custom_func(msg.single_int64)], @index3 + @index4) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type.payload.single_int64, pure_custom_func(@index0), msg.oneof_type.payload.single_int32, @index1 + pure_custom_func(@index2) + @index1], @index3 + pure_custom_func(msg.single_int64)) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([pure_custom_func(msg.oneof_type.payload.single_int64), pure_custom_func(msg.oneof_type.payload.single_int32)], @index0 + @index1 + @index0 + pure_custom_func(msg.single_int64)) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([pure_custom_func(msg.oneof_type.payload.single_int64), @index0 + pure_custom_func(msg.oneof_type.payload.single_int32)], @index1 + @index0 + pure_custom_func(msg.single_int64)) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([pure_custom_func(msg.oneof_type.payload.single_int64), @index0 + pure_custom_func(msg.oneof_type.payload.single_int32) + @index0], @index1 + pure_custom_func(msg.single_int64)) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([pure_custom_func(msg.oneof_type.payload.single_int64)], @index0 + pure_custom_func(msg.oneof_type.payload.single_int32) + @index0 + pure_custom_func(msg.single_int64)) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([pure_custom_func(msg.oneof_type.payload.single_int64)], @index0 + pure_custom_func(msg.oneof_type.payload.single_int32) + @index0 + pure_custom_func(msg.single_int64)) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([pure_custom_func(msg.oneof_type.payload.single_int64)], @index0 + pure_custom_func(msg.oneof_type.payload.single_int32) + @index0 + pure_custom_func(msg.single_int64)) From dfebe25d6228578a21506375400be4739ccfaf0d Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Tue, 5 Mar 2024 11:42:29 -0800 Subject: [PATCH 050/486] Fix constant folding with in operator involving comprehension identifiers PiperOrigin-RevId: 612916293 --- .../optimizers/ConstantFoldingOptimizer.java | 43 ++++++++++++++----- .../ConstantFoldingOptimizerTest.java | 10 ++++- 2 files changed, 41 insertions(+), 12 deletions(-) diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java b/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java index 716cdafc6..f913c3d37 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java @@ -85,22 +85,21 @@ public OptimizationResult optimize(CelNavigableAst navigableAst, Cel cel) if (iterCount >= constantFoldingOptions.maxIterationLimit()) { throw new IllegalStateException("Max iteration count reached."); } - Optional foldableExpr = + Optional foldableExpr = navigableAst .getRoot() .allNodes() .filter(ConstantFoldingOptimizer::canFold) - .map(CelNavigableExpr::expr) - .filter(expr -> !visitedExprs.contains(expr)) + .filter(node -> !visitedExprs.contains(node.expr())) .findAny(); if (!foldableExpr.isPresent()) { break; } - visitedExprs.add(foldableExpr.get()); + visitedExprs.add(foldableExpr.get().expr()); Optional mutatedAst; // Attempt to prune if it is a non-strict call - mutatedAst = maybePruneBranches(navigableAst.getAst(), foldableExpr.get()); + mutatedAst = maybePruneBranches(navigableAst.getAst(), foldableExpr.get().expr()); if (!mutatedAst.isPresent()) { // Evaluate the call then fold mutatedAst = maybeFold(cel, navigableAst.getAst(), foldableExpr.get()); @@ -150,7 +149,7 @@ private static boolean canFold(CelNavigableExpr navigableExpr) { } if (functionName.equals(Operator.IN.getFunction())) { - return true; + return canFoldInOperator(navigableExpr); } // Default case: all call arguments must be constants. If the argument is a container (ex: @@ -166,6 +165,30 @@ private static boolean canFold(CelNavigableExpr navigableExpr) { } } + private static boolean canFoldInOperator(CelNavigableExpr navigableExpr) { + ImmutableList allIdents = + navigableExpr + .allNodes() + .filter(node -> node.getKind().equals(Kind.IDENT)) + .collect(toImmutableList()); + for (CelNavigableExpr identNode : allIdents) { + CelNavigableExpr parent = identNode.parent().orElse(null); + while (parent != null) { + if (parent.getKind().equals(Kind.COMPREHENSION)) { + if (parent.expr().comprehension().accuVar().equals(identNode.expr().ident().name())) { + // Prevent folding a subexpression if it contains a variable declared by a + // comprehension. The subexpression cannot be compiled without the full context of the + // surrounding comprehension. + return false; + } + } + parent = parent.parent().orElse(null); + } + } + + return true; + } + private static boolean areChildrenArgConstant(CelNavigableExpr expr) { if (expr.getKind().equals(Kind.CONSTANT)) { return true; @@ -195,10 +218,10 @@ private static boolean isNestedComprehension(CelNavigableExpr expr) { } private Optional maybeFold( - Cel cel, CelAbstractSyntaxTree ast, CelExpr expr) throws CelOptimizationException { + Cel cel, CelAbstractSyntaxTree ast, CelNavigableExpr node) throws CelOptimizationException { Object result; try { - result = CelExprUtil.evaluateExpr(cel, expr); + result = CelExprUtil.evaluateExpr(cel, node.expr()); } catch (CelValidationException | CelEvaluationException e) { throw new CelOptimizationException( "Constant folding failure. Failed to evaluate subtree due to: " + e.getMessage(), e); @@ -209,11 +232,11 @@ private Optional maybeFold( // ex2: optional.ofNonZeroValue(5) -> optional.of(5) if (result instanceof Optional) { Optional optResult = ((Optional) result); - return maybeRewriteOptional(optResult, ast, expr); + return maybeRewriteOptional(optResult, ast, node.expr()); } return maybeAdaptEvaluatedResult(result) - .map(celExpr -> mutableAst.replaceSubtree(ast, celExpr, expr.id())); + .map(celExpr -> mutableAst.replaceSubtree(ast, celExpr, node.id())); } private Optional maybeAdaptEvaluatedResult(Object result) { diff --git a/optimizer/src/test/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizerTest.java b/optimizer/src/test/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizerTest.java index 2ed564cc9..5ccc41388 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizerTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizerTest.java @@ -26,6 +26,7 @@ import dev.cel.common.types.ListType; import dev.cel.common.types.MapType; import dev.cel.common.types.SimpleType; +import dev.cel.extensions.CelExtensions; import dev.cel.extensions.CelOptionalLibrary; import dev.cel.optimizer.CelOptimizationException; import dev.cel.optimizer.CelOptimizer; @@ -48,7 +49,7 @@ public class ConstantFoldingOptimizerTest { .addVar("map_var", MapType.create(SimpleType.STRING, SimpleType.STRING)) .addMessageTypes(TestAllTypes.getDescriptor()) .setContainer("dev.cel.testing.testdata.proto3") - .addCompilerLibraries(CelOptionalLibrary.INSTANCE) + .addCompilerLibraries(CelExtensions.bindings(), CelOptionalLibrary.INSTANCE) .addRuntimeLibraries(CelOptionalLibrary.INSTANCE) .build(); @@ -159,6 +160,8 @@ public class ConstantFoldingOptimizerTest { "{source: '{\"a\": dyn([1, 2]), \"b\": x}', expected: '{\"a\": [1, 2], \"b\": x}'}") @TestParameters("{source: 'map_var[?\"key\"]', expected: 'map_var[?\"key\"]'}") @TestParameters("{source: '\"abc\" in list_var', expected: '\"abc\" in list_var'}") + @TestParameters( + "{source: 'cel.bind(r0, [1, 2, 3], cel.bind(r1, 1 in r0, r1))', expected: 'true'}") // TODO: Support folding lists with mixed types. This requires mutable lists. // @TestParameters("{source: 'dyn([1]) + [1.0]'}") public void constantFold_success(String source, String expected) throws Exception { @@ -198,6 +201,9 @@ public void constantFold_success(String source, String expected) throws Exceptio @TestParameters( "{source: '[{}, {\"a\": 1}, {\"b\": 2}].filter(m, has(x.a))', expected:" + " '[{}, {\"a\": 1}, {\"b\": 2}].filter(m, has(x.a))'}") + @TestParameters( + "{source: 'cel.bind(r0, [1, 2, 3], cel.bind(r1, 1 in r0 && 2 in x, r1))', expected:" + + " 'cel.bind(r0, [1, 2, 3], cel.bind(r1, 1 in r0 && 2 in x, r1))'}") public void constantFold_macros_macroCallMetadataPopulated(String source, String expected) throws Exception { Cel cel = @@ -207,7 +213,7 @@ public void constantFold_macros_macroCallMetadataPopulated(String source, String .addMessageTypes(TestAllTypes.getDescriptor()) .setStandardMacros(CelStandardMacro.STANDARD_MACROS) .setOptions(CelOptions.current().populateMacroCalls(true).build()) - .addCompilerLibraries(CelOptionalLibrary.INSTANCE) + .addCompilerLibraries(CelExtensions.bindings(), CelOptionalLibrary.INSTANCE) .addRuntimeLibraries(CelOptionalLibrary.INSTANCE) .build(); CelOptimizer celOptimizer = From 9fd2d2643946ee811947e98fd8251a3b889c1fc0 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Tue, 5 Mar 2024 13:09:11 -0800 Subject: [PATCH 051/486] Retain tagged extension when it exists in both original and new ASTs PiperOrigin-RevId: 612944207 --- .../main/java/dev/cel/common/CelSource.java | 17 ++++-- .../java/dev/cel/common/CelSourceTest.java | 3 +- .../java/dev/cel/optimizer/MutableAst.java | 9 ++- .../dev/cel/optimizer/MutableAstTest.java | 60 ++++++++++++++++++- 4 files changed, 81 insertions(+), 8 deletions(-) diff --git a/common/src/main/java/dev/cel/common/CelSource.java b/common/src/main/java/dev/cel/common/CelSource.java index 62a74873a..6adaf8773 100644 --- a/common/src/main/java/dev/cel/common/CelSource.java +++ b/common/src/main/java/dev/cel/common/CelSource.java @@ -21,6 +21,7 @@ import com.google.common.base.Splitter; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.errorprone.annotations.CheckReturnValue; import com.google.errorprone.annotations.Immutable; @@ -43,7 +44,7 @@ public final class CelSource { private final ImmutableList lineOffsets; private final ImmutableMap positions; private final ImmutableMap macroCalls; - private final ImmutableList extensions; + private final ImmutableSet extensions; private CelSource(Builder builder) { this.codePoints = checkNotNull(builder.codePoints); @@ -80,7 +81,7 @@ public ImmutableMap getMacroCalls() { return macroCalls; } - public ImmutableList getExtensions() { + public ImmutableSet getExtensions() { return extensions; } @@ -209,7 +210,7 @@ public static final class Builder { private final List lineOffsets; private final ImmutableMap.Builder positions; private final Map macroCalls; - private final ImmutableList.Builder extensions; + private final ImmutableSet.Builder extensions; private String description; @@ -222,7 +223,7 @@ private Builder(CelCodePointArray codePoints, List lineOffsets) { this.lineOffsets = checkNotNull(lineOffsets); this.positions = ImmutableMap.builder(); this.macroCalls = new HashMap<>(); - this.extensions = ImmutableList.builder(); + this.extensions = ImmutableSet.builder(); this.description = ""; } @@ -278,6 +279,10 @@ public Builder clearMacroCall(long exprId) { return this; } + /** + * Adds one or more {@link Extension}s to the source information. Extensions implement set + * semantics and deduped if same ones are provided. + */ @CanIgnoreReturnValue public Builder addAllExtensions(Iterable extensions) { checkNotNull(extensions); @@ -285,6 +290,10 @@ public Builder addAllExtensions(Iterable extensions) { return this; } + /** + * Adds one or more {@link Extension}s to the source information. Extensions implement set + * semantics and deduped if same ones are provided. + */ @CanIgnoreReturnValue public Builder addAllExtensions(Extension... extensions) { return addAllExtensions(Arrays.asList(extensions)); diff --git a/common/src/test/java/dev/cel/common/CelSourceTest.java b/common/src/test/java/dev/cel/common/CelSourceTest.java index 74e350a35..a97eeb853 100644 --- a/common/src/test/java/dev/cel/common/CelSourceTest.java +++ b/common/src/test/java/dev/cel/common/CelSourceTest.java @@ -18,6 +18,7 @@ import static org.antlr.v4.runtime.IntStream.UNKNOWN_SOURCE_NAME; import static org.junit.Assert.assertThrows; +import com.google.common.collect.Iterables; import dev.cel.common.CelSource.Extension; import dev.cel.common.CelSource.Extension.Component; import dev.cel.common.CelSource.Extension.Version; @@ -172,7 +173,7 @@ public void source_withExtension() { Component.COMPONENT_TYPE_CHECKER)) .build(); - Extension extension = celSource.getExtensions().get(0); + Extension extension = Iterables.getOnlyElement(celSource.getExtensions()); assertThat(extension.id()).isEqualTo("extension_id"); assertThat(extension.version().major()).isEqualTo(5L); assertThat(extension.version().minor()).isEqualTo(3L); diff --git a/optimizer/src/main/java/dev/cel/optimizer/MutableAst.java b/optimizer/src/main/java/dev/cel/optimizer/MutableAst.java index 1a466df67..181dda25c 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/MutableAst.java +++ b/optimizer/src/main/java/dev/cel/optimizer/MutableAst.java @@ -571,7 +571,11 @@ private static CelSource combine(CelSource celSource1, CelSource celSource2) { macroMap.putAll(celSource1.getMacroCalls()); macroMap.putAll(celSource2.getMacroCalls()); - return CelSource.newBuilder().addAllMacroCalls(macroMap.buildOrThrow()).build(); + return CelSource.newBuilder() + .addAllExtensions(celSource1.getExtensions()) + .addAllExtensions(celSource2.getExtensions()) + .addAllMacroCalls(macroMap.buildOrThrow()) + .build(); } /** @@ -589,7 +593,8 @@ private CelAbstractSyntaxTree stabilizeAst(CelAbstractSyntaxTree ast, long seedE return CelAbstractSyntaxTree.newParsedAst(newExprBuilder.build(), ast.getSource()); } - CelSource.Builder sourceBuilder = CelSource.newBuilder(); + CelSource.Builder sourceBuilder = + CelSource.newBuilder().addAllExtensions(ast.getSource().getExtensions()); // Update the macro call IDs and their call IDs for (Entry macroCall : ast.getSource().getMacroCalls().entrySet()) { long macroId = macroCall.getKey(); diff --git a/optimizer/src/test/java/dev/cel/optimizer/MutableAstTest.java b/optimizer/src/test/java/dev/cel/optimizer/MutableAstTest.java index da8ecfb7b..af0e1241e 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/MutableAstTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/MutableAstTest.java @@ -122,7 +122,7 @@ public void mutableAst_macro_sourceMacroCallsPopulated() throws Exception { } @Test - public void mutableAst_astContainsTaggedExtension_retained() throws Exception { + public void replaceSubtree_astContainsTaggedExtension_retained() throws Exception { CelAbstractSyntaxTree ast = CEL.compile("has(TestAllTypes{}.single_int32)").getAst(); Extension extension = Extension.create("test", Version.of(1, 1)); CelSource celSource = ast.getSource().toBuilder().addAllExtensions(extension).build(); @@ -137,6 +137,64 @@ public void mutableAst_astContainsTaggedExtension_retained() throws Exception { assertThat(mutatedAst.getSource().getExtensions()).containsExactly(extension); } + @Test + public void replaceSubtreeWithNewAst_astsContainTaggedExtension_retained() throws Exception { + // Setup first AST with a test extension + CelAbstractSyntaxTree ast = CEL.compile("has(TestAllTypes{}.single_int32)").getAst(); + Extension extension = Extension.create("test", Version.of(1, 1)); + ast = + CelAbstractSyntaxTree.newCheckedAst( + ast.getExpr(), + ast.getSource().toBuilder().addAllExtensions(extension).build(), + ast.getReferenceMap(), + ast.getTypeMap()); + // Setup second AST with another test extension + CelAbstractSyntaxTree astToReplaceWith = CEL.compile("cel.bind(a, true, a)").getAst(); + Extension extension2 = Extension.create("test2", Version.of(2, 2)); + astToReplaceWith = + CelAbstractSyntaxTree.newCheckedAst( + astToReplaceWith.getExpr(), + astToReplaceWith.getSource().toBuilder().addAllExtensions(extension2).build(), + astToReplaceWith.getReferenceMap(), + astToReplaceWith.getTypeMap()); + + // Mutate the original AST with the new AST at the root + CelAbstractSyntaxTree mutatedAst = + MUTABLE_AST.replaceSubtreeWithNewAst(ast, astToReplaceWith, ast.getExpr().id()); + + // Expect that both the extensions are merged + assertThat(mutatedAst.getSource().getExtensions()).containsExactly(extension, extension2); + } + + @Test + public void replaceSubtreeWithNewAst_astsContainSameExtensions_deduped() throws Exception { + // Setup first AST with a test extension + CelAbstractSyntaxTree ast = CEL.compile("has(TestAllTypes{}.single_int32)").getAst(); + Extension extension = Extension.create("test", Version.of(1, 1)); + ast = + CelAbstractSyntaxTree.newCheckedAst( + ast.getExpr(), + ast.getSource().toBuilder().addAllExtensions(extension).build(), + ast.getReferenceMap(), + ast.getTypeMap()); + // Setup second AST with the same test extension as above + CelAbstractSyntaxTree astToReplaceWith = CEL.compile("cel.bind(a, true, a)").getAst(); + Extension extension2 = Extension.create("test", Version.of(1, 1)); + astToReplaceWith = + CelAbstractSyntaxTree.newCheckedAst( + astToReplaceWith.getExpr(), + astToReplaceWith.getSource().toBuilder().addAllExtensions(extension2).build(), + astToReplaceWith.getReferenceMap(), + astToReplaceWith.getTypeMap()); + + // Mutate the original AST with the new AST at the root + CelAbstractSyntaxTree mutatedAst = + MUTABLE_AST.replaceSubtreeWithNewAst(ast, astToReplaceWith, ast.getExpr().id()); + + // Expect that the extension is deduped + assertThat(mutatedAst.getSource().getExtensions()).containsExactly(extension); + } + @Test @TestParameters("{source: '[1].exists(x, x > 0)', expectedMacroCallSize: 1}") @TestParameters( From 5c7efafd3c5abc611fb07f941dbcaec109865340 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Tue, 5 Mar 2024 13:44:00 -0800 Subject: [PATCH 052/486] Fix constant folding when ternary arg is replaced with a comprehension PiperOrigin-RevId: 612955389 --- optimizer/src/main/java/dev/cel/optimizer/MutableAst.java | 6 +++++- .../optimizer/optimizers/ConstantFoldingOptimizerTest.java | 5 ++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/optimizer/src/main/java/dev/cel/optimizer/MutableAst.java b/optimizer/src/main/java/dev/cel/optimizer/MutableAst.java index 181dda25c..bf813eef4 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/MutableAst.java +++ b/optimizer/src/main/java/dev/cel/optimizer/MutableAst.java @@ -130,7 +130,11 @@ public CelAbstractSyntaxTree replaceSubtree( CelAbstractSyntaxTree ast, CelExpr newExpr, long exprIdToReplace) { return replaceSubtreeWithNewAst( ast, - CelAbstractSyntaxTree.newParsedAst(newExpr, CelSource.newBuilder().build()), + CelAbstractSyntaxTree.newParsedAst( + newExpr, + // Copy the macro call information to the new AST such that macro call map can be + // normalized post-replacement. + CelSource.newBuilder().addAllMacroCalls(ast.getSource().getMacroCalls()).build()), exprIdToReplace); } diff --git a/optimizer/src/test/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizerTest.java b/optimizer/src/test/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizerTest.java index 5ccc41388..ddadd5a20 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizerTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizerTest.java @@ -204,6 +204,7 @@ public void constantFold_success(String source, String expected) throws Exceptio @TestParameters( "{source: 'cel.bind(r0, [1, 2, 3], cel.bind(r1, 1 in r0 && 2 in x, r1))', expected:" + " 'cel.bind(r0, [1, 2, 3], cel.bind(r1, 1 in r0 && 2 in x, r1))'}") + @TestParameters("{source: 'false ? false : cel.bind(a, x, a)', expected: 'cel.bind(a, x, a)'}") public void constantFold_macros_macroCallMetadataPopulated(String source, String expected) throws Exception { Cel cel = @@ -247,6 +248,8 @@ public void constantFold_macros_macroCallMetadataPopulated(String source, String @TestParameters( "{source: '[{}, {\"a\": 1}, {\"b\": 2}].filter(m, has({\"a\": true}.a)) == " + " [{}, {\"a\": 1}, {\"b\": 2}]'}") + @TestParameters("{source: 'cel.bind(r0, [1, 2, 3], cel.bind(r1, 1 in r0 && 2 in r0, r1))'}") + @TestParameters("{source: 'false ? false : cel.bind(a, true, a)'}") public void constantFold_macros_withoutMacroCallMetadata(String source) throws Exception { Cel cel = CelFactory.standardCelBuilder() @@ -255,7 +258,7 @@ public void constantFold_macros_withoutMacroCallMetadata(String source) throws E .addMessageTypes(TestAllTypes.getDescriptor()) .setStandardMacros(CelStandardMacro.STANDARD_MACROS) .setOptions(CelOptions.current().populateMacroCalls(false).build()) - .addCompilerLibraries(CelOptionalLibrary.INSTANCE) + .addCompilerLibraries(CelExtensions.bindings(), CelOptionalLibrary.INSTANCE) .addRuntimeLibraries(CelOptionalLibrary.INSTANCE) .build(); CelOptimizer celOptimizer = From 2a5f04a1e58a1dd9bbff6dcb7dfb87fdc11a43c2 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Tue, 5 Mar 2024 14:04:22 -0800 Subject: [PATCH 053/486] Add baseline tests for constant folding applied before subexpression optimization PiperOrigin-RevId: 612962249 --- .../SubexpressionOptimizerBaselineTest.java | 49 +- ...old_before_subexpression_unparsed.baseline | 655 ++++++++++++++++++ 2 files changed, 699 insertions(+), 5 deletions(-) create mode 100644 optimizer/src/test/resources/constfold_before_subexpression_unparsed.baseline diff --git a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerBaselineTest.java b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerBaselineTest.java index 278a79976..ca3e0f77a 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerBaselineTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerBaselineTest.java @@ -101,7 +101,7 @@ public void allOptimizers_producesSameEvaluationResult( CEL.createProgram(ast) .eval(ImmutableMap.of("msg", TEST_ALL_TYPES_INPUT, "x", 5L, "opt_x", Optional.of(5L))); - CelAbstractSyntaxTree optimizedAst = cseTestOptimizer.celOptimizer.optimize(ast); + CelAbstractSyntaxTree optimizedAst = cseTestOptimizer.cseOptimizer.optimize(ast); Object optimizedEvalResult = CEL.createProgram(optimizedAst) @@ -119,7 +119,39 @@ public void subexpression_unparsed() throws Exception { boolean resultPrinted = false; for (CseTestOptimizer cseTestOptimizer : CseTestOptimizer.values()) { String optimizerName = cseTestOptimizer.name(); - CelAbstractSyntaxTree optimizedAst = cseTestOptimizer.celOptimizer.optimize(ast); + CelAbstractSyntaxTree optimizedAst = cseTestOptimizer.cseOptimizer.optimize(ast); + if (!resultPrinted) { + Object optimizedEvalResult = + CEL.createProgram(optimizedAst) + .eval( + ImmutableMap.of( + "msg", TEST_ALL_TYPES_INPUT, "x", 5L, "opt_x", Optional.of(5L))); + testOutput().println("Result: " + optimizedEvalResult); + resultPrinted = true; + } + try { + testOutput().printf("[%s]: %s", optimizerName, CEL_UNPARSER.unparse(optimizedAst)); + } catch (RuntimeException e) { + testOutput().printf("[%s]: Unparse Error: %s", optimizerName, e); + } + testOutput().println(); + } + testOutput().println(); + } + } + + @Test + public void constfold_before_subexpression_unparsed() throws Exception { + for (CseTestCase cseTestCase : CseTestCase.values()) { + testOutput().println("Test case: " + cseTestCase.name()); + testOutput().println("Source: " + cseTestCase.source); + testOutput().println("=====>"); + CelAbstractSyntaxTree ast = CEL.compile(cseTestCase.source).getAst(); + boolean resultPrinted = false; + for (CseTestOptimizer cseTestOptimizer : CseTestOptimizer.values()) { + String optimizerName = cseTestOptimizer.name(); + CelAbstractSyntaxTree optimizedAst = + cseTestOptimizer.cseWithConstFoldingOptimizer.optimize(ast); if (!resultPrinted) { Object optimizedEvalResult = CEL.createProgram(optimizedAst) @@ -149,7 +181,7 @@ public void subexpression_ast(@TestParameter CseTestOptimizer cseTestOptimizer) testOutput().println("Source: " + cseTestCase.source); testOutput().println("=====>"); CelAbstractSyntaxTree ast = CEL.compile(cseTestCase.source).getAst(); - CelAbstractSyntaxTree optimizedAst = cseTestOptimizer.celOptimizer.optimize(ast); + CelAbstractSyntaxTree optimizedAst = cseTestOptimizer.cseOptimizer.optimize(ast); testOutput().println(optimizedAst.getExpr()); } } @@ -339,10 +371,17 @@ private enum CseTestOptimizer { BLOCK_RECURSION_DEPTH_9( OPTIMIZER_COMMON_OPTIONS.toBuilder().subexpressionMaxRecursionDepth(9).build()); - private final CelOptimizer celOptimizer; + private final CelOptimizer cseOptimizer; + private final CelOptimizer cseWithConstFoldingOptimizer; CseTestOptimizer(SubexpressionOptimizerOptions option) { - this.celOptimizer = newCseOptimizer(CEL, option); + this.cseOptimizer = newCseOptimizer(CEL, option); + this.cseWithConstFoldingOptimizer = + CelOptimizerFactory.standardCelOptimizerBuilder(CEL) + .addAstOptimizers( + ConstantFoldingOptimizer.getInstance(), + SubexpressionOptimizer.newInstance(option)) + .build(); } } diff --git a/optimizer/src/test/resources/constfold_before_subexpression_unparsed.baseline b/optimizer/src/test/resources/constfold_before_subexpression_unparsed.baseline new file mode 100644 index 000000000..2ebaf7ac2 --- /dev/null +++ b/optimizer/src/test/resources/constfold_before_subexpression_unparsed.baseline @@ -0,0 +1,655 @@ +Test case: SIZE_1 +Source: size([1,2]) + size([1,2]) + 1 == 5 +=====> +Result: true +[CASCADED_BINDS]: true +[BLOCK_COMMON_SUBEXPR_ONLY]: true +[BLOCK_RECURSION_DEPTH_1]: true +[BLOCK_RECURSION_DEPTH_2]: true +[BLOCK_RECURSION_DEPTH_3]: true +[BLOCK_RECURSION_DEPTH_4]: true +[BLOCK_RECURSION_DEPTH_5]: true +[BLOCK_RECURSION_DEPTH_6]: true +[BLOCK_RECURSION_DEPTH_7]: true +[BLOCK_RECURSION_DEPTH_8]: true +[BLOCK_RECURSION_DEPTH_9]: true + +Test case: SIZE_2 +Source: 2 + size([1,2]) + size([1,2]) + 1 == 7 +=====> +Result: true +[CASCADED_BINDS]: true +[BLOCK_COMMON_SUBEXPR_ONLY]: true +[BLOCK_RECURSION_DEPTH_1]: true +[BLOCK_RECURSION_DEPTH_2]: true +[BLOCK_RECURSION_DEPTH_3]: true +[BLOCK_RECURSION_DEPTH_4]: true +[BLOCK_RECURSION_DEPTH_5]: true +[BLOCK_RECURSION_DEPTH_6]: true +[BLOCK_RECURSION_DEPTH_7]: true +[BLOCK_RECURSION_DEPTH_8]: true +[BLOCK_RECURSION_DEPTH_9]: true + +Test case: SIZE_3 +Source: size([0]) + size([0]) + size([1,2]) + size([1,2]) == 6 +=====> +Result: true +[CASCADED_BINDS]: true +[BLOCK_COMMON_SUBEXPR_ONLY]: true +[BLOCK_RECURSION_DEPTH_1]: true +[BLOCK_RECURSION_DEPTH_2]: true +[BLOCK_RECURSION_DEPTH_3]: true +[BLOCK_RECURSION_DEPTH_4]: true +[BLOCK_RECURSION_DEPTH_5]: true +[BLOCK_RECURSION_DEPTH_6]: true +[BLOCK_RECURSION_DEPTH_7]: true +[BLOCK_RECURSION_DEPTH_8]: true +[BLOCK_RECURSION_DEPTH_9]: true + +Test case: SIZE_4 +Source: 5 + size([0]) + size([0]) + size([1,2]) + size([1,2]) + size([1,2,3]) + size([1,2,3]) == 17 +=====> +Result: true +[CASCADED_BINDS]: true +[BLOCK_COMMON_SUBEXPR_ONLY]: true +[BLOCK_RECURSION_DEPTH_1]: true +[BLOCK_RECURSION_DEPTH_2]: true +[BLOCK_RECURSION_DEPTH_3]: true +[BLOCK_RECURSION_DEPTH_4]: true +[BLOCK_RECURSION_DEPTH_5]: true +[BLOCK_RECURSION_DEPTH_6]: true +[BLOCK_RECURSION_DEPTH_7]: true +[BLOCK_RECURSION_DEPTH_8]: true +[BLOCK_RECURSION_DEPTH_9]: true + +Test case: TIMESTAMP +Source: timestamp(int(timestamp(1000000000))).getFullYear() + timestamp(int(timestamp(75))).getFullYear() + timestamp(int(timestamp(50))).getFullYear() + timestamp(int(timestamp(1000000000))).getFullYear() + timestamp(int(timestamp(50))).getSeconds() + timestamp(int(timestamp(200))).getFullYear() + timestamp(int(timestamp(200))).getFullYear() + timestamp(int(timestamp(75))).getMinutes() + timestamp(int(timestamp(1000000000))).getFullYear() == 13934 +=====> +Result: true +[CASCADED_BINDS]: true +[BLOCK_COMMON_SUBEXPR_ONLY]: true +[BLOCK_RECURSION_DEPTH_1]: true +[BLOCK_RECURSION_DEPTH_2]: true +[BLOCK_RECURSION_DEPTH_3]: true +[BLOCK_RECURSION_DEPTH_4]: true +[BLOCK_RECURSION_DEPTH_5]: true +[BLOCK_RECURSION_DEPTH_6]: true +[BLOCK_RECURSION_DEPTH_7]: true +[BLOCK_RECURSION_DEPTH_8]: true +[BLOCK_RECURSION_DEPTH_9]: true + +Test case: MAP_INDEX +Source: {"a": 2}["a"] + {"a": 2}["a"] * {"a": 2}["a"] == 6 +=====> +Result: true +[CASCADED_BINDS]: true +[BLOCK_COMMON_SUBEXPR_ONLY]: true +[BLOCK_RECURSION_DEPTH_1]: true +[BLOCK_RECURSION_DEPTH_2]: true +[BLOCK_RECURSION_DEPTH_3]: true +[BLOCK_RECURSION_DEPTH_4]: true +[BLOCK_RECURSION_DEPTH_5]: true +[BLOCK_RECURSION_DEPTH_6]: true +[BLOCK_RECURSION_DEPTH_7]: true +[BLOCK_RECURSION_DEPTH_8]: true +[BLOCK_RECURSION_DEPTH_9]: true + +Test case: NESTED_MAP_CONSTRUCTION +Source: {'a': {'b': 1}, 'c': {'b': 1}, 'd': {'e': {'b': 1}}, 'e': {'e': {'b': 1}}} +=====> +Result: {a={b=1}, c={b=1}, d={e={b=1}}, e={e={b=1}}} +[CASCADED_BINDS]: cel.bind(@r0, {"b": 1}, cel.bind(@r1, {"e": @r0}, {"a": @r0, "c": @r0, "d": @r1, "e": @r1})) +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([{"b": 1}, {"e": @index0}], {"a": @index0, "c": @index0, "d": @index1, "e": @index1}) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([{"b": 1}, {"e": @index0}], {"a": @index0, "c": @index0, "d": @index1, "e": @index1}) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([{"e": {"b": 1}}, {"b": 1}], {"a": @index1, "c": @index1, "d": @index0, "e": @index0}) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([{"e": {"b": 1}}, {"b": 1}], {"a": @index1, "c": @index1, "d": @index0, "e": @index0}) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([{"e": {"b": 1}}, {"b": 1}], {"a": @index1, "c": @index1, "d": @index0, "e": @index0}) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([{"e": {"b": 1}}, {"b": 1}], {"a": @index1, "c": @index1, "d": @index0, "e": @index0}) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([{"e": {"b": 1}}, {"b": 1}], {"a": @index1, "c": @index1, "d": @index0, "e": @index0}) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([{"e": {"b": 1}}, {"b": 1}], {"a": @index1, "c": @index1, "d": @index0, "e": @index0}) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([{"e": {"b": 1}}, {"b": 1}], {"a": @index1, "c": @index1, "d": @index0, "e": @index0}) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([{"e": {"b": 1}}, {"b": 1}], {"a": @index1, "c": @index1, "d": @index0, "e": @index0}) + +Test case: NESTED_LIST_CONSTRUCTION +Source: [1, [1,2,3,4], 2, [1,2,3,4], 5, [1,2,3,4], 7, [[1,2], [1,2,3,4]], [1,2]] +=====> +Result: [1, [1, 2, 3, 4], 2, [1, 2, 3, 4], 5, [1, 2, 3, 4], 7, [[1, 2], [1, 2, 3, 4]], [1, 2]] +[CASCADED_BINDS]: cel.bind(@r0, [1, 2, 3, 4], cel.bind(@r1, [1, 2], [1, @r0, 2, @r0, 5, @r0, 7, [@r1, @r0], @r1])) +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([[1, 2, 3, 4], [1, 2]], [1, @index0, 2, @index0, 5, @index0, 7, [@index1, @index0], @index1]) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([[1, 2, 3, 4], [1, 2], [@index1, @index0]], [1, @index0, 2, @index0, 5, @index0, 7, @index2, @index1]) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([[1, 2, 3, 4], [1, 2]], [1, @index0, 2, @index0, 5, @index0, 7, [@index1, @index0], @index1]) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([[1, 2, 3, 4], [1, 2]], [1, @index0, 2, @index0, 5, @index0, 7, [@index1, @index0], @index1]) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([[1, 2, 3, 4], [1, 2]], [1, @index0, 2, @index0, 5, @index0, 7, [@index1, @index0], @index1]) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([[1, 2, 3, 4], [1, 2]], [1, @index0, 2, @index0, 5, @index0, 7, [@index1, @index0], @index1]) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([[1, 2, 3, 4], [1, 2]], [1, @index0, 2, @index0, 5, @index0, 7, [@index1, @index0], @index1]) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([[1, 2, 3, 4], [1, 2]], [1, @index0, 2, @index0, 5, @index0, 7, [@index1, @index0], @index1]) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([[1, 2, 3, 4], [1, 2]], [1, @index0, 2, @index0, 5, @index0, 7, [@index1, @index0], @index1]) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([[1, 2, 3, 4], [1, 2]], [1, @index0, 2, @index0, 5, @index0, 7, [@index1, @index0], @index1]) + +Test case: SELECT +Source: msg.single_int64 + msg.single_int64 == 6 +=====> +Result: true +[CASCADED_BINDS]: cel.bind(@r0, msg.single_int64, @r0 + @r0) == 6 +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.single_int64], @index0 + @index0 == 6) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.single_int64, @index0 + @index0], @index1 == 6) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.single_int64], @index0 + @index0 == 6) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.single_int64], @index0 + @index0 == 6) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.single_int64], @index0 + @index0 == 6) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.single_int64], @index0 + @index0 == 6) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.single_int64], @index0 + @index0 == 6) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([msg.single_int64], @index0 + @index0 == 6) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([msg.single_int64], @index0 + @index0 == 6) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([msg.single_int64], @index0 + @index0 == 6) + +Test case: SELECT_NESTED_1 +Source: msg.oneof_type.payload.single_int64 + msg.oneof_type.payload.single_int32 + msg.oneof_type.payload.single_int64 + msg.single_int64 + msg.oneof_type.payload.oneof_type.payload.single_int64 == 31 +=====> +Result: true +[CASCADED_BINDS]: cel.bind(@r0, msg.oneof_type.payload, cel.bind(@r1, @r0.single_int64, @r1 + @r0.single_int32 + @r1) + msg.single_int64 + @r0.oneof_type.payload.single_int64) == 31 +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.oneof_type.payload, @index0.single_int64], @index1 + @index0.single_int32 + @index1 + msg.single_int64 + @index0.oneof_type.payload.single_int64 == 31) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, @index1.single_int32, @index2 + @index3, @index4 + @index2, msg.single_int64, @index5 + @index6, @index1.oneof_type, @index8.payload, @index9.single_int64, @index7 + @index10], @index11 == 31) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type.payload, @index0.single_int64, @index1 + @index0.single_int32, @index2 + @index1 + msg.single_int64, @index0.oneof_type.payload, @index3 + @index4.single_int64], @index5 == 31) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type.payload.single_int64, msg.oneof_type.payload, @index0 + @index1.single_int32 + @index0, @index1.oneof_type.payload.single_int64, @index2 + msg.single_int64 + @index3], @index4 == 31) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.oneof_type.payload.single_int64, msg.oneof_type.payload, @index0 + @index1.single_int32 + @index0 + msg.single_int64, @index2 + @index1.oneof_type.payload.single_int64], @index3 == 31) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.oneof_type.payload.single_int64, msg.oneof_type.payload, @index0 + @index1.single_int32 + @index0 + msg.single_int64 + @index1.oneof_type.payload.single_int64], @index2 == 31) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.oneof_type.payload.single_int64, msg.oneof_type.payload], @index0 + @index1.single_int32 + @index0 + msg.single_int64 + @index1.oneof_type.payload.single_int64 == 31) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([msg.oneof_type.payload.single_int64, msg.oneof_type.payload], @index0 + @index1.single_int32 + @index0 + msg.single_int64 + @index1.oneof_type.payload.single_int64 == 31) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([msg.oneof_type.payload.single_int64, msg.oneof_type.payload], @index0 + @index1.single_int32 + @index0 + msg.single_int64 + @index1.oneof_type.payload.single_int64 == 31) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([msg.oneof_type.payload.single_int64, msg.oneof_type.payload], @index0 + @index1.single_int32 + @index0 + msg.single_int64 + @index1.oneof_type.payload.single_int64 == 31) + +Test case: SELECT_NESTED_2 +Source: true || msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload.single_bool || msg.oneof_type.payload.oneof_type.payload.oneof_type.child.child.payload.single_bool +=====> +Result: true +[CASCADED_BINDS]: true +[BLOCK_COMMON_SUBEXPR_ONLY]: true +[BLOCK_RECURSION_DEPTH_1]: true +[BLOCK_RECURSION_DEPTH_2]: true +[BLOCK_RECURSION_DEPTH_3]: true +[BLOCK_RECURSION_DEPTH_4]: true +[BLOCK_RECURSION_DEPTH_5]: true +[BLOCK_RECURSION_DEPTH_6]: true +[BLOCK_RECURSION_DEPTH_7]: true +[BLOCK_RECURSION_DEPTH_8]: true +[BLOCK_RECURSION_DEPTH_9]: true + +Test case: SELECT_NESTED_MESSAGE_MAP_INDEX_1 +Source: msg.oneof_type.payload.map_int32_int64[1] + msg.oneof_type.payload.map_int32_int64[1] + msg.oneof_type.payload.map_int32_int64[1] == 15 +=====> +Result: true +[CASCADED_BINDS]: cel.bind(@r0, msg.oneof_type.payload.map_int32_int64[1], @r0 + @r0 + @r0) == 15 +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.oneof_type.payload.map_int32_int64[1]], @index0 + @index0 + @index0 == 15) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_int32_int64, @index2[1], @index3 + @index3, @index4 + @index3], @index5 == 15) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type.payload, @index0.map_int32_int64[1], @index1 + @index1 + @index1], @index2 == 15) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type.payload.map_int32_int64, @index0[1]], @index1 + @index1 + @index1 == 15) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.oneof_type.payload.map_int32_int64[1]], @index0 + @index0 + @index0 == 15) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.oneof_type.payload.map_int32_int64[1]], @index0 + @index0 + @index0 == 15) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.oneof_type.payload.map_int32_int64[1]], @index0 + @index0 + @index0 == 15) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([msg.oneof_type.payload.map_int32_int64[1]], @index0 + @index0 + @index0 == 15) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([msg.oneof_type.payload.map_int32_int64[1]], @index0 + @index0 + @index0 == 15) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([msg.oneof_type.payload.map_int32_int64[1]], @index0 + @index0 + @index0 == 15) + +Test case: SELECT_NESTED_MESSAGE_MAP_INDEX_2 +Source: msg.oneof_type.payload.map_int32_int64[0] + msg.oneof_type.payload.map_int32_int64[1] + msg.oneof_type.payload.map_int32_int64[2] == 8 +=====> +Result: true +[CASCADED_BINDS]: cel.bind(@r0, msg.oneof_type.payload.map_int32_int64, @r0[0] + @r0[1] + @r0[2]) == 8 +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.oneof_type.payload.map_int32_int64], @index0[0] + @index0[1] + @index0[2] == 8) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_int32_int64, @index2[0], @index2[1], @index3 + @index4, @index2[2], @index5 + @index6], @index7 == 8) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type.payload, @index0.map_int32_int64, @index1[0] + @index1[1], @index2 + @index1[2]], @index3 == 8) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type.payload.map_int32_int64, @index0[0] + @index0[1] + @index0[2]], @index1 == 8) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.oneof_type.payload.map_int32_int64], @index0[0] + @index0[1] + @index0[2] == 8) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.oneof_type.payload.map_int32_int64], @index0[0] + @index0[1] + @index0[2] == 8) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.oneof_type.payload.map_int32_int64], @index0[0] + @index0[1] + @index0[2] == 8) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([msg.oneof_type.payload.map_int32_int64], @index0[0] + @index0[1] + @index0[2] == 8) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([msg.oneof_type.payload.map_int32_int64], @index0[0] + @index0[1] + @index0[2] == 8) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([msg.oneof_type.payload.map_int32_int64], @index0[0] + @index0[1] + @index0[2] == 8) + +Test case: SELECT_NESTED_NO_COMMON_SUBEXPR +Source: msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload.single_int64 +=====> +Result: 0 +[CASCADED_BINDS]: msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload.single_int64 +[BLOCK_COMMON_SUBEXPR_ONLY]: msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload.single_int64 +[BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.oneof_type, @index2.payload, @index3.oneof_type, @index4.payload, @index5.oneof_type, @index6.payload], @index7.single_int64) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type.payload, @index0.oneof_type.payload, @index1.oneof_type.payload, @index2.oneof_type.payload], @index3.single_int64) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type.payload.oneof_type, @index0.payload.oneof_type.payload], @index1.oneof_type.payload.single_int64) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.oneof_type.payload.oneof_type.payload, @index0.oneof_type.payload.oneof_type.payload], @index1.single_int64) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.oneof_type.payload.oneof_type.payload.oneof_type], @index0.payload.oneof_type.payload.single_int64) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.oneof_type.payload.oneof_type.payload.oneof_type.payload], @index0.oneof_type.payload.single_int64) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type], @index0.payload.single_int64) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload], @index0.single_int64) +[BLOCK_RECURSION_DEPTH_9]: msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload.single_int64 + +Test case: TERNARY +Source: (msg.single_int64 > 0 ? msg.single_int64 : 0) == 3 +=====> +Result: true +[CASCADED_BINDS]: cel.bind(@r0, msg.single_int64, (@r0 > 0) ? @r0 : 0) == 3 +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.single_int64], ((@index0 > 0) ? @index0 : 0) == 3) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.single_int64, @index0 > 0, @index1 ? @index0 : 0], @index2 == 3) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.single_int64, (@index0 > 0) ? @index0 : 0], @index1 == 3) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.single_int64], ((@index0 > 0) ? @index0 : 0) == 3) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.single_int64], ((@index0 > 0) ? @index0 : 0) == 3) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.single_int64], ((@index0 > 0) ? @index0 : 0) == 3) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.single_int64], ((@index0 > 0) ? @index0 : 0) == 3) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([msg.single_int64], ((@index0 > 0) ? @index0 : 0) == 3) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([msg.single_int64], ((@index0 > 0) ? @index0 : 0) == 3) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([msg.single_int64], ((@index0 > 0) ? @index0 : 0) == 3) + +Test case: TERNARY_BIND_RHS_ONLY +Source: false ? false : (msg.single_int64) + ((msg.single_int64 + 1) * 2) == 11 +=====> +Result: true +[CASCADED_BINDS]: cel.bind(@r0, msg.single_int64, @r0 + (@r0 + 1) * 2) == 11 +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.single_int64], @index0 + (@index0 + 1) * 2 == 11) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.single_int64, @index0 + 1, @index1 * 2, @index0 + @index2], @index3 == 11) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.single_int64, (@index0 + 1) * 2], @index0 + @index1 == 11) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.single_int64, @index0 + (@index0 + 1) * 2], @index1 == 11) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.single_int64], @index0 + (@index0 + 1) * 2 == 11) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.single_int64], @index0 + (@index0 + 1) * 2 == 11) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.single_int64], @index0 + (@index0 + 1) * 2 == 11) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([msg.single_int64], @index0 + (@index0 + 1) * 2 == 11) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([msg.single_int64], @index0 + (@index0 + 1) * 2 == 11) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([msg.single_int64], @index0 + (@index0 + 1) * 2 == 11) + +Test case: NESTED_TERNARY +Source: (msg.single_int64 > 0 ? (msg.single_int32 > 0 ? msg.single_int64 + msg.single_int32 : 0) : 0) == 8 +=====> +Result: true +[CASCADED_BINDS]: cel.bind(@r0, msg.single_int64, (@r0 > 0) ? cel.bind(@r1, msg.single_int32, (@r1 > 0) ? (@r0 + @r1) : 0) : 0) == 8 +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.single_int64, msg.single_int32], ((@index0 > 0) ? ((@index1 > 0) ? (@index0 + @index1) : 0) : 0) == 8) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.single_int64, msg.single_int32, @index0 > 0, @index1 > 0, @index0 + @index1, @index3 ? @index4 : 0, @index2 ? @index5 : 0], @index6 == 8) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.single_int64, msg.single_int32, (@index1 > 0) ? (@index0 + @index1) : 0, (@index0 > 0) ? @index2 : 0], @index3 == 8) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.single_int64, msg.single_int32, (@index0 > 0) ? ((@index1 > 0) ? (@index0 + @index1) : 0) : 0], @index2 == 8) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.single_int64, msg.single_int32], ((@index0 > 0) ? ((@index1 > 0) ? (@index0 + @index1) : 0) : 0) == 8) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.single_int64, msg.single_int32], ((@index0 > 0) ? ((@index1 > 0) ? (@index0 + @index1) : 0) : 0) == 8) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.single_int64, msg.single_int32], ((@index0 > 0) ? ((@index1 > 0) ? (@index0 + @index1) : 0) : 0) == 8) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([msg.single_int64, msg.single_int32], ((@index0 > 0) ? ((@index1 > 0) ? (@index0 + @index1) : 0) : 0) == 8) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([msg.single_int64, msg.single_int32], ((@index0 > 0) ? ((@index1 > 0) ? (@index0 + @index1) : 0) : 0) == 8) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([msg.single_int64, msg.single_int32], ((@index0 > 0) ? ((@index1 > 0) ? (@index0 + @index1) : 0) : 0) == 8) + +Test case: MULTIPLE_MACROS_1 +Source: size([[1].exists(i, i > 0)]) + size([[1].exists(j, j > 0)]) + size([[2].exists(k, k > 1)]) + size([[2].exists(l, l > 1)]) == 4 +=====> +Result: true +[CASCADED_BINDS]: true +[BLOCK_COMMON_SUBEXPR_ONLY]: true +[BLOCK_RECURSION_DEPTH_1]: true +[BLOCK_RECURSION_DEPTH_2]: true +[BLOCK_RECURSION_DEPTH_3]: true +[BLOCK_RECURSION_DEPTH_4]: true +[BLOCK_RECURSION_DEPTH_5]: true +[BLOCK_RECURSION_DEPTH_6]: true +[BLOCK_RECURSION_DEPTH_7]: true +[BLOCK_RECURSION_DEPTH_8]: true +[BLOCK_RECURSION_DEPTH_9]: true + +Test case: MULTIPLE_MACROS_2 +Source: [[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == 'a')] + [['a'].exists(l, l == 'a')] == [true, true, true, true] +=====> +Result: true +[CASCADED_BINDS]: true +[BLOCK_COMMON_SUBEXPR_ONLY]: true +[BLOCK_RECURSION_DEPTH_1]: true +[BLOCK_RECURSION_DEPTH_2]: true +[BLOCK_RECURSION_DEPTH_3]: true +[BLOCK_RECURSION_DEPTH_4]: true +[BLOCK_RECURSION_DEPTH_5]: true +[BLOCK_RECURSION_DEPTH_6]: true +[BLOCK_RECURSION_DEPTH_7]: true +[BLOCK_RECURSION_DEPTH_8]: true +[BLOCK_RECURSION_DEPTH_9]: true + +Test case: NESTED_MACROS +Source: [1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [[2, 3, 4], [2, 3, 4], [2, 3, 4]] +=====> +Result: true +[CASCADED_BINDS]: true +[BLOCK_COMMON_SUBEXPR_ONLY]: true +[BLOCK_RECURSION_DEPTH_1]: true +[BLOCK_RECURSION_DEPTH_2]: true +[BLOCK_RECURSION_DEPTH_3]: true +[BLOCK_RECURSION_DEPTH_4]: true +[BLOCK_RECURSION_DEPTH_5]: true +[BLOCK_RECURSION_DEPTH_6]: true +[BLOCK_RECURSION_DEPTH_7]: true +[BLOCK_RECURSION_DEPTH_8]: true +[BLOCK_RECURSION_DEPTH_9]: true + +Test case: NESTED_MACROS_2 +Source: [1, 2].map(y, [1, 2, 3].filter(x, x == y)) == [[1], [2]] +=====> +Result: true +[CASCADED_BINDS]: true +[BLOCK_COMMON_SUBEXPR_ONLY]: true +[BLOCK_RECURSION_DEPTH_1]: true +[BLOCK_RECURSION_DEPTH_2]: true +[BLOCK_RECURSION_DEPTH_3]: true +[BLOCK_RECURSION_DEPTH_4]: true +[BLOCK_RECURSION_DEPTH_5]: true +[BLOCK_RECURSION_DEPTH_6]: true +[BLOCK_RECURSION_DEPTH_7]: true +[BLOCK_RECURSION_DEPTH_8]: true +[BLOCK_RECURSION_DEPTH_9]: true + +Test case: INCLUSION_LIST +Source: 1 in [1,2,3] && 2 in [1,2,3] && 3 in [3, [1,2,3]] && 1 in [1,2,3] +=====> +Result: true +[CASCADED_BINDS]: true +[BLOCK_COMMON_SUBEXPR_ONLY]: true +[BLOCK_RECURSION_DEPTH_1]: true +[BLOCK_RECURSION_DEPTH_2]: true +[BLOCK_RECURSION_DEPTH_3]: true +[BLOCK_RECURSION_DEPTH_4]: true +[BLOCK_RECURSION_DEPTH_5]: true +[BLOCK_RECURSION_DEPTH_6]: true +[BLOCK_RECURSION_DEPTH_7]: true +[BLOCK_RECURSION_DEPTH_8]: true +[BLOCK_RECURSION_DEPTH_9]: true + +Test case: INCLUSION_MAP +Source: 2 in {'a': 1, 2: {true: false}, 3: {true: false}} +=====> +Result: true +[CASCADED_BINDS]: true +[BLOCK_COMMON_SUBEXPR_ONLY]: true +[BLOCK_RECURSION_DEPTH_1]: true +[BLOCK_RECURSION_DEPTH_2]: true +[BLOCK_RECURSION_DEPTH_3]: true +[BLOCK_RECURSION_DEPTH_4]: true +[BLOCK_RECURSION_DEPTH_5]: true +[BLOCK_RECURSION_DEPTH_6]: true +[BLOCK_RECURSION_DEPTH_7]: true +[BLOCK_RECURSION_DEPTH_8]: true +[BLOCK_RECURSION_DEPTH_9]: true + +Test case: MACRO_ITER_VAR_NOT_REFERENCED +Source: [1,2].map(i, [1, 2].map(i, [3,4])) == [[[3, 4], [3, 4]], [[3, 4], [3, 4]]] +=====> +Result: true +[CASCADED_BINDS]: true +[BLOCK_COMMON_SUBEXPR_ONLY]: true +[BLOCK_RECURSION_DEPTH_1]: true +[BLOCK_RECURSION_DEPTH_2]: true +[BLOCK_RECURSION_DEPTH_3]: true +[BLOCK_RECURSION_DEPTH_4]: true +[BLOCK_RECURSION_DEPTH_5]: true +[BLOCK_RECURSION_DEPTH_6]: true +[BLOCK_RECURSION_DEPTH_7]: true +[BLOCK_RECURSION_DEPTH_8]: true +[BLOCK_RECURSION_DEPTH_9]: true + +Test case: MACRO_SHADOWED_VARIABLE +Source: [x - 1 > 3 ? x - 1 : 5].exists(x, x - 1 > 3) || x - 1 > 3 +=====> +Result: true +[CASCADED_BINDS]: cel.bind(@r0, x - 1, cel.bind(@r1, @r0 > 3, [@r1 ? @r0 : 5].exists(@c0:0, @c0:0 - 1 > 3) || @r1)) +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([x - 1, @index0 > 3], [@index1 ? @index0 : 5].exists(@c0:0, @c0:0 - 1 > 3) || @index1) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([x - 1, @index0 > 3, @index1 ? @index0 : 5, [@index2], @c0:0 - 1, @index4 > 3, @x0:0 || @index5], @index3.exists(@c0:0, @index5) || @index1) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([x - 1 > 3, @index0 ? (x - 1) : 5, @c0:0 - 1 > 3, [@index1], @x0:0 || @index2], @index3.exists(@c0:0, @index2) || @index0) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([x - 1 > 3, [@index0 ? (x - 1) : 5], @x0:0 || @c0:0 - 1 > 3, @index1.exists(@c0:0, @c0:0 - 1 > 3)], @index3 || @index0) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([x - 1 > 3, [@index0 ? (x - 1) : 5].exists(@c0:0, @c0:0 - 1 > 3)], @index1 || @index0) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([x - 1 > 3], [@index0 ? (x - 1) : 5].exists(@c0:0, @c0:0 - 1 > 3) || @index0) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([x - 1 > 3], [@index0 ? (x - 1) : 5].exists(@c0:0, @c0:0 - 1 > 3) || @index0) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([x - 1 > 3], [@index0 ? (x - 1) : 5].exists(@c0:0, @c0:0 - 1 > 3) || @index0) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([x - 1 > 3], [@index0 ? (x - 1) : 5].exists(@c0:0, @c0:0 - 1 > 3) || @index0) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([x - 1 > 3], [@index0 ? (x - 1) : 5].exists(@c0:0, @c0:0 - 1 > 3) || @index0) + +Test case: MACRO_SHADOWED_VARIABLE_2 +Source: ["foo", "bar"].map(x, [x + x, x + x]).map(x, [x + x, x + x]) +=====> +Result: [[[foofoo, foofoo, foofoo, foofoo], [foofoo, foofoo, foofoo, foofoo]], [[barbar, barbar, barbar, barbar], [barbar, barbar, barbar, barbar]]] +[CASCADED_BINDS]: [cel.bind(@r0, ["foofoo", "foofoo", "foofoo", "foofoo"], [@r0, @r0]), cel.bind(@r1, ["barbar", "barbar", "barbar", "barbar"], [@r1, @r1])] +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([["foofoo", "foofoo", "foofoo", "foofoo"], ["barbar", "barbar", "barbar", "barbar"]], [[@index0, @index0], [@index1, @index1]]) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([["foofoo", "foofoo", "foofoo", "foofoo"], ["barbar", "barbar", "barbar", "barbar"], [@index0, @index0], [@index1, @index1]], [@index2, @index3]) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([["foofoo", "foofoo", "foofoo", "foofoo"], ["barbar", "barbar", "barbar", "barbar"]], [[@index0, @index0], [@index1, @index1]]) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([["foofoo", "foofoo", "foofoo", "foofoo"], ["barbar", "barbar", "barbar", "barbar"]], [[@index0, @index0], [@index1, @index1]]) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([["foofoo", "foofoo", "foofoo", "foofoo"], ["barbar", "barbar", "barbar", "barbar"]], [[@index0, @index0], [@index1, @index1]]) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([["foofoo", "foofoo", "foofoo", "foofoo"], ["barbar", "barbar", "barbar", "barbar"]], [[@index0, @index0], [@index1, @index1]]) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([["foofoo", "foofoo", "foofoo", "foofoo"], ["barbar", "barbar", "barbar", "barbar"]], [[@index0, @index0], [@index1, @index1]]) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([["foofoo", "foofoo", "foofoo", "foofoo"], ["barbar", "barbar", "barbar", "barbar"]], [[@index0, @index0], [@index1, @index1]]) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([["foofoo", "foofoo", "foofoo", "foofoo"], ["barbar", "barbar", "barbar", "barbar"]], [[@index0, @index0], [@index1, @index1]]) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([["foofoo", "foofoo", "foofoo", "foofoo"], ["barbar", "barbar", "barbar", "barbar"]], [[@index0, @index0], [@index1, @index1]]) + +Test case: PRESENCE_TEST +Source: has({'a': true}.a) && {'a':true}['a'] +=====> +Result: true +[CASCADED_BINDS]: true +[BLOCK_COMMON_SUBEXPR_ONLY]: true +[BLOCK_RECURSION_DEPTH_1]: true +[BLOCK_RECURSION_DEPTH_2]: true +[BLOCK_RECURSION_DEPTH_3]: true +[BLOCK_RECURSION_DEPTH_4]: true +[BLOCK_RECURSION_DEPTH_5]: true +[BLOCK_RECURSION_DEPTH_6]: true +[BLOCK_RECURSION_DEPTH_7]: true +[BLOCK_RECURSION_DEPTH_8]: true +[BLOCK_RECURSION_DEPTH_9]: true + +Test case: PRESENCE_TEST_WITH_TERNARY +Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : 0) == 10 +=====> +Result: true +[CASCADED_BINDS]: cel.bind(@r0, msg.oneof_type, has(@r0.payload) ? @r0.payload.single_int64 : 0) == 10 +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.oneof_type], (has(@index0.payload) ? @index0.payload.single_int64 : 0) == 10) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64], (has(@index0.payload) ? @index2 : 0) == 10) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type, @index0.payload.single_int64, has(@index0.payload) ? @index1 : 0], @index2 == 10) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type, has(@index0.payload) ? @index0.payload.single_int64 : 0], @index1 == 10) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.oneof_type], (has(@index0.payload) ? @index0.payload.single_int64 : 0) == 10) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.oneof_type], (has(@index0.payload) ? @index0.payload.single_int64 : 0) == 10) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.oneof_type], (has(@index0.payload) ? @index0.payload.single_int64 : 0) == 10) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([msg.oneof_type], (has(@index0.payload) ? @index0.payload.single_int64 : 0) == 10) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([msg.oneof_type], (has(@index0.payload) ? @index0.payload.single_int64 : 0) == 10) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([msg.oneof_type], (has(@index0.payload) ? @index0.payload.single_int64 : 0) == 10) + +Test case: PRESENCE_TEST_WITH_TERNARY_2 +Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : msg.oneof_type.payload.single_int64 * 0) == 10 +=====> +Result: true +[CASCADED_BINDS]: cel.bind(@r0, msg.oneof_type, cel.bind(@r1, @r0.payload.single_int64, has(@r0.payload) ? @r1 : (@r1 * 0))) == 10 +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.oneof_type, @index0.payload.single_int64], (has(@index0.payload) ? @index1 : (@index1 * 0)) == 10) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, @index2 * 0], (has(@index0.payload) ? @index2 : @index3) == 10) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type.payload, @index0.single_int64, msg.oneof_type, has(@index2.payload) ? @index1 : (@index1 * 0)], @index3 == 10) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type.payload.single_int64, has(msg.oneof_type.payload) ? @index0 : (@index0 * 0)], @index1 == 10) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.oneof_type.payload.single_int64], (has(msg.oneof_type.payload) ? @index0 : (@index0 * 0)) == 10) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.oneof_type.payload.single_int64], (has(msg.oneof_type.payload) ? @index0 : (@index0 * 0)) == 10) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.oneof_type.payload.single_int64], (has(msg.oneof_type.payload) ? @index0 : (@index0 * 0)) == 10) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([msg.oneof_type.payload.single_int64], (has(msg.oneof_type.payload) ? @index0 : (@index0 * 0)) == 10) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([msg.oneof_type.payload.single_int64], (has(msg.oneof_type.payload) ? @index0 : (@index0 * 0)) == 10) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([msg.oneof_type.payload.single_int64], (has(msg.oneof_type.payload) ? @index0 : (@index0 * 0)) == 10) + +Test case: PRESENCE_TEST_WITH_TERNARY_3 +Source: (has(msg.oneof_type.payload.single_int64) ? msg.oneof_type.payload.single_int64 : msg.oneof_type.payload.single_int64 * 0) == 10 +=====> +Result: true +[CASCADED_BINDS]: cel.bind(@r0, msg.oneof_type.payload, cel.bind(@r1, @r0.single_int64, has(@r0.single_int64) ? @r1 : (@r1 * 0))) == 10 +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.oneof_type.payload, @index0.single_int64], (has(@index0.single_int64) ? @index1 : (@index1 * 0)) == 10) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, @index2 * 0], (has(@index1.single_int64) ? @index2 : @index3) == 10) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type.payload, @index0.single_int64, has(@index0.single_int64) ? @index1 : (@index1 * 0)], @index2 == 10) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type.payload.single_int64, msg.oneof_type.payload], (has(@index1.single_int64) ? @index0 : (@index0 * 0)) == 10) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.oneof_type.payload.single_int64, has(msg.oneof_type.payload.single_int64) ? @index0 : (@index0 * 0)], @index1 == 10) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.oneof_type.payload.single_int64], (has(msg.oneof_type.payload.single_int64) ? @index0 : (@index0 * 0)) == 10) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.oneof_type.payload.single_int64], (has(msg.oneof_type.payload.single_int64) ? @index0 : (@index0 * 0)) == 10) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([msg.oneof_type.payload.single_int64], (has(msg.oneof_type.payload.single_int64) ? @index0 : (@index0 * 0)) == 10) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([msg.oneof_type.payload.single_int64], (has(msg.oneof_type.payload.single_int64) ? @index0 : (@index0 * 0)) == 10) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([msg.oneof_type.payload.single_int64], (has(msg.oneof_type.payload.single_int64) ? @index0 : (@index0 * 0)) == 10) + +Test case: PRESENCE_TEST_WITH_TERNARY_NESTED +Source: (has(msg.oneof_type) && has(msg.oneof_type.payload) && has(msg.oneof_type.payload.single_int64)) ? ((has(msg.oneof_type.payload.map_string_string) && has(msg.oneof_type.payload.map_string_string.key)) ? msg.oneof_type.payload.map_string_string.key == 'A' : false) : false +=====> +Result: true +[CASCADED_BINDS]: cel.bind(@r0, msg.oneof_type, cel.bind(@r1, @r0.payload, (has(msg.oneof_type) && has(@r0.payload) && has(@r1.single_int64)) ? cel.bind(@r2, @r1.map_string_string, (has(@r1.map_string_string) && has(@r2.key)) ? (@r2.key == "A") : false) : false)) +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_string_string], (has(msg.oneof_type) && has(@index0.payload) && has(@index1.single_int64)) ? ((has(@index1.map_string_string) && has(@index2.key)) ? (@index2.key == "A") : false) : false) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_string_string, @index2.key, @index3 == "A"], (has(msg.oneof_type) && has(@index0.payload) && has(@index1.single_int64)) ? ((has(@index1.map_string_string) && has(@index2.key)) ? @index4 : false) : false) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type.payload, @index0.map_string_string, has(@index0.map_string_string) && has(@index1.key), @index1.key == "A", msg.oneof_type, has(msg.oneof_type) && has(@index4.payload), @index5 && has(@index0.single_int64)], @index6 ? (@index2 ? @index3 : false) : false) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type.payload.map_string_string, msg.oneof_type.payload, has(msg.oneof_type) && has(msg.oneof_type.payload), (has(@index1.map_string_string) && has(@index0.key)) ? (@index0.key == "A") : false], (@index2 && has(@index1.single_int64)) ? @index3 : false) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.oneof_type.payload.map_string_string, msg.oneof_type.payload, has(msg.oneof_type) && has(msg.oneof_type.payload) && has(@index1.single_int64)], @index2 ? ((has(@index1.map_string_string) && has(@index0.key)) ? (@index0.key == "A") : false) : false) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.oneof_type.payload.map_string_string, msg.oneof_type.payload], (has(msg.oneof_type) && has(msg.oneof_type.payload) && has(@index1.single_int64)) ? ((has(@index1.map_string_string) && has(@index0.key)) ? (@index0.key == "A") : false) : false) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.oneof_type.payload.map_string_string, msg.oneof_type.payload], (has(msg.oneof_type) && has(msg.oneof_type.payload) && has(@index1.single_int64)) ? ((has(@index1.map_string_string) && has(@index0.key)) ? (@index0.key == "A") : false) : false) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([msg.oneof_type.payload.map_string_string, msg.oneof_type.payload], (has(msg.oneof_type) && has(msg.oneof_type.payload) && has(@index1.single_int64)) ? ((has(@index1.map_string_string) && has(@index0.key)) ? (@index0.key == "A") : false) : false) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([msg.oneof_type.payload.map_string_string, msg.oneof_type.payload], (has(msg.oneof_type) && has(msg.oneof_type.payload) && has(@index1.single_int64)) ? ((has(@index1.map_string_string) && has(@index0.key)) ? (@index0.key == "A") : false) : false) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([msg.oneof_type.payload.map_string_string, msg.oneof_type.payload], (has(msg.oneof_type) && has(msg.oneof_type.payload) && has(@index1.single_int64)) ? ((has(@index1.map_string_string) && has(@index0.key)) ? (@index0.key == "A") : false) : false) + +Test case: OPTIONAL_LIST +Source: [10, ?optional.none(), [?optional.none(), ?opt_x], [?optional.none(), ?opt_x]] == [10, [5], [5]] +=====> +Result: true +[CASCADED_BINDS]: cel.bind(@r0, optional.none(), [10, ?@r0, [?opt_x], [?@r0, ?opt_x]]) == cel.bind(@r1, [5], [10, @r1, @r1]) +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([optional.none(), [5]], [10, ?@index0, [?opt_x], [?@index0, ?opt_x]] == [10, @index1, @index1]) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([optional.none(), [5], [?opt_x], [?@index0, ?opt_x], [10, ?@index0, @index2, @index3], [10, @index1, @index1]], @index4 == @index5) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([optional.none(), [5], [10, ?@index0, [?opt_x], [?@index0, ?opt_x]]], @index2 == [10, @index1, @index1]) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([optional.none(), [5]], [10, ?@index0, [?opt_x], [?@index0, ?opt_x]] == [10, @index1, @index1]) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([optional.none(), [5]], [10, ?@index0, [?opt_x], [?@index0, ?opt_x]] == [10, @index1, @index1]) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([optional.none(), [5]], [10, ?@index0, [?opt_x], [?@index0, ?opt_x]] == [10, @index1, @index1]) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([optional.none(), [5]], [10, ?@index0, [?opt_x], [?@index0, ?opt_x]] == [10, @index1, @index1]) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([optional.none(), [5]], [10, ?@index0, [?opt_x], [?@index0, ?opt_x]] == [10, @index1, @index1]) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([optional.none(), [5]], [10, ?@index0, [?opt_x], [?@index0, ?opt_x]] == [10, @index1, @index1]) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([optional.none(), [5]], [10, ?@index0, [?opt_x], [?@index0, ?opt_x]] == [10, @index1, @index1]) + +Test case: OPTIONAL_MAP +Source: {?'hello': optional.of('hello')}['hello'] + {?'hello': optional.of('hello')}['hello'] == 'hellohello' +=====> +Result: true +[CASCADED_BINDS]: true +[BLOCK_COMMON_SUBEXPR_ONLY]: true +[BLOCK_RECURSION_DEPTH_1]: true +[BLOCK_RECURSION_DEPTH_2]: true +[BLOCK_RECURSION_DEPTH_3]: true +[BLOCK_RECURSION_DEPTH_4]: true +[BLOCK_RECURSION_DEPTH_5]: true +[BLOCK_RECURSION_DEPTH_6]: true +[BLOCK_RECURSION_DEPTH_7]: true +[BLOCK_RECURSION_DEPTH_8]: true +[BLOCK_RECURSION_DEPTH_9]: true + +Test case: OPTIONAL_MAP_CHAINED +Source: {?'key': optional.of('test')}[?'bogus'].or({'key': 'test'}[?'bogus']).orValue({'key': 'test'}['key']) == 'test' +=====> +Result: true +[CASCADED_BINDS]: true +[BLOCK_COMMON_SUBEXPR_ONLY]: true +[BLOCK_RECURSION_DEPTH_1]: true +[BLOCK_RECURSION_DEPTH_2]: true +[BLOCK_RECURSION_DEPTH_3]: true +[BLOCK_RECURSION_DEPTH_4]: true +[BLOCK_RECURSION_DEPTH_5]: true +[BLOCK_RECURSION_DEPTH_6]: true +[BLOCK_RECURSION_DEPTH_7]: true +[BLOCK_RECURSION_DEPTH_8]: true +[BLOCK_RECURSION_DEPTH_9]: true + +Test case: OPTIONAL_MESSAGE +Source: TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}.single_int32 + TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}.single_int64 == 5 +=====> +Result: true +[CASCADED_BINDS]: true +[BLOCK_COMMON_SUBEXPR_ONLY]: true +[BLOCK_RECURSION_DEPTH_1]: true +[BLOCK_RECURSION_DEPTH_2]: true +[BLOCK_RECURSION_DEPTH_3]: true +[BLOCK_RECURSION_DEPTH_4]: true +[BLOCK_RECURSION_DEPTH_5]: true +[BLOCK_RECURSION_DEPTH_6]: true +[BLOCK_RECURSION_DEPTH_7]: true +[BLOCK_RECURSION_DEPTH_8]: true +[BLOCK_RECURSION_DEPTH_9]: true + +Test case: CALL +Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('h' + 'e' + 'l' + 'l' + 'o') +=====> +Result: true +[CASCADED_BINDS]: true +[BLOCK_COMMON_SUBEXPR_ONLY]: true +[BLOCK_RECURSION_DEPTH_1]: true +[BLOCK_RECURSION_DEPTH_2]: true +[BLOCK_RECURSION_DEPTH_3]: true +[BLOCK_RECURSION_DEPTH_4]: true +[BLOCK_RECURSION_DEPTH_5]: true +[BLOCK_RECURSION_DEPTH_6]: true +[BLOCK_RECURSION_DEPTH_7]: true +[BLOCK_RECURSION_DEPTH_8]: true +[BLOCK_RECURSION_DEPTH_9]: true + +Test case: CALL_ARGUMENT_NESTED_NO_COMMON_SUBEXPR +Source: 'hello world'.matches('h' + 'e' + 'l' + 'l' + 'o') +=====> +Result: true +[CASCADED_BINDS]: true +[BLOCK_COMMON_SUBEXPR_ONLY]: true +[BLOCK_RECURSION_DEPTH_1]: true +[BLOCK_RECURSION_DEPTH_2]: true +[BLOCK_RECURSION_DEPTH_3]: true +[BLOCK_RECURSION_DEPTH_4]: true +[BLOCK_RECURSION_DEPTH_5]: true +[BLOCK_RECURSION_DEPTH_6]: true +[BLOCK_RECURSION_DEPTH_7]: true +[BLOCK_RECURSION_DEPTH_8]: true +[BLOCK_RECURSION_DEPTH_9]: true + +Test case: CALL_TARGET_NESTED_NO_COMMON_SUBEXPR +Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('hello') +=====> +Result: true +[CASCADED_BINDS]: true +[BLOCK_COMMON_SUBEXPR_ONLY]: true +[BLOCK_RECURSION_DEPTH_1]: true +[BLOCK_RECURSION_DEPTH_2]: true +[BLOCK_RECURSION_DEPTH_3]: true +[BLOCK_RECURSION_DEPTH_4]: true +[BLOCK_RECURSION_DEPTH_5]: true +[BLOCK_RECURSION_DEPTH_6]: true +[BLOCK_RECURSION_DEPTH_7]: true +[BLOCK_RECURSION_DEPTH_8]: true +[BLOCK_RECURSION_DEPTH_9]: true + +Test case: CALL_BOTH_ARGUMENT_TARGET_NESTED_NO_COMMON_SUBEXPR +Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('w' + 'o' + 'r' + 'l' + 'd') +=====> +Result: true +[CASCADED_BINDS]: true +[BLOCK_COMMON_SUBEXPR_ONLY]: true +[BLOCK_RECURSION_DEPTH_1]: true +[BLOCK_RECURSION_DEPTH_2]: true +[BLOCK_RECURSION_DEPTH_3]: true +[BLOCK_RECURSION_DEPTH_4]: true +[BLOCK_RECURSION_DEPTH_5]: true +[BLOCK_RECURSION_DEPTH_6]: true +[BLOCK_RECURSION_DEPTH_7]: true +[BLOCK_RECURSION_DEPTH_8]: true +[BLOCK_RECURSION_DEPTH_9]: true + +Test case: CUSTOM_FUNCTION_INELIMINABLE +Source: non_pure_custom_func(msg.oneof_type.payload.single_int64) + non_pure_custom_func(msg.oneof_type.payload.single_int32) + non_pure_custom_func(msg.oneof_type.payload.single_int64) + non_pure_custom_func(msg.single_int64) +=====> +Result: 31 +[CASCADED_BINDS]: cel.bind(@r0, msg.oneof_type.payload, cel.bind(@r1, @r0.single_int64, non_pure_custom_func(@r1) + non_pure_custom_func(@r0.single_int32) + non_pure_custom_func(@r1))) + non_pure_custom_func(msg.single_int64) +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.oneof_type.payload, @index0.single_int64], non_pure_custom_func(@index1) + non_pure_custom_func(@index0.single_int32) + non_pure_custom_func(@index1) + non_pure_custom_func(msg.single_int64)) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64], non_pure_custom_func(@index2) + non_pure_custom_func(@index1.single_int32) + non_pure_custom_func(@index2) + non_pure_custom_func(msg.single_int64)) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type.payload, @index0.single_int64], non_pure_custom_func(@index1) + non_pure_custom_func(@index0.single_int32) + non_pure_custom_func(@index1) + non_pure_custom_func(msg.single_int64)) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type.payload.single_int64], non_pure_custom_func(@index0) + non_pure_custom_func(msg.oneof_type.payload.single_int32) + non_pure_custom_func(@index0) + non_pure_custom_func(msg.single_int64)) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.oneof_type.payload.single_int64], non_pure_custom_func(@index0) + non_pure_custom_func(msg.oneof_type.payload.single_int32) + non_pure_custom_func(@index0) + non_pure_custom_func(msg.single_int64)) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.oneof_type.payload.single_int64], non_pure_custom_func(@index0) + non_pure_custom_func(msg.oneof_type.payload.single_int32) + non_pure_custom_func(@index0) + non_pure_custom_func(msg.single_int64)) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.oneof_type.payload.single_int64], non_pure_custom_func(@index0) + non_pure_custom_func(msg.oneof_type.payload.single_int32) + non_pure_custom_func(@index0) + non_pure_custom_func(msg.single_int64)) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([msg.oneof_type.payload.single_int64], non_pure_custom_func(@index0) + non_pure_custom_func(msg.oneof_type.payload.single_int32) + non_pure_custom_func(@index0) + non_pure_custom_func(msg.single_int64)) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([msg.oneof_type.payload.single_int64], non_pure_custom_func(@index0) + non_pure_custom_func(msg.oneof_type.payload.single_int32) + non_pure_custom_func(@index0) + non_pure_custom_func(msg.single_int64)) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([msg.oneof_type.payload.single_int64], non_pure_custom_func(@index0) + non_pure_custom_func(msg.oneof_type.payload.single_int32) + non_pure_custom_func(@index0) + non_pure_custom_func(msg.single_int64)) + +Test case: CUSTOM_FUNCTION_ELIMINABLE +Source: pure_custom_func(msg.oneof_type.payload.single_int64) + pure_custom_func(msg.oneof_type.payload.single_int32) + pure_custom_func(msg.oneof_type.payload.single_int64) + pure_custom_func(msg.single_int64) +=====> +Result: 31 +[CASCADED_BINDS]: cel.bind(@r0, msg.oneof_type.payload, cel.bind(@r1, pure_custom_func(@r0.single_int64), @r1 + pure_custom_func(@r0.single_int32) + @r1)) + pure_custom_func(msg.single_int64) +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.oneof_type.payload, pure_custom_func(@index0.single_int64)], @index1 + pure_custom_func(@index0.single_int32) + @index1 + pure_custom_func(msg.single_int64)) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, pure_custom_func(@index2), @index1.single_int32, pure_custom_func(@index4), @index3 + @index5, @index6 + @index3, msg.single_int64, pure_custom_func(@index8)], @index7 + @index9) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type.payload, pure_custom_func(@index0.single_int64), pure_custom_func(@index0.single_int32), @index1 + @index2 + @index1, pure_custom_func(msg.single_int64)], @index3 + @index4) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type.payload.single_int64, pure_custom_func(@index0), msg.oneof_type.payload.single_int32, @index1 + pure_custom_func(@index2) + @index1], @index3 + pure_custom_func(msg.single_int64)) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([pure_custom_func(msg.oneof_type.payload.single_int64), pure_custom_func(msg.oneof_type.payload.single_int32)], @index0 + @index1 + @index0 + pure_custom_func(msg.single_int64)) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([pure_custom_func(msg.oneof_type.payload.single_int64), @index0 + pure_custom_func(msg.oneof_type.payload.single_int32)], @index1 + @index0 + pure_custom_func(msg.single_int64)) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([pure_custom_func(msg.oneof_type.payload.single_int64), @index0 + pure_custom_func(msg.oneof_type.payload.single_int32) + @index0], @index1 + pure_custom_func(msg.single_int64)) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([pure_custom_func(msg.oneof_type.payload.single_int64)], @index0 + pure_custom_func(msg.oneof_type.payload.single_int32) + @index0 + pure_custom_func(msg.single_int64)) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([pure_custom_func(msg.oneof_type.payload.single_int64)], @index0 + pure_custom_func(msg.oneof_type.payload.single_int32) + @index0 + pure_custom_func(msg.single_int64)) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([pure_custom_func(msg.oneof_type.payload.single_int64)], @index0 + pure_custom_func(msg.oneof_type.payload.single_int32) + @index0 + pure_custom_func(msg.single_int64)) From 4aabfd07cfad9001a7c196319bd5da178f390c30 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Tue, 5 Mar 2024 14:56:22 -0800 Subject: [PATCH 054/486] Allow mutation of AST containing expanded macro that does not exist in macro_call map PiperOrigin-RevId: 612979566 --- .../main/java/dev/cel/common/ast/CelExpr.java | 7 ++ .../java/dev/cel/optimizer/MutableAst.java | 87 +++++++++++++++++-- .../dev/cel/optimizer/MutableAstTest.java | 42 +++++++++ .../resources/subexpression_unparsed.baseline | 18 ++-- 4 files changed, 139 insertions(+), 15 deletions(-) diff --git a/common/src/main/java/dev/cel/common/ast/CelExpr.java b/common/src/main/java/dev/cel/common/ast/CelExpr.java index c4e53906a..3aa3037b5 100644 --- a/common/src/main/java/dev/cel/common/ast/CelExpr.java +++ b/common/src/main/java/dev/cel/common/ast/CelExpr.java @@ -525,6 +525,13 @@ public ImmutableList getArgsBuilders() { return mutableArgs.stream().map(CelExpr::toBuilder).collect(toImmutableList()); } + @CanIgnoreReturnValue + public Builder clearArgs() { + mutableArgs.clear(); + return this; + } + + @CanIgnoreReturnValue public Builder setArg(int index, CelExpr arg) { checkNotNull(arg); mutableArgs.set(index, arg); diff --git a/optimizer/src/main/java/dev/cel/optimizer/MutableAst.java b/optimizer/src/main/java/dev/cel/optimizer/MutableAst.java index bf813eef4..225f7a385 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/MutableAst.java +++ b/optimizer/src/main/java/dev/cel/optimizer/MutableAst.java @@ -645,16 +645,18 @@ private CelSource normalizeMacroSource( })); // Update the macro call IDs and their call references - for (Entry macroCall : celSource.getMacroCalls().entrySet()) { - long macroId = macroCall.getKey(); + for (Entry existingMacroCall : celSource.getMacroCalls().entrySet()) { + long macroId = existingMacroCall.getKey(); long callId = idGenerator.generate(macroId); if (!allExprs.containsKey(callId)) { continue; } - CelExpr.Builder newCall = renumberExprIds(idGenerator, macroCall.getValue().toBuilder()); - CelNavigableExpr callNav = CelNavigableExpr.fromExpr(newCall.build()); + CelExpr.Builder newMacroCallExpr = + renumberExprIds(idGenerator, existingMacroCall.getValue().toBuilder()); + + CelNavigableExpr callNav = CelNavigableExpr.fromExpr(newMacroCallExpr.build()); ImmutableList callDescendants = callNav.descendants().map(CelNavigableExpr::expr).collect(toImmutableList()); @@ -665,10 +667,24 @@ private CelSource normalizeMacroSource( CelExpr mutatedExpr = allExprs.get(callChild.id()); if (!callChild.equals(mutatedExpr)) { - newCall = mutateExpr((arg) -> arg, newCall, mutatedExpr.toBuilder(), callChild.id()); + newMacroCallExpr = + mutateExpr( + NO_OP_ID_GENERATOR, newMacroCallExpr, mutatedExpr.toBuilder(), callChild.id()); + } + } + + if (exprIdToReplace > 0) { + long replacedId = idGenerator.generate(exprIdToReplace); + boolean isListExprBeingReplaced = + allExprs.containsKey(replacedId) + && allExprs.get(replacedId).exprKind().getKind().equals(Kind.CREATE_LIST); + if (isListExprBeingReplaced) { + unwrapListArgumentsInMacroCallExpr( + allExprs.get(callId).comprehension(), newMacroCallExpr); } } - sourceBuilder.addMacroCalls(callId, newCall.build()); + + sourceBuilder.addMacroCalls(callId, newMacroCallExpr.build()); } // Replace comprehension nodes with a NOT_SET reference to reduce AST size. @@ -688,11 +704,70 @@ private CelSource normalizeMacroSource( node.id()); macroCall.setValue(mutatedNode.build()); }); + + // Prune any NOT_SET (comprehension) nodes that no longer exist in the main AST + // This can occur from pulling out a nested comprehension into a separate cel.block index + CelNavigableExpr.fromExpr(macroCallExpr) + .allNodes() + .filter(node -> node.getKind().equals(Kind.NOT_SET)) + .map(CelNavigableExpr::id) + .filter(id -> !allExprs.containsKey(id)) + .forEach( + id -> { + ImmutableList newCallArgs = + macroCallExpr.call().args().stream() + .filter(node -> node.id() != id) + .collect(toImmutableList()); + CelCall.Builder call = + macroCallExpr.call().toBuilder().clearArgs().addArgs(newCallArgs); + + macroCall.setValue(macroCallExpr.toBuilder().setCall(call.build()).build()); + }); } return sourceBuilder.build(); } + /** + * Unwraps the arguments in the extraneous list_expr which is present in the AST but does not + * exist in the macro call map. `map`, `filter` are examples of such. + * + *

This method inspects the comprehension's accumulator initializer to infer that the list_expr + * solely exists to match the expected result type of the macro call signature. + * + * @param comprehension Comprehension in the main AST to extract the macro call arguments from + * (loop step). + * @param newMacroCallExpr (Output parameter) Modified macro call expression with the call + * arguments unwrapped. + */ + private static void unwrapListArgumentsInMacroCallExpr( + CelComprehension comprehension, CelExpr.Builder newMacroCallExpr) { + CelExpr accuInit = comprehension.accuInit(); + if (!accuInit.exprKind().getKind().equals(Kind.CREATE_LIST) + || !accuInit.createList().elements().isEmpty()) { + // Does not contain an extraneous list. + return; + } + + CelExpr loopStepExpr = comprehension.loopStep(); + ImmutableList args = loopStepExpr.call().args(); + if (args.size() != 2) { + throw new IllegalArgumentException( + String.format( + "Expected exactly 2 arguments but got %d instead on expr id: %d", + args.size(), loopStepExpr.id())); + } + + CelCall newMacroCall = newMacroCallExpr.call(); + newMacroCallExpr.setCall( + newMacroCallExpr.call().toBuilder() + .clearArgs() + .addArgs( + newMacroCall.args().get(0)) // iter_var is first argument of the call by convention + .addArgs(args.get(1).createList().elements()) + .build()); + } + private CelExpr.Builder mutateExpr( ExprIdGenerator idGenerator, CelExpr.Builder root, diff --git a/optimizer/src/test/java/dev/cel/optimizer/MutableAstTest.java b/optimizer/src/test/java/dev/cel/optimizer/MutableAstTest.java index af0e1241e..25cc48f9f 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/MutableAstTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/MutableAstTest.java @@ -18,6 +18,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertThrows; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.testing.junit.testparameterinjector.TestParameterInjector; import com.google.testing.junit.testparameterinjector.TestParameters; @@ -47,6 +48,7 @@ import dev.cel.parser.CelUnparserFactory; import dev.cel.parser.Operator; import dev.cel.testing.testdata.proto3.TestAllTypesProto.TestAllTypes; +import java.util.List; import org.junit.Test; import org.junit.runner.RunWith; @@ -439,6 +441,46 @@ public void replaceSubtree_macroReplacedWithConstExpr_macroCallCleared() throws assertThat(CEL.createProgram(CEL.check(mutatedAst).getAst()).eval()).isEqualTo(1); } + @Test + @SuppressWarnings("unchecked") // Test only + public void replaceSubtree_replaceExtraneousListCreatedByMacro_unparseSuccess() throws Exception { + // Certain macros such as `map` or `filter` generates an extraneous list_expr in the loop step's + // argument that does not exist in the original expression. + // For example, the loop step of this expression looks like: + // CALL [10] { + // function: _+_ + // args: { + // IDENT [8] { + // name: __result__ + // } + // CREATE_LIST [9] { + // elements: { + // CONSTANT [5] { value: 1 } + // } + // } + // } + // } + CelAbstractSyntaxTree ast = CEL.compile("[1].map(x, 1)").getAst(); + + // These two mutation are equivalent. + CelAbstractSyntaxTree mutatedAstWithList = + MUTABLE_AST.replaceSubtree( + ast, + CelExpr.ofCreateListExpr( + 0, + ImmutableList.of(CelExpr.newBuilder().setConstant(CelConstant.ofValue(2L)).build()), + ImmutableList.of()), + 9L); + CelAbstractSyntaxTree mutatedAstWithConstant = + MUTABLE_AST.replaceSubtree( + ast, CelExpr.newBuilder().setConstant(CelConstant.ofValue(2L)).build(), 5L); + + assertThat(CEL_UNPARSER.unparse(mutatedAstWithList)).isEqualTo("[1].map(x, 2)"); + assertThat(CEL_UNPARSER.unparse(mutatedAstWithConstant)).isEqualTo("[1].map(x, 2)"); + assertThat((List) CEL.createProgram(CEL.check(mutatedAstWithList).getAst()).eval()) + .containsExactly(2L); + } + @Test public void globalCallExpr_replaceRoot() throws Exception { // Tree shape (brackets are expr IDs): diff --git a/optimizer/src/test/resources/subexpression_unparsed.baseline b/optimizer/src/test/resources/subexpression_unparsed.baseline index 28d55996b..83a434ac4 100644 --- a/optimizer/src/test/resources/subexpression_unparsed.baseline +++ b/optimizer/src/test/resources/subexpression_unparsed.baseline @@ -310,10 +310,10 @@ Result: true [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([[1, 2, 3], [2, 3, 4]], @index0.map(@c0:0, @index0.map(@c1:0, @c1:0 + 1)) == [@index1, @index1, @index1]) [BLOCK_RECURSION_DEPTH_1]: cel.@block([[1, 2, 3], [2, 3, 4], @c1:0 + 1, [@index2], @x1:0 + @index3, [@index1, @index1, @index1]], @index0.map(@c0:0, @index0.map(@c1:0, @index2)) == @index5) [BLOCK_RECURSION_DEPTH_2]: cel.@block([[1, 2, 3], [2, 3, 4], [@c1:0 + 1], @index0.map(@c1:0, @c1:0 + 1), @x0:0 + [@index3], @index0.map(@c0:0, @index3)], @index5 == [@index1, @index1, @index1]) -[BLOCK_RECURSION_DEPTH_3]: Unparse Error: java.lang.IllegalArgumentException: unexpected expr kind: NOT_SET +[BLOCK_RECURSION_DEPTH_3]: cel.@block([[1, 2, 3], [2, 3, 4], @x1:0 + [@c1:0 + 1], [@index0.map(@c1:0, @c1:0 + 1)]], @index0.map(@c0:0) == [@index1, @index1, @index1]) [BLOCK_RECURSION_DEPTH_4]: cel.@block([[1, 2, 3], [2, 3, 4], @index0.map(@c1:0, @c1:0 + 1)], @index0.map(@c0:0, @index2) == [@index1, @index1, @index1]) -[BLOCK_RECURSION_DEPTH_5]: Unparse Error: java.lang.IllegalArgumentException: unexpected expr kind: NOT_SET -[BLOCK_RECURSION_DEPTH_6]: Unparse Error: java.lang.IllegalArgumentException: unexpected expr kind: NOT_SET +[BLOCK_RECURSION_DEPTH_5]: cel.@block([[1, 2, 3], [2, 3, 4], [@index0.map(@c1:0, @c1:0 + 1)]], @index0.map(@c0:0) == [@index1, @index1, @index1]) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([[1, 2, 3], [2, 3, 4], @x0:0 + [@index0.map(@c1:0, @c1:0 + 1)]], @index0.map(@c0:0) == [@index1, @index1, @index1]) [BLOCK_RECURSION_DEPTH_7]: cel.@block([[1, 2, 3], [2, 3, 4], @index0.map(@c0:0, @index0.map(@c1:0, @c1:0 + 1))], @index2 == [@index1, @index1, @index1]) [BLOCK_RECURSION_DEPTH_8]: cel.@block([[1, 2, 3], [2, 3, 4]], @index0.map(@c0:0, @index0.map(@c1:0, @c1:0 + 1)) == [@index1, @index1, @index1]) [BLOCK_RECURSION_DEPTH_9]: cel.@block([[1, 2, 3], [2, 3, 4]], @index0.map(@c0:0, @index0.map(@c1:0, @c1:0 + 1)) == [@index1, @index1, @index1]) @@ -326,10 +326,10 @@ Result: true [BLOCK_COMMON_SUBEXPR_ONLY]: [1, 2].map(@c0:0, [1, 2, 3].filter(@c1:0, @c1:0 == @c0:0)) == [[1], [2]] [BLOCK_RECURSION_DEPTH_1]: cel.@block([[1, 2], [1, 2, 3], @c1:0 == @c0:0, [@c1:0], @x1:0 + @index3, @index2 ? @index4 : @x1:0, [1], [2], [@index6, @index7]], @index0.map(@c0:0, @index1.filter(@c1:0, @index2)) == @index8) [BLOCK_RECURSION_DEPTH_2]: cel.@block([@x1:0 + [@c1:0], (@c1:0 == @c0:0) ? @index0 : @x1:0, [1, 2, 3].filter(@c1:0, @c1:0 == @c0:0), @x0:0 + [@index2], [1, 2].map(@c0:0, @index2), [[1], [2]]], @index4 == @index5) -[BLOCK_RECURSION_DEPTH_3]: Unparse Error: java.lang.IllegalArgumentException: unexpected expr kind: NOT_SET +[BLOCK_RECURSION_DEPTH_3]: cel.@block([(@c1:0 == @c0:0) ? (@x1:0 + [@c1:0]) : @x1:0, [[1, 2, 3].filter(@c1:0, @c1:0 == @c0:0)]], [1, 2].map(@c0:0) == [[1], [2]]) [BLOCK_RECURSION_DEPTH_4]: cel.@block([[1, 2, 3].filter(@c1:0, @c1:0 == @c0:0)], [1, 2].map(@c0:0, @index0) == [[1], [2]]) -[BLOCK_RECURSION_DEPTH_5]: Unparse Error: java.lang.IllegalArgumentException: unexpected expr kind: NOT_SET -[BLOCK_RECURSION_DEPTH_6]: Unparse Error: java.lang.IllegalArgumentException: unexpected expr kind: NOT_SET +[BLOCK_RECURSION_DEPTH_5]: cel.@block([[[1, 2, 3].filter(@c1:0, @c1:0 == @c0:0)]], [1, 2].map(@c0:0) == [[1], [2]]) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([@x0:0 + [[1, 2, 3].filter(@c1:0, @c1:0 == @c0:0)]], [1, 2].map(@c0:0) == [[1], [2]]) [BLOCK_RECURSION_DEPTH_7]: cel.@block([[1, 2].map(@c0:0, [1, 2, 3].filter(@c1:0, @c1:0 == @c0:0))], @index0 == [[1], [2]]) [BLOCK_RECURSION_DEPTH_8]: [1, 2].map(@c0:0, [1, 2, 3].filter(@c1:0, @c1:0 == @c0:0)) == [[1], [2]] [BLOCK_RECURSION_DEPTH_9]: [1, 2].map(@c0:0, [1, 2, 3].filter(@c1:0, @c1:0 == @c0:0)) == [[1], [2]] @@ -374,10 +374,10 @@ Result: true [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([[1, 2], [3, 4], [@index1, @index1]], @index0.map(@c0:0, @index0.map(@c1:0, @index1)) == [@index2, @index2]) [BLOCK_RECURSION_DEPTH_1]: cel.@block([[1, 2], [3, 4], [@index1, @index1], [@index1], @x1:0 + @index3, [@index2, @index2]], @index0.map(@c0:0, @index0.map(@c1:0, @index1)) == @index5) [BLOCK_RECURSION_DEPTH_2]: cel.@block([[[3, 4], [3, 4]], [1, 2], [[3, 4]], @index1.map(@c1:0, [3, 4]), @x0:0 + [@index3], @index1.map(@c0:0, @index3)], @index5 == [@index0, @index0]) -[BLOCK_RECURSION_DEPTH_3]: Unparse Error: java.lang.IllegalArgumentException: unexpected expr kind: NOT_SET +[BLOCK_RECURSION_DEPTH_3]: cel.@block([[[3, 4], [3, 4]], [1, 2], @x1:0 + [[3, 4]], [@index1.map(@c1:0, [3, 4])]], @index1.map(@c0:0) == [@index0, @index0]) [BLOCK_RECURSION_DEPTH_4]: cel.@block([[[3, 4], [3, 4]], [1, 2], @index1.map(@c1:0, [3, 4])], @index1.map(@c0:0, @index2) == [@index0, @index0]) -[BLOCK_RECURSION_DEPTH_5]: Unparse Error: java.lang.IllegalArgumentException: unexpected expr kind: NOT_SET -[BLOCK_RECURSION_DEPTH_6]: Unparse Error: java.lang.IllegalArgumentException: unexpected expr kind: NOT_SET +[BLOCK_RECURSION_DEPTH_5]: cel.@block([[[3, 4], [3, 4]], [1, 2], [@index1.map(@c1:0, [3, 4])]], @index1.map(@c0:0) == [@index0, @index0]) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([[[3, 4], [3, 4]], [1, 2], @x0:0 + [@index1.map(@c1:0, [3, 4])]], @index1.map(@c0:0) == [@index0, @index0]) [BLOCK_RECURSION_DEPTH_7]: cel.@block([[[3, 4], [3, 4]], [1, 2], @index1.map(@c0:0, @index1.map(@c1:0, [3, 4]))], @index2 == [@index0, @index0]) [BLOCK_RECURSION_DEPTH_8]: cel.@block([[[3, 4], [3, 4]], [1, 2]], @index1.map(@c0:0, @index1.map(@c1:0, [3, 4])) == [@index0, @index0]) [BLOCK_RECURSION_DEPTH_9]: cel.@block([[[3, 4], [3, 4]], [1, 2]], @index1.map(@c0:0, @index1.map(@c1:0, [3, 4])) == [@index0, @index0]) From af32065d267ce61363a7cc384e368ea5dd09bbbd Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Tue, 5 Mar 2024 17:12:36 -0800 Subject: [PATCH 055/486] Internal Changes PiperOrigin-RevId: 613020157 --- optimizer/optimizers/BUILD.bazel | 1 - 1 file changed, 1 deletion(-) diff --git a/optimizer/optimizers/BUILD.bazel b/optimizer/optimizers/BUILD.bazel index e39612db2..5debf13bc 100644 --- a/optimizer/optimizers/BUILD.bazel +++ b/optimizer/optimizers/BUILD.bazel @@ -10,6 +10,5 @@ java_library( java_library( name = "common_subexpression_elimination", - visibility = ["//visibility:public"], # TODO: Expose when ready exports = ["//optimizer/src/main/java/dev/cel/optimizer/optimizers:common_subexpression_elimination"], ) From 366e7496667dd5583db70c05b356c7c58e3a5c4b Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Wed, 6 Mar 2024 10:34:16 -0800 Subject: [PATCH 056/486] Optimize parsing a large string literal by avoiding making substring copies PiperOrigin-RevId: 613266460 --- .../main/java/dev/cel/common/internal/Constants.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/common/src/main/java/dev/cel/common/internal/Constants.java b/common/src/main/java/dev/cel/common/internal/Constants.java index f699639d4..0367d879a 100644 --- a/common/src/main/java/dev/cel/common/internal/Constants.java +++ b/common/src/main/java/dev/cel/common/internal/Constants.java @@ -497,7 +497,15 @@ private static void checkForClosingQuote(String text, String quote) throws Parse while (position + quote.length() <= text.length()) { char codeUnit = text.charAt(position); if (codeUnit != '\\') { - if (text.substring(position).startsWith(quote)) { + boolean quoteMatches = true; + for (int i = 0; i < quote.length(); i++) { + if (text.charAt(position + i) != quote.charAt(i)) { + quoteMatches = false; + break; + } + } + + if (quoteMatches) { isClosed = position + quote.length() == text.length(); break; } From bb64ec74a90ba4ef9a7fb82fa6e399a15be26635 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Wed, 6 Mar 2024 11:02:30 -0800 Subject: [PATCH 057/486] Add an option for controlling short-circuiting behavior for logical operators. PiperOrigin-RevId: 613276249 --- .../main/java/dev/cel/common/CelOptions.java | 14 ++ .../dev/cel/runtime/DefaultInterpreter.java | 47 ++++-- .../java/dev/cel/runtime/CelRuntimeTest.java | 141 +++++++++++++++++- 3 files changed, 190 insertions(+), 12 deletions(-) diff --git a/common/src/main/java/dev/cel/common/CelOptions.java b/common/src/main/java/dev/cel/common/CelOptions.java index eaa812e2b..f421bee68 100644 --- a/common/src/main/java/dev/cel/common/CelOptions.java +++ b/common/src/main/java/dev/cel/common/CelOptions.java @@ -71,6 +71,8 @@ public abstract class CelOptions { public abstract boolean disableCelStandardEquality(); + public abstract boolean enableShortCircuiting(); + public abstract boolean enableRegexPartialMatch(); public abstract boolean enableUnsignedComparisonAndArithmeticIsUnsigned(); @@ -170,6 +172,7 @@ public static Builder newBuilder() { .enableNamespacedDeclarations(true) // Evaluation options .disableCelStandardEquality(true) + .enableShortCircuiting(true) .enableRegexPartialMatch(false) .enableUnsignedComparisonAndArithmeticIsUnsigned(false) .enableUnsignedLongs(false) @@ -364,6 +367,17 @@ public abstract static class Builder { */ public abstract Builder disableCelStandardEquality(boolean value); + /** + * Enable short-circuiting of the logical operator evaluation. If enabled, AND, OR, and TERNARY + * do not evaluate the entire expression once the resulting value is known from the left-hand + * side. + * + *

This option is enabled by default. In most cases, this should not be disabled except for + * debugging purposes or collecting results for all evaluated branches through {@link + * dev.cel.runtime.CelEvaluationListener}. + */ + public abstract Builder enableShortCircuiting(boolean value); + /** * Treat regex {@code matches} calls as substring (unanchored) match patterns. * diff --git a/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java b/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java index bf6af55ee..cd7c25fb3 100644 --- a/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java +++ b/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java @@ -455,13 +455,22 @@ private Optional maybeContainerIndexAttribute( private IntermediateResult evalConditional(ExecutionFrame frame, CelCall callExpr) throws InterpreterException { IntermediateResult condition = evalBooleanStrict(frame, callExpr.args().get(0)); - if (isUnknownValue(condition.value())) { - return condition; - } - if ((boolean) condition.value()) { - return evalInternal(frame, callExpr.args().get(1)); + if (celOptions.enableShortCircuiting()) { + if (isUnknownValue(condition.value())) { + return condition; + } + if ((boolean) condition.value()) { + return evalInternal(frame, callExpr.args().get(1)); + } + return evalInternal(frame, callExpr.args().get(2)); + } else { + IntermediateResult lhs = evalInternal(frame, callExpr.args().get(1)); + IntermediateResult rhs = evalInternal(frame, callExpr.args().get(2)); + if (isUnknownValue(condition.value())) { + return condition; + } + return (boolean) condition.value() ? lhs : rhs; } - return evalInternal(frame, callExpr.args().get(2)); } private IntermediateResult mergeBooleanUnknowns(IntermediateResult lhs, IntermediateResult rhs) @@ -482,15 +491,33 @@ private IntermediateResult mergeBooleanUnknowns(IntermediateResult lhs, Intermed InterpreterUtil.shortcircuitUnknownOrThrowable(lhs.value(), rhs.value())); } + private enum ShortCircuitableOperators { + LOGICAL_OR, + LOGICAL_AND + } + + private boolean canShortCircuit(IntermediateResult result, ShortCircuitableOperators operator) { + if (!celOptions.enableShortCircuiting() || !(result.value() instanceof Boolean)) { + return false; + } + + Boolean value = (Boolean) result.value(); + if (value && operator.equals(ShortCircuitableOperators.LOGICAL_OR)) { + return true; + } + + return !value && operator.equals(ShortCircuitableOperators.LOGICAL_AND); + } + private IntermediateResult evalLogicalOr(ExecutionFrame frame, CelCall callExpr) throws InterpreterException { IntermediateResult left = evalBooleanNonstrict(frame, callExpr.args().get(0)); - if (left.value() instanceof Boolean && (Boolean) left.value()) { + if (canShortCircuit(left, ShortCircuitableOperators.LOGICAL_OR)) { return left; } IntermediateResult right = evalBooleanNonstrict(frame, callExpr.args().get(1)); - if (right.value() instanceof Boolean && (Boolean) right.value()) { + if (canShortCircuit(right, ShortCircuitableOperators.LOGICAL_OR)) { return right; } @@ -505,12 +532,12 @@ private IntermediateResult evalLogicalOr(ExecutionFrame frame, CelCall callExpr) private IntermediateResult evalLogicalAnd(ExecutionFrame frame, CelCall callExpr) throws InterpreterException { IntermediateResult left = evalBooleanNonstrict(frame, callExpr.args().get(0)); - if (left.value() instanceof Boolean && !((Boolean) left.value())) { + if (canShortCircuit(left, ShortCircuitableOperators.LOGICAL_AND)) { return left; } IntermediateResult right = evalBooleanNonstrict(frame, callExpr.args().get(1)); - if (right.value() instanceof Boolean && !((Boolean) right.value())) { + if (canShortCircuit(right, ShortCircuitableOperators.LOGICAL_AND)) { return right; } diff --git a/runtime/src/test/java/dev/cel/runtime/CelRuntimeTest.java b/runtime/src/test/java/dev/cel/runtime/CelRuntimeTest.java index 72038992e..2d6d7ed76 100644 --- a/runtime/src/test/java/dev/cel/runtime/CelRuntimeTest.java +++ b/runtime/src/test/java/dev/cel/runtime/CelRuntimeTest.java @@ -20,6 +20,7 @@ import com.google.api.expr.v1alpha1.Constant; import com.google.api.expr.v1alpha1.Expr; import com.google.api.expr.v1alpha1.Type.PrimitiveType; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.protobuf.Any; import com.google.protobuf.BoolValue; @@ -27,6 +28,8 @@ import com.google.protobuf.DescriptorProtos.FileDescriptorSet; import com.google.protobuf.DynamicMessage; import com.google.rpc.context.AttributeContext; +import com.google.testing.junit.testparameterinjector.TestParameterInjector; +import com.google.testing.junit.testparameterinjector.TestParameters; import dev.cel.bundle.Cel; import dev.cel.bundle.CelFactory; import dev.cel.common.CelAbstractSyntaxTree; @@ -50,9 +53,8 @@ import java.util.concurrent.atomic.AtomicReference; import org.junit.Test; import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; -@RunWith(JUnit4.class) +@RunWith(TestParameterInjector.class) public class CelRuntimeTest { @Test @@ -400,6 +402,141 @@ public void trace_withVariableResolver() throws Exception { assertThat(result).isEqualTo("hello"); } + @Test + public void trace_shortCircuitingDisabled_logicalAndAllBranchesVisited() throws Exception { + ImmutableList.Builder branchResults = ImmutableList.builder(); + CelEvaluationListener listener = + (expr, res) -> { + if (expr.constantOrDefault().getKind().equals(CelConstant.Kind.BOOLEAN_VALUE)) { + branchResults.add((Boolean) res); + } + }; + Cel cel = + CelFactory.standardCelBuilder() + .setOptions(CelOptions.current().enableShortCircuiting(false).build()) + .build(); + CelAbstractSyntaxTree ast = cel.compile("false && true && false").getAst(); + + boolean result = (boolean) cel.createProgram(ast).trace(listener); + + assertThat(result).isFalse(); + assertThat(branchResults.build()).containsExactly(false, true, false); + } + + @Test + public void trace_shortCircuitingDisabled_logicalAndWithUnknowns() throws Exception { + ImmutableList.Builder branchResults = ImmutableList.builder(); + CelEvaluationListener listener = + (expr, res) -> { + if (expr.constantOrDefault().getKind().equals(CelConstant.Kind.BOOLEAN_VALUE) + || expr.identOrDefault().name().equals("x")) { + branchResults.add(res); + } + }; + Cel cel = + CelFactory.standardCelBuilder() + .addVar("x", SimpleType.BOOL) + .setOptions(CelOptions.current().enableShortCircuiting(false).build()) + .build(); + CelAbstractSyntaxTree ast = cel.compile("false && false && x").getAst(); + + Object unknownResult = cel.createProgram(ast).trace(listener); + + assertThat(InterpreterUtil.isUnknown(unknownResult)).isTrue(); + assertThat(branchResults.build()).containsExactly(false, false, unknownResult); + } + + @Test + public void trace_shortCircuitingDisabled_logicalOrAllBranchesVisited() throws Exception { + ImmutableList.Builder branchResults = ImmutableList.builder(); + CelEvaluationListener listener = + (expr, res) -> { + if (expr.constantOrDefault().getKind().equals(CelConstant.Kind.BOOLEAN_VALUE)) { + branchResults.add((Boolean) res); + } + }; + Cel cel = + CelFactory.standardCelBuilder() + .setOptions(CelOptions.current().enableShortCircuiting(false).build()) + .build(); + CelAbstractSyntaxTree ast = cel.compile("true || false || true").getAst(); + + boolean result = (boolean) cel.createProgram(ast).trace(listener); + + assertThat(result).isTrue(); + assertThat(branchResults.build()).containsExactly(true, false, true); + } + + @Test + public void trace_shortCircuitingDisabled_logicalOrWithUnknowns() throws Exception { + ImmutableList.Builder branchResults = ImmutableList.builder(); + CelEvaluationListener listener = + (expr, res) -> { + if (expr.constantOrDefault().getKind().equals(CelConstant.Kind.BOOLEAN_VALUE) + || expr.identOrDefault().name().equals("x")) { + branchResults.add(res); + } + }; + Cel cel = + CelFactory.standardCelBuilder() + .addVar("x", SimpleType.BOOL) + .setOptions(CelOptions.current().enableShortCircuiting(false).build()) + .build(); + CelAbstractSyntaxTree ast = cel.compile("false || false || x").getAst(); + + Object unknownResult = cel.createProgram(ast).trace(listener); + + assertThat(InterpreterUtil.isUnknown(unknownResult)).isTrue(); + assertThat(branchResults.build()).containsExactly(false, false, unknownResult); + } + + @Test + public void trace_shortCircuitingDisabled_ternaryAllBranchesVisited() throws Exception { + ImmutableList.Builder branchResults = ImmutableList.builder(); + CelEvaluationListener listener = + (expr, res) -> { + if (expr.constantOrDefault().getKind().equals(CelConstant.Kind.BOOLEAN_VALUE)) { + branchResults.add((Boolean) res); + } + }; + Cel cel = + CelFactory.standardCelBuilder() + .setOptions(CelOptions.current().enableShortCircuiting(false).build()) + .build(); + CelAbstractSyntaxTree ast = cel.compile("true ? false : true").getAst(); + + boolean result = (boolean) cel.createProgram(ast).trace(listener); + + assertThat(result).isFalse(); + assertThat(branchResults.build()).containsExactly(true, false, true); + } + + @Test + @TestParameters("{source: 'false ? true : x'}") + @TestParameters("{source: 'true ? x : false'}") + @TestParameters("{source: 'x ? true : false'}") + public void trace_shortCircuitingDisabled_ternaryWithUnknowns(String source) throws Exception { + ImmutableList.Builder branchResults = ImmutableList.builder(); + CelEvaluationListener listener = + (expr, res) -> { + if (expr.constantOrDefault().getKind().equals(CelConstant.Kind.BOOLEAN_VALUE) + || expr.identOrDefault().name().equals("x")) { + branchResults.add(res); + } + }; + Cel cel = + CelFactory.standardCelBuilder() + .addVar("x", SimpleType.BOOL) + .setOptions(CelOptions.current().enableShortCircuiting(false).build()) + .build(); + CelAbstractSyntaxTree ast = cel.compile(source).getAst(); + + Object unknownResult = cel.createProgram(ast).trace(listener); + + assertThat(InterpreterUtil.isUnknown(unknownResult)).isTrue(); + assertThat(branchResults.build()).containsExactly(false, unknownResult, true); + } + @Test public void standardEnvironmentDisabledForRuntime_throws() throws Exception { CelCompiler celCompiler = From ffb486c1bf525774cfc6e437bbe4f3d0c6b9d84a Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Wed, 6 Mar 2024 11:17:41 -0800 Subject: [PATCH 058/486] Prepare 0.4.0 release PiperOrigin-RevId: 613281438 --- README.md | 4 ++-- publish/BUILD.bazel | 1 + publish/cel_version.bzl | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f721f8dfc..211cb7707 100644 --- a/README.md +++ b/README.md @@ -55,14 +55,14 @@ CEL-Java is available in Maven Central Repository. [Download the JARs here][8] o dev.cel cel - 0.3.1 + 0.4.0 ``` **Gradle** ```gradle -implementation 'dev.cel:cel:0.3.0' +implementation 'dev.cel:cel:0.4.0' ``` Then run this example: diff --git a/publish/BUILD.bazel b/publish/BUILD.bazel index 4f16dc50c..7abe2c447 100644 --- a/publish/BUILD.bazel +++ b/publish/BUILD.bazel @@ -16,6 +16,7 @@ RUNTIME_TARGETS = [ COMPILER_TARGETS = [ "//parser/src/main/java/dev/cel/parser", "//parser/src/main/java/dev/cel/parser:parser_builder", + "//parser/src/main/java/dev/cel/parser:unparser", "//checker/src/main/java/dev/cel/checker:checker", "//checker/src/main/java/dev/cel/checker:checker_builder", "//checker/src/main/java/dev/cel/checker:proto_type_mask", diff --git a/publish/cel_version.bzl b/publish/cel_version.bzl index 3176b284c..7c9516b20 100644 --- a/publish/cel_version.bzl +++ b/publish/cel_version.bzl @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. """Maven artifact version for CEL.""" -CEL_VERSION = "0.3.1" +CEL_VERSION = "0.4.0" From dd9ed38da74418508f80a31a2016a7514cec5e26 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Wed, 6 Mar 2024 15:05:50 -0800 Subject: [PATCH 059/486] Add CSE to publish target PiperOrigin-RevId: 613354167 --- publish/BUILD.bazel | 1 + 1 file changed, 1 insertion(+) diff --git a/publish/BUILD.bazel b/publish/BUILD.bazel index 7abe2c447..630d0f94d 100644 --- a/publish/BUILD.bazel +++ b/publish/BUILD.bazel @@ -44,6 +44,7 @@ OPTIMIZER_TARGETS = [ "//optimizer/src/main/java/dev/cel/optimizer:mutable_ast", "//optimizer/src/main/java/dev/cel/optimizer:optimizer_impl", "//optimizer/src/main/java/dev/cel/optimizer/optimizers:constant_folding", + "//optimizer/src/main/java/dev/cel/optimizer/optimizers:common_subexpression_elimination", ] V1ALPHA1_UTILITY_TARGETS = [ From 6d6ecd480b76feb97ef852a9cfc7b79e7fa09457 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Mon, 18 Mar 2024 11:53:52 -0700 Subject: [PATCH 060/486] Optimize scoped variable access using an unmodifiable map PiperOrigin-RevId: 616901857 --- .../dev/cel/runtime/DefaultInterpreter.java | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java b/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java index cd7c25fb3..d941f6734 100644 --- a/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java +++ b/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java @@ -19,7 +19,6 @@ import com.google.auto.value.AutoValue; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; import com.google.errorprone.annotations.Immutable; import javax.annotation.concurrent.ThreadSafe; import dev.cel.common.CelAbstractSyntaxTree; @@ -43,6 +42,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; @@ -852,14 +852,12 @@ private IntermediateResult evalComprehension( } i++; - ImmutableMap loopVars = - ImmutableMap.of( - iterVar, - IntermediateResult.create(iterAttr, RuntimeHelpers.maybeAdaptPrimitive(elem)), - accuVar, - accuValue); + Map loopVars = new HashMap<>(); + loopVars.put( + iterVar, IntermediateResult.create(iterAttr, RuntimeHelpers.maybeAdaptPrimitive(elem))); + loopVars.put(accuVar, accuValue); - frame.pushScope(loopVars); + frame.pushScope(Collections.unmodifiableMap(loopVars)); IntermediateResult evalObject = evalBooleanStrict(frame, compre.loopCondition()); if (!isUnknownValue(evalObject.value()) && !(boolean) evalObject.value()) { frame.popScope(); @@ -869,7 +867,7 @@ private IntermediateResult evalComprehension( frame.popScope(); } - frame.pushScope(ImmutableMap.of(accuVar, accuValue)); + frame.pushScope(Collections.singletonMap(accuVar, accuValue)); IntermediateResult result = evalInternal(frame, compre.result()); frame.popScope(); return result; @@ -878,14 +876,14 @@ private IntermediateResult evalComprehension( private IntermediateResult evalCelBlock( ExecutionFrame frame, CelExpr unusedExpr, CelCall blockCall) throws InterpreterException { CelCreateList exprList = blockCall.args().get(0).createList(); - ImmutableMap.Builder blockList = ImmutableMap.builder(); + Map blockList = new HashMap<>(); for (int index = 0; index < exprList.elements().size(); index++) { // Register the block indices as lazily evaluated expressions stored as unique identifiers. blockList.put( "@index" + index, IntermediateResult.create(new LazyExpression(exprList.elements().get(index)))); } - frame.pushScope(blockList.buildOrThrow()); + frame.pushScope(Collections.unmodifiableMap(blockList)); return evalInternal(frame, blockCall.args().get(1)); } @@ -970,7 +968,8 @@ private void cacheLazilyEvaluatedResult( currentResolver.cacheLazilyEvaluatedResult(name, result); } - private void pushScope(ImmutableMap scope) { + /** Note: we utilize a HashMap instead of ImmutableMap to make lookups faster on string keys. */ + private void pushScope(Map scope) { RuntimeUnknownResolver scopedResolver = currentResolver.withScope(scope); currentResolver = scopedResolver; resolvers.addLast(scopedResolver); From 9719d529633596f4d27e5184cac6c3dbc68f10bd Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Wed, 20 Mar 2024 09:32:11 -0700 Subject: [PATCH 061/486] Fix an issue with incorrect boolean evaluation when short-circuiting is disabled PiperOrigin-RevId: 617539191 --- .../dev/cel/runtime/DefaultInterpreter.java | 72 +++++--- .../java/dev/cel/runtime/CelRuntimeTest.java | 160 ++++++++++++++++-- 2 files changed, 197 insertions(+), 35 deletions(-) diff --git a/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java b/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java index d941f6734..0579887e9 100644 --- a/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java +++ b/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java @@ -464,12 +464,14 @@ private IntermediateResult evalConditional(ExecutionFrame frame, CelCall callExp } return evalInternal(frame, callExpr.args().get(2)); } else { - IntermediateResult lhs = evalInternal(frame, callExpr.args().get(1)); - IntermediateResult rhs = evalInternal(frame, callExpr.args().get(2)); + IntermediateResult lhs = evalNonstrictly(frame, callExpr.args().get(1)); + IntermediateResult rhs = evalNonstrictly(frame, callExpr.args().get(2)); if (isUnknownValue(condition.value())) { return condition; } - return (boolean) condition.value() ? lhs : rhs; + Object result = + InterpreterUtil.strict((boolean) condition.value() ? lhs.value() : rhs.value()); + return IntermediateResult.create(result); } } @@ -497,7 +499,7 @@ private enum ShortCircuitableOperators { } private boolean canShortCircuit(IntermediateResult result, ShortCircuitableOperators operator) { - if (!celOptions.enableShortCircuiting() || !(result.value() instanceof Boolean)) { + if (!(result.value() instanceof Boolean)) { return false; } @@ -511,19 +513,32 @@ private boolean canShortCircuit(IntermediateResult result, ShortCircuitableOpera private IntermediateResult evalLogicalOr(ExecutionFrame frame, CelCall callExpr) throws InterpreterException { - IntermediateResult left = evalBooleanNonstrict(frame, callExpr.args().get(0)); - if (canShortCircuit(left, ShortCircuitableOperators.LOGICAL_OR)) { - return left; - } + IntermediateResult left; + IntermediateResult right; + if (celOptions.enableShortCircuiting()) { + left = evalBooleanNonstrict(frame, callExpr.args().get(0)); + if (canShortCircuit(left, ShortCircuitableOperators.LOGICAL_OR)) { + return left; + } - IntermediateResult right = evalBooleanNonstrict(frame, callExpr.args().get(1)); - if (canShortCircuit(right, ShortCircuitableOperators.LOGICAL_OR)) { - return right; + right = evalBooleanNonstrict(frame, callExpr.args().get(1)); + if (canShortCircuit(right, ShortCircuitableOperators.LOGICAL_OR)) { + return right; + } + } else { + left = evalBooleanNonstrict(frame, callExpr.args().get(0)); + right = evalBooleanNonstrict(frame, callExpr.args().get(1)); + if (canShortCircuit(left, ShortCircuitableOperators.LOGICAL_OR)) { + return left; + } + if (canShortCircuit(right, ShortCircuitableOperators.LOGICAL_OR)) { + return right; + } } - // both false. + // both are booleans. if (right.value() instanceof Boolean && left.value() instanceof Boolean) { - return left; + return IntermediateResult.create((Boolean) right.value() || (Boolean) left.value()); } return mergeBooleanUnknowns(left, right); @@ -531,19 +546,32 @@ private IntermediateResult evalLogicalOr(ExecutionFrame frame, CelCall callExpr) private IntermediateResult evalLogicalAnd(ExecutionFrame frame, CelCall callExpr) throws InterpreterException { - IntermediateResult left = evalBooleanNonstrict(frame, callExpr.args().get(0)); - if (canShortCircuit(left, ShortCircuitableOperators.LOGICAL_AND)) { - return left; - } + IntermediateResult left; + IntermediateResult right; + if (celOptions.enableShortCircuiting()) { + left = evalBooleanNonstrict(frame, callExpr.args().get(0)); + if (canShortCircuit(left, ShortCircuitableOperators.LOGICAL_AND)) { + return left; + } - IntermediateResult right = evalBooleanNonstrict(frame, callExpr.args().get(1)); - if (canShortCircuit(right, ShortCircuitableOperators.LOGICAL_AND)) { - return right; + right = evalBooleanNonstrict(frame, callExpr.args().get(1)); + if (canShortCircuit(right, ShortCircuitableOperators.LOGICAL_AND)) { + return right; + } + } else { + left = evalBooleanNonstrict(frame, callExpr.args().get(0)); + right = evalBooleanNonstrict(frame, callExpr.args().get(1)); + if (canShortCircuit(left, ShortCircuitableOperators.LOGICAL_AND)) { + return left; + } + if (canShortCircuit(right, ShortCircuitableOperators.LOGICAL_AND)) { + return right; + } } - // both true. + // both are booleans. if (right.value() instanceof Boolean && left.value() instanceof Boolean) { - return left; + return IntermediateResult.create((Boolean) right.value() && (Boolean) left.value()); } return mergeBooleanUnknowns(left, right); diff --git a/runtime/src/test/java/dev/cel/runtime/CelRuntimeTest.java b/runtime/src/test/java/dev/cel/runtime/CelRuntimeTest.java index 2d6d7ed76..8e065ea13 100644 --- a/runtime/src/test/java/dev/cel/runtime/CelRuntimeTest.java +++ b/runtime/src/test/java/dev/cel/runtime/CelRuntimeTest.java @@ -28,6 +28,7 @@ import com.google.protobuf.DescriptorProtos.FileDescriptorSet; import com.google.protobuf.DynamicMessage; import com.google.rpc.context.AttributeContext; +import com.google.testing.junit.testparameterinjector.TestParameter; import com.google.testing.junit.testparameterinjector.TestParameterInjector; import com.google.testing.junit.testparameterinjector.TestParameters; import dev.cel.bundle.Cel; @@ -403,7 +404,10 @@ public void trace_withVariableResolver() throws Exception { } @Test - public void trace_shortCircuitingDisabled_logicalAndAllBranchesVisited() throws Exception { + public void trace_shortCircuitingDisabled_logicalAndAllBranchesVisited( + @TestParameter boolean first, @TestParameter boolean second, @TestParameter boolean third) + throws Exception { + String expression = String.format("%s && %s && %s", first, second, third); ImmutableList.Builder branchResults = ImmutableList.builder(); CelEvaluationListener listener = (expr, res) -> { @@ -411,20 +415,64 @@ public void trace_shortCircuitingDisabled_logicalAndAllBranchesVisited() throws branchResults.add((Boolean) res); } }; + Cel celWithShortCircuit = + CelFactory.standardCelBuilder() + .setOptions(CelOptions.current().enableShortCircuiting(true).build()) + .build(); + Cel cel = + CelFactory.standardCelBuilder() + .setOptions(CelOptions.current().enableShortCircuiting(false).build()) + .build(); + CelAbstractSyntaxTree ast = cel.compile(expression).getAst(); + + boolean result = (boolean) cel.createProgram(ast).trace(listener); + boolean shortCircuitedResult = + (boolean) + celWithShortCircuit + .createProgram(celWithShortCircuit.compile(expression).getAst()) + .eval(); + + assertThat(result).isEqualTo(shortCircuitedResult); + assertThat(branchResults.build()).containsExactly(first, second, third).inOrder(); + } + + @Test + @TestParameters("{source: 'false && false && x'}") + @TestParameters("{source: 'false && x && false'}") + @TestParameters("{source: 'x && false && false'}") + public void trace_shortCircuitingDisabledWithUnknownsAndedToFalse_returnsFalse(String source) + throws Exception { + ImmutableList.Builder branchResults = ImmutableList.builder(); + CelEvaluationListener listener = + (expr, res) -> { + if (expr.constantOrDefault().getKind().equals(CelConstant.Kind.BOOLEAN_VALUE) + || expr.identOrDefault().name().equals("x")) { + if (InterpreterUtil.isUnknown(res)) { + branchResults.add("x"); // Swap unknown result with a sentinel value for testing + } else { + branchResults.add(res); + } + } + }; Cel cel = CelFactory.standardCelBuilder() + .addVar("x", SimpleType.BOOL) .setOptions(CelOptions.current().enableShortCircuiting(false).build()) .build(); - CelAbstractSyntaxTree ast = cel.compile("false && true && false").getAst(); + CelAbstractSyntaxTree ast = cel.compile(source).getAst(); boolean result = (boolean) cel.createProgram(ast).trace(listener); assertThat(result).isFalse(); - assertThat(branchResults.build()).containsExactly(false, true, false); + assertThat(branchResults.build()).containsExactly(false, false, "x"); } @Test - public void trace_shortCircuitingDisabled_logicalAndWithUnknowns() throws Exception { + @TestParameters("{source: 'true && true && x'}") + @TestParameters("{source: 'true && x && true'}") + @TestParameters("{source: 'x && true && true'}") + public void trace_shortCircuitingDisabledWithUnknownAndedToTrue_returnsUnknown(String source) + throws Exception { ImmutableList.Builder branchResults = ImmutableList.builder(); CelEvaluationListener listener = (expr, res) -> { @@ -438,16 +486,19 @@ public void trace_shortCircuitingDisabled_logicalAndWithUnknowns() throws Except .addVar("x", SimpleType.BOOL) .setOptions(CelOptions.current().enableShortCircuiting(false).build()) .build(); - CelAbstractSyntaxTree ast = cel.compile("false && false && x").getAst(); + CelAbstractSyntaxTree ast = cel.compile(source).getAst(); Object unknownResult = cel.createProgram(ast).trace(listener); assertThat(InterpreterUtil.isUnknown(unknownResult)).isTrue(); - assertThat(branchResults.build()).containsExactly(false, false, unknownResult); + assertThat(branchResults.build()).containsExactly(true, true, unknownResult); } @Test - public void trace_shortCircuitingDisabled_logicalOrAllBranchesVisited() throws Exception { + public void trace_shortCircuitingDisabled_logicalOrAllBranchesVisited( + @TestParameter boolean first, @TestParameter boolean second, @TestParameter boolean third) + throws Exception { + String expression = String.format("%s || %s || %s", first, second, third); ImmutableList.Builder branchResults = ImmutableList.builder(); CelEvaluationListener listener = (expr, res) -> { @@ -455,20 +506,33 @@ public void trace_shortCircuitingDisabled_logicalOrAllBranchesVisited() throws E branchResults.add((Boolean) res); } }; + Cel celWithShortCircuit = + CelFactory.standardCelBuilder() + .setOptions(CelOptions.current().enableShortCircuiting(true).build()) + .build(); Cel cel = CelFactory.standardCelBuilder() .setOptions(CelOptions.current().enableShortCircuiting(false).build()) .build(); - CelAbstractSyntaxTree ast = cel.compile("true || false || true").getAst(); + CelAbstractSyntaxTree ast = cel.compile(expression).getAst(); boolean result = (boolean) cel.createProgram(ast).trace(listener); - - assertThat(result).isTrue(); - assertThat(branchResults.build()).containsExactly(true, false, true); + boolean shortCircuitedResult = + (boolean) + celWithShortCircuit + .createProgram(celWithShortCircuit.compile(expression).getAst()) + .eval(); + + assertThat(result).isEqualTo(shortCircuitedResult); + assertThat(branchResults.build()).containsExactly(first, second, third).inOrder(); } @Test - public void trace_shortCircuitingDisabled_logicalOrWithUnknowns() throws Exception { + @TestParameters("{source: 'false || false || x'}") + @TestParameters("{source: 'false || x || false'}") + @TestParameters("{source: 'x || false || false'}") + public void trace_shortCircuitingDisabledWithUnknownsOredToFalse_returnsUnknown(String source) + throws Exception { ImmutableList.Builder branchResults = ImmutableList.builder(); CelEvaluationListener listener = (expr, res) -> { @@ -482,7 +546,7 @@ public void trace_shortCircuitingDisabled_logicalOrWithUnknowns() throws Excepti .addVar("x", SimpleType.BOOL) .setOptions(CelOptions.current().enableShortCircuiting(false).build()) .build(); - CelAbstractSyntaxTree ast = cel.compile("false || false || x").getAst(); + CelAbstractSyntaxTree ast = cel.compile(source).getAst(); Object unknownResult = cel.createProgram(ast).trace(listener); @@ -490,6 +554,37 @@ public void trace_shortCircuitingDisabled_logicalOrWithUnknowns() throws Excepti assertThat(branchResults.build()).containsExactly(false, false, unknownResult); } + @Test + @TestParameters("{source: 'true || true || x'}") + @TestParameters("{source: 'true || x || true'}") + @TestParameters("{source: 'x || true || true'}") + public void trace_shortCircuitingDisabledWithUnknownOredToTrue_returnsTrue(String source) + throws Exception { + ImmutableList.Builder branchResults = ImmutableList.builder(); + CelEvaluationListener listener = + (expr, res) -> { + if (expr.constantOrDefault().getKind().equals(CelConstant.Kind.BOOLEAN_VALUE) + || expr.identOrDefault().name().equals("x")) { + if (InterpreterUtil.isUnknown(res)) { + branchResults.add("x"); // Swap unknown result with a sentinel value for testing + } else { + branchResults.add(res); + } + } + }; + Cel cel = + CelFactory.standardCelBuilder() + .addVar("x", SimpleType.BOOL) + .setOptions(CelOptions.current().enableShortCircuiting(false).build()) + .build(); + CelAbstractSyntaxTree ast = cel.compile(source).getAst(); + + boolean result = (boolean) cel.createProgram(ast).trace(listener); + + assertThat(result).isTrue(); + assertThat(branchResults.build()).containsExactly(true, true, "x"); + } + @Test public void trace_shortCircuitingDisabled_ternaryAllBranchesVisited() throws Exception { ImmutableList.Builder branchResults = ImmutableList.builder(); @@ -537,6 +632,45 @@ public void trace_shortCircuitingDisabled_ternaryWithUnknowns(String source) thr assertThat(branchResults.build()).containsExactly(false, unknownResult, true); } + @Test + @TestParameters( + "{expression: 'false ? (1 / 0) > 2 : false', firstVisited: false, secondVisited: false}") + @TestParameters( + "{expression: 'false ? (1 / 0) > 2 : true', firstVisited: false, secondVisited: true}") + @TestParameters( + "{expression: 'true ? false : (1 / 0) > 2', firstVisited: true, secondVisited: false}") + @TestParameters( + "{expression: 'true ? true : (1 / 0) > 2', firstVisited: true, secondVisited: true}") + public void trace_shortCircuitingDisabled_ternaryWithError( + String expression, boolean firstVisited, boolean secondVisited) throws Exception { + ImmutableList.Builder branchResults = ImmutableList.builder(); + CelEvaluationListener listener = + (expr, res) -> { + if (expr.constantOrDefault().getKind().equals(CelConstant.Kind.BOOLEAN_VALUE)) { + branchResults.add(res); + } + }; + Cel celWithShortCircuit = + CelFactory.standardCelBuilder() + .setOptions(CelOptions.current().enableShortCircuiting(true).build()) + .build(); + Cel cel = + CelFactory.standardCelBuilder() + .setOptions(CelOptions.current().enableShortCircuiting(false).build()) + .build(); + CelAbstractSyntaxTree ast = cel.compile(expression).getAst(); + + boolean result = (boolean) cel.createProgram(ast).trace(listener); + boolean shortCircuitedResult = + (boolean) + celWithShortCircuit + .createProgram(celWithShortCircuit.compile(expression).getAst()) + .eval(); + + assertThat(result).isEqualTo(shortCircuitedResult); + assertThat(branchResults.build()).containsExactly(firstVisited, secondVisited).inOrder(); + } + @Test public void standardEnvironmentDisabledForRuntime_throws() throws Exception { CelCompiler celCompiler = From 91a7cf769b57b9ae7cce49a41332c0b709ff6f10 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Thu, 21 Mar 2024 12:01:52 -0700 Subject: [PATCH 062/486] Prepare 0.4.1 release PiperOrigin-RevId: 617919967 --- README.md | 4 ++-- publish/cel_version.bzl | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 211cb7707..83b42cb51 100644 --- a/README.md +++ b/README.md @@ -55,14 +55,14 @@ CEL-Java is available in Maven Central Repository. [Download the JARs here][8] o dev.cel cel - 0.4.0 + 0.4.1 ``` **Gradle** ```gradle -implementation 'dev.cel:cel:0.4.0' +implementation 'dev.cel:cel:0.4.1' ``` Then run this example: diff --git a/publish/cel_version.bzl b/publish/cel_version.bzl index 7c9516b20..23c4f0e6c 100644 --- a/publish/cel_version.bzl +++ b/publish/cel_version.bzl @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. """Maven artifact version for CEL.""" -CEL_VERSION = "0.4.0" +CEL_VERSION = "0.4.1" From 33d5ab8aa3568113a3ac4948638b27c966dbe972 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Mon, 25 Mar 2024 11:22:59 -0700 Subject: [PATCH 063/486] Accept a list as an argument to setParameterTypes in function overload decl PiperOrigin-RevId: 618904024 --- .../test/java/dev/cel/bundle/CelImplTest.java | 40 +++++++++++++++++-- .../src/main/java/dev/cel/checker/Env.java | 2 +- .../dev/cel/checker/CelOverloadDeclTest.java | 18 +++++++++ .../java/dev/cel/common/CelOverloadDecl.java | 2 +- 4 files changed, 56 insertions(+), 6 deletions(-) diff --git a/bundle/src/test/java/dev/cel/bundle/CelImplTest.java b/bundle/src/test/java/dev/cel/bundle/CelImplTest.java index 2b3cf30bb..625d2d1a7 100644 --- a/bundle/src/test/java/dev/cel/bundle/CelImplTest.java +++ b/bundle/src/test/java/dev/cel/bundle/CelImplTest.java @@ -16,6 +16,9 @@ import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; +import static dev.cel.common.CelFunctionDecl.newFunctionDeclaration; +import static dev.cel.common.CelOverloadDecl.newGlobalOverload; +import static dev.cel.common.CelOverloadDecl.newMemberOverload; import static org.junit.Assert.assertThrows; import dev.cel.expr.CheckedExpr; @@ -55,10 +58,8 @@ import dev.cel.checker.ProtoTypeMask; import dev.cel.checker.TypeProvider; import dev.cel.common.CelAbstractSyntaxTree; -import dev.cel.common.CelFunctionDecl; import dev.cel.common.CelIssue; import dev.cel.common.CelOptions; -import dev.cel.common.CelOverloadDecl; import dev.cel.common.CelProtoAbstractSyntaxTree; import dev.cel.common.CelValidationException; import dev.cel.common.CelValidationResult; @@ -97,6 +98,7 @@ import dev.cel.testing.testdata.proto3.TestAllTypesProto.TestAllTypes; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -1800,9 +1802,9 @@ public boolean isAssignableFrom(CelType other) { CelFactory.standardCelBuilder() .addVar("x", SimpleType.INT) .addFunctionDeclarations( - CelFunctionDecl.newFunctionDeclaration( + newFunctionDeclaration( "print", - CelOverloadDecl.newGlobalOverload( + newGlobalOverload( "print_overload", SimpleType.STRING, customType))) // The overload would accept either Int or CustomType @@ -1816,6 +1818,36 @@ public boolean isAssignableFrom(CelType other) { assertThat(result).isEqualTo("5"); } + @Test + @SuppressWarnings("unchecked") // test only + public void program_functionParamWithWellKnownType() throws Exception { + Cel cel = + CelFactory.standardCelBuilder() + .addFunctionDeclarations( + newFunctionDeclaration( + "hasStringValue", + newMemberOverload( + "struct_hasStringValue_string_string", + SimpleType.BOOL, + StructTypeReference.create("google.protobuf.Struct"), + SimpleType.STRING, + SimpleType.STRING))) + .addFunctionBindings( + CelFunctionBinding.from( + "struct_hasStringValue_string_string", + ImmutableList.of(Map.class, String.class, String.class), + args -> { + Map map = (Map) args[0]; + return map.containsKey(args[1]) && map.containsValue(args[2]); + })) + .build(); + CelAbstractSyntaxTree ast = cel.compile("{'a': 'b'}.hasStringValue('a', 'b')").getAst(); + + boolean result = (boolean) cel.createProgram(ast).eval(); + + assertThat(result).isTrue(); + } + @Test public void toBuilder_isImmutable() { CelBuilder celBuilder = CelFactory.standardCelBuilder(); diff --git a/checker/src/main/java/dev/cel/checker/Env.java b/checker/src/main/java/dev/cel/checker/Env.java index 8ce80f488..e1846f1b8 100644 --- a/checker/src/main/java/dev/cel/checker/Env.java +++ b/checker/src/main/java/dev/cel/checker/Env.java @@ -966,7 +966,7 @@ private static CelFunctionDecl sanitizeFunction(CelFunctionDecl func) { overloadBuilder.setResultType(getWellKnownType(resultType)); } - ImmutableSet.Builder parameterTypeBuilder = ImmutableSet.builder(); + ImmutableList.Builder parameterTypeBuilder = ImmutableList.builder(); for (CelType paramType : overloadBuilder.parameterTypes()) { if (isWellKnownType(paramType)) { parameterTypeBuilder.add(getWellKnownType(paramType)); diff --git a/checker/src/test/java/dev/cel/checker/CelOverloadDeclTest.java b/checker/src/test/java/dev/cel/checker/CelOverloadDeclTest.java index 41a11d045..f78a4fa62 100644 --- a/checker/src/test/java/dev/cel/checker/CelOverloadDeclTest.java +++ b/checker/src/test/java/dev/cel/checker/CelOverloadDeclTest.java @@ -20,6 +20,7 @@ import static dev.cel.common.CelOverloadDecl.newMemberOverload; import dev.cel.expr.Decl.FunctionDecl.Overload; +import com.google.common.collect.ImmutableList; import dev.cel.common.CelOverloadDecl; import dev.cel.common.types.CelTypes; import dev.cel.common.types.SimpleType; @@ -85,4 +86,21 @@ public void toProtoOverload_withTypeParams() { .containsExactly(CelTypes.STRING, CelTypes.DOUBLE, CelTypes.createTypeParam("B")); assertThat(protoOverload.getTypeParamsList()).containsExactly("A", "B"); } + + @Test + public void setParameterTypes_doesNotDedupe() { + CelOverloadDecl overloadDecl = + CelOverloadDecl.newBuilder() + .setParameterTypes( + ImmutableList.of( + SimpleType.STRING, SimpleType.STRING, SimpleType.STRING, SimpleType.INT)) + .setOverloadId("overload_id") + .setIsInstanceFunction(true) + .setResultType(SimpleType.DYN) + .build(); + + assertThat(overloadDecl.parameterTypes()) + .containsExactly(SimpleType.STRING, SimpleType.STRING, SimpleType.STRING, SimpleType.INT) + .inOrder(); + } } diff --git a/common/src/main/java/dev/cel/common/CelOverloadDecl.java b/common/src/main/java/dev/cel/common/CelOverloadDecl.java index 30bcac5a8..247f86bc1 100644 --- a/common/src/main/java/dev/cel/common/CelOverloadDecl.java +++ b/common/src/main/java/dev/cel/common/CelOverloadDecl.java @@ -93,7 +93,7 @@ public abstract static class Builder { * Sets the parameter types {@link #parameterTypes()}. Note that this will override any * parameter types added via the accumulator methods {@link #addParameterTypes}. */ - public abstract Builder setParameterTypes(ImmutableSet value); + public abstract Builder setParameterTypes(ImmutableList value); public abstract CelType resultType(); From e37e14b04849bd0cfc2200cf7c2532a2272a70a3 Mon Sep 17 00:00:00 2001 From: CEL Dev Team Date: Mon, 25 Mar 2024 18:48:23 -0700 Subject: [PATCH 064/486] Use simple for loop instead of stream in CEL runtime equality PiperOrigin-RevId: 619027024 --- runtime/src/main/java/dev/cel/runtime/RuntimeEquality.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/runtime/src/main/java/dev/cel/runtime/RuntimeEquality.java b/runtime/src/main/java/dev/cel/runtime/RuntimeEquality.java index 517fb1729..05bda7caa 100644 --- a/runtime/src/main/java/dev/cel/runtime/RuntimeEquality.java +++ b/runtime/src/main/java/dev/cel/runtime/RuntimeEquality.java @@ -54,8 +54,11 @@ public boolean inList(List list, A value, CelOptions celOptions) { return true; } if (value instanceof Number) { - // Ensure that list elements are properly unwrapped and compared for equality. - return list.stream().anyMatch(elem -> objectEquals(elem, value, celOptions)); + for (A elem : list) { + if (objectEquals(elem, value, celOptions)) { + return true; + } + } } return false; } From 423e8bbdea948ac9843835c80ae914f4bcf68b87 Mon Sep 17 00:00:00 2001 From: Justin King Date: Fri, 29 Mar 2024 11:16:56 -0700 Subject: [PATCH 065/486] Enable conformance tests for `optional_type` PiperOrigin-RevId: 620293266 --- BUILD.bazel | 15 ++- .../main/java/dev/cel/common/ast/CelExpr.java | 8 ++ .../cel/extensions/CelOptionalLibrary.java | 5 +- .../dev/cel/parser/CelMacroExprFactory.java | 96 +++++++++++++++++++ .../src/main/java/dev/cel/parser/Parser.java | 5 + .../cel/parser/CelMacroExprFactoryTest.java | 5 + publish/BUILD.bazel | 2 +- 7 files changed, 125 insertions(+), 11 deletions(-) diff --git a/BUILD.bazel b/BUILD.bazel index 3f9a36090..0a86ecbce 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -15,6 +15,13 @@ # Includes package-wide build definitions for maven imported java targets # that needs to be defined separately. +load( + "@bazel_tools//tools/jdk:default_java_toolchain.bzl", + "BASE_JDK9_JVM_OPTS", + "DEFAULT_JAVACOPTS", + "DEFAULT_TOOLCHAIN_CONFIGURATION", + "default_java_toolchain", +) load("@rules_license//rules:license.bzl", "license") licenses(["notice"]) # Apache License 2.0 @@ -82,14 +89,6 @@ java_library( ], ) -load( - "@bazel_tools//tools/jdk:default_java_toolchain.bzl", - "BASE_JDK9_JVM_OPTS", - "DEFAULT_JAVACOPTS", - "DEFAULT_TOOLCHAIN_CONFIGURATION", - "default_java_toolchain", -) - default_java_toolchain( name = "repository_default_toolchain", configuration = DEFAULT_TOOLCHAIN_CONFIGURATION, diff --git a/common/src/main/java/dev/cel/common/ast/CelExpr.java b/common/src/main/java/dev/cel/common/ast/CelExpr.java index 3aa3037b5..f494aa114 100644 --- a/common/src/main/java/dev/cel/common/ast/CelExpr.java +++ b/common/src/main/java/dev/cel/common/ast/CelExpr.java @@ -297,34 +297,42 @@ public CelComprehension comprehension() { return exprKind().comprehension(); } + @CanIgnoreReturnValue public Builder setConstant(CelConstant constant) { return setExprKind(AutoOneOf_CelExpr_ExprKind.constant(constant)); } + @CanIgnoreReturnValue public Builder setIdent(CelIdent ident) { return setExprKind(AutoOneOf_CelExpr_ExprKind.ident(ident)); } + @CanIgnoreReturnValue public Builder setCall(CelCall call) { return setExprKind(AutoOneOf_CelExpr_ExprKind.call(call)); } + @CanIgnoreReturnValue public Builder setSelect(CelSelect select) { return setExprKind(AutoOneOf_CelExpr_ExprKind.select(select)); } + @CanIgnoreReturnValue public Builder setCreateList(CelCreateList createList) { return setExprKind(AutoOneOf_CelExpr_ExprKind.createList(createList)); } + @CanIgnoreReturnValue public Builder setCreateStruct(CelCreateStruct createStruct) { return setExprKind(AutoOneOf_CelExpr_ExprKind.createStruct(createStruct)); } + @CanIgnoreReturnValue public Builder setCreateMap(CelCreateMap createMap) { return setExprKind(AutoOneOf_CelExpr_ExprKind.createMap(createMap)); } + @CanIgnoreReturnValue public Builder setComprehension(CelComprehension comprehension) { return setExprKind(AutoOneOf_CelExpr_ExprKind.comprehension(comprehension)); } diff --git a/extensions/src/main/java/dev/cel/extensions/CelOptionalLibrary.java b/extensions/src/main/java/dev/cel/extensions/CelOptionalLibrary.java index 1da3e57d1..bacc027cd 100644 --- a/extensions/src/main/java/dev/cel/extensions/CelOptionalLibrary.java +++ b/extensions/src/main/java/dev/cel/extensions/CelOptionalLibrary.java @@ -240,7 +240,8 @@ private static Optional expandOptMap( UNUSED_ITER_VAR, exprFactory.newList(), varName, - exprFactory.newReceiverCall(Function.VALUE.getFunction(), target), + exprFactory.newReceiverCall( + Function.VALUE.getFunction(), exprFactory.copy(target)), exprFactory.newBoolLiteral(true), exprFactory.newIdentifier(varName), mapExpr)), @@ -272,7 +273,7 @@ private static Optional expandOptFlatMap( UNUSED_ITER_VAR, exprFactory.newList(), varName, - exprFactory.newReceiverCall(Function.VALUE.getFunction(), target), + exprFactory.newReceiverCall(Function.VALUE.getFunction(), exprFactory.copy(target)), exprFactory.newBoolLiteral(true), exprFactory.newIdentifier(varName), mapExpr), diff --git a/parser/src/main/java/dev/cel/parser/CelMacroExprFactory.java b/parser/src/main/java/dev/cel/parser/CelMacroExprFactory.java index 9a01d7968..531622486 100644 --- a/parser/src/main/java/dev/cel/parser/CelMacroExprFactory.java +++ b/parser/src/main/java/dev/cel/parser/CelMacroExprFactory.java @@ -56,6 +56,102 @@ public final CelSourceLocation getSourceLocation(CelExpr expr) { return getSourceLocation(expr.id()); } + /** Duplicates {@link CelExpr} with a brand new set of identifiers. */ + public final CelExpr copy(CelExpr expr) { + CelExpr.Builder builder = CelExpr.newBuilder().setId(copyExprId(expr.id())); + switch (expr.exprKind().getKind()) { + case CONSTANT: + builder.setConstant(expr.constant()); + break; + case IDENT: + builder.setIdent(expr.ident()); + break; + case SELECT: + builder.setSelect( + CelExpr.CelSelect.newBuilder() + .setOperand(copy(expr.select().operand())) + .setField(expr.select().field()) + .setTestOnly(expr.select().testOnly()) + .build()); + break; + case CALL: + { + CelExpr.CelCall.Builder callBuilder = + CelExpr.CelCall.newBuilder().setFunction(expr.call().function()); + expr.call().target().ifPresent(target -> callBuilder.setTarget(copy(target))); + for (CelExpr arg : expr.call().args()) { + callBuilder.addArgs(copy(arg)); + } + builder.setCall(callBuilder.build()); + } + break; + case CREATE_LIST: + { + CelExpr.CelCreateList.Builder listBuilder = + CelExpr.CelCreateList.newBuilder() + .addOptionalIndices(expr.createList().optionalIndices()); + for (CelExpr element : expr.createList().elements()) { + listBuilder.addElements(copy(element)); + } + builder.setCreateList(listBuilder.build()); + } + break; + case CREATE_STRUCT: + { + CelExpr.CelCreateStruct.Builder structBuilder = + CelExpr.CelCreateStruct.newBuilder() + .setMessageName(expr.createStruct().messageName()); + for (CelExpr.CelCreateStruct.Entry entry : expr.createStruct().entries()) { + structBuilder.addEntries( + CelExpr.CelCreateStruct.Entry.newBuilder() + .setId(copyExprId(entry.id())) + .setFieldKey(entry.fieldKey()) + .setValue(copy(entry.value())) + .setOptionalEntry(entry.optionalEntry()) + .build()); + } + builder.setCreateStruct(structBuilder.build()); + } + break; + case CREATE_MAP: + { + CelExpr.CelCreateMap.Builder mapBuilder = CelExpr.CelCreateMap.newBuilder(); + for (CelExpr.CelCreateMap.Entry entry : expr.createMap().entries()) { + mapBuilder.addEntries( + CelExpr.CelCreateMap.Entry.newBuilder() + .setId(copyExprId(entry.id())) + .setKey(copy(entry.key())) + .setValue(copy(entry.value())) + .setOptionalEntry(entry.optionalEntry()) + .build()); + } + builder.setCreateMap(mapBuilder.build()); + } + break; + case COMPREHENSION: + builder.setComprehension( + CelExpr.CelComprehension.newBuilder() + .setIterVar(expr.comprehension().iterVar()) + .setIterRange(copy(expr.comprehension().iterRange())) + .setAccuVar(expr.comprehension().accuVar()) + .setAccuInit(copy(expr.comprehension().accuInit())) + .setLoopCondition(copy(expr.comprehension().loopCondition())) + .setLoopStep(copy(expr.comprehension().loopStep())) + .setResult(copy(expr.comprehension().result())) + .build()); + break; + case NOT_SET: + break; + } + return builder.build(); + } + + /** + * Returns the next unique expression ID which is associated with the same metadata (i.e. source + * location, types, references, etc.) as `id`. + */ + protected abstract long copyExprId(long id); + /** Retrieves the source location for the given {@link CelExpr} ID. */ protected abstract CelSourceLocation getSourceLocation(long exprId); diff --git a/parser/src/main/java/dev/cel/parser/Parser.java b/parser/src/main/java/dev/cel/parser/Parser.java index abc5eb21f..95fac0008 100644 --- a/parser/src/main/java/dev/cel/parser/Parser.java +++ b/parser/src/main/java/dev/cel/parser/Parser.java @@ -1110,6 +1110,11 @@ private long nextExprId(int position) { return exprId; } + @Override + public long copyExprId(long id) { + return nextExprId(getPosition(id)); + } + @Override public long nextExprId() { checkState(!positions.isEmpty()); // Should only be called while expanding macros. diff --git a/parser/src/test/java/dev/cel/parser/CelMacroExprFactoryTest.java b/parser/src/test/java/dev/cel/parser/CelMacroExprFactoryTest.java index 0a66f26da..eacd5479c 100644 --- a/parser/src/test/java/dev/cel/parser/CelMacroExprFactoryTest.java +++ b/parser/src/test/java/dev/cel/parser/CelMacroExprFactoryTest.java @@ -41,6 +41,11 @@ private TestCelExprFactory() { exprId = 0L; } + @Override + public long copyExprId(long unused) { + return nextExprId(); + } + @Override public long nextExprId() { return ++exprId; diff --git a/publish/BUILD.bazel b/publish/BUILD.bazel index 630d0f94d..a07bed4d0 100644 --- a/publish/BUILD.bazel +++ b/publish/BUILD.bazel @@ -1,5 +1,5 @@ -load("@rules_jvm_external//:defs.bzl", "java_export") load("@bazel_common//tools/maven:pom_file.bzl", "pom_file") +load("@rules_jvm_external//:defs.bzl", "java_export") load("//publish:cel_version.bzl", "CEL_VERSION") # Note: These targets must reference the build targets in `src` directly in From aaaec129f5253aecbd7ce9bd925646f1ca30d061 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Tue, 2 Apr 2024 10:18:45 -0700 Subject: [PATCH 066/486] Fix optional type resolution PiperOrigin-RevId: 621218599 --- .../cel/extensions/CelOptionalLibrary.java | 7 +++++++ .../test/java/dev/cel/extensions/BUILD.bazel | 1 + .../extensions/CelOptionalLibraryTest.java | 20 +++++++++++++++++++ .../dev/cel/runtime/StandardTypeResolver.java | 3 +++ 4 files changed, 31 insertions(+) diff --git a/extensions/src/main/java/dev/cel/extensions/CelOptionalLibrary.java b/extensions/src/main/java/dev/cel/extensions/CelOptionalLibrary.java index bacc027cd..dad6e0a97 100644 --- a/extensions/src/main/java/dev/cel/extensions/CelOptionalLibrary.java +++ b/extensions/src/main/java/dev/cel/extensions/CelOptionalLibrary.java @@ -28,12 +28,14 @@ import dev.cel.common.CelFunctionDecl; import dev.cel.common.CelIssue; import dev.cel.common.CelOverloadDecl; +import dev.cel.common.CelVarDecl; import dev.cel.common.ast.CelExpr; import dev.cel.common.types.ListType; import dev.cel.common.types.MapType; import dev.cel.common.types.OptionalType; import dev.cel.common.types.SimpleType; import dev.cel.common.types.TypeParamType; +import dev.cel.common.types.TypeType; import dev.cel.compiler.CelCompilerLibrary; import dev.cel.parser.CelMacro; import dev.cel.parser.CelMacroExprFactory; @@ -93,6 +95,11 @@ public void setCheckerOptions(CelCheckerBuilder checkerBuilder) { OptionalType optionalTypeV = OptionalType.create(paramTypeV); ListType listTypeV = ListType.create(paramTypeV); MapType mapTypeKv = MapType.create(paramTypeK, paramTypeV); + + // Type declaration for optional_type -> type(optional_type(V)) + checkerBuilder.addVarDeclarations( + CelVarDecl.newVarDeclaration(OptionalType.NAME, TypeType.create(optionalTypeV))); + checkerBuilder.addFunctionDeclarations( CelFunctionDecl.newFunctionDeclaration( Function.OPTIONAL_OF.getFunction(), diff --git a/extensions/src/test/java/dev/cel/extensions/BUILD.bazel b/extensions/src/test/java/dev/cel/extensions/BUILD.bazel index 7f572f58f..c2a362a81 100644 --- a/extensions/src/test/java/dev/cel/extensions/BUILD.bazel +++ b/extensions/src/test/java/dev/cel/extensions/BUILD.bazel @@ -27,6 +27,7 @@ java_library( "//parser:macro", "//runtime", "//runtime:interpreter_util", + "@cel_spec//proto/cel/expr:expr_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_protobuf_protobuf_java_util", diff --git a/extensions/src/test/java/dev/cel/extensions/CelOptionalLibraryTest.java b/extensions/src/test/java/dev/cel/extensions/CelOptionalLibraryTest.java index 31df7a325..be215b645 100644 --- a/extensions/src/test/java/dev/cel/extensions/CelOptionalLibraryTest.java +++ b/extensions/src/test/java/dev/cel/extensions/CelOptionalLibraryTest.java @@ -17,6 +17,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertThrows; +import dev.cel.expr.Value; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.primitives.UnsignedLong; @@ -1409,4 +1410,23 @@ public void optionalFlatMapMacro_withNonIdent_throws() { .hasMessageThat() .contains("optFlatMap() variable name must be a simple identifier"); } + + @Test + public void optionalType_typeResolution() throws Exception { + Cel cel = newCelBuilder().build(); + + CelAbstractSyntaxTree ast = cel.compile("optional_type").getAst(); + + assertThat(cel.createProgram(ast).eval()) + .isEqualTo(Value.newBuilder().setTypeValue("optional_type").build()); + } + + @Test + public void optionalType_typeComparison() throws Exception { + Cel cel = newCelBuilder().build(); + + CelAbstractSyntaxTree ast = cel.compile("type(optional.none()) == optional_type").getAst(); + + assertThat(cel.createProgram(ast).eval()).isEqualTo(true); + } } diff --git a/runtime/src/main/java/dev/cel/runtime/StandardTypeResolver.java b/runtime/src/main/java/dev/cel/runtime/StandardTypeResolver.java index c0860f26b..3a46ebea5 100644 --- a/runtime/src/main/java/dev/cel/runtime/StandardTypeResolver.java +++ b/runtime/src/main/java/dev/cel/runtime/StandardTypeResolver.java @@ -34,6 +34,7 @@ import dev.cel.common.types.TypeType; import java.util.Collection; import java.util.Map; +import java.util.Optional; import org.jspecify.nullness.Nullable; /** @@ -76,6 +77,8 @@ private static ImmutableMap> commonTypes(boolean unsignedLongs) // Aggregate types. .put(createType("list"), Collection.class) .put(createType("map"), Map.class) + // Optional type + .put(createType("optional_type"), Optional.class) .buildOrThrow(); } From eda95b0bdb3acc1ad96ee37b469c77d3278e9768 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Thu, 4 Apr 2024 14:29:32 -0700 Subject: [PATCH 067/486] Fix optional field selection behavior on structs PiperOrigin-RevId: 621971615 --- .../extensions/CelOptionalLibraryTest.java | 25 +++++++++++++++++ .../runtime/DescriptorMessageProvider.java | 28 +++++++++++-------- 2 files changed, 41 insertions(+), 12 deletions(-) diff --git a/extensions/src/test/java/dev/cel/extensions/CelOptionalLibraryTest.java b/extensions/src/test/java/dev/cel/extensions/CelOptionalLibraryTest.java index be215b645..12eab47c4 100644 --- a/extensions/src/test/java/dev/cel/extensions/CelOptionalLibraryTest.java +++ b/extensions/src/test/java/dev/cel/extensions/CelOptionalLibraryTest.java @@ -541,6 +541,31 @@ public void optionalFieldSelection_onProtoMessage_returnsOptionalValue() throws assertThat(result).hasValue(5L); } + @Test + public void optionalFieldSelection_onProtoMessage_listValue() throws Exception { + Cel cel = newCelBuilder().build(); + CelAbstractSyntaxTree ast = + cel.compile("optional.of(TestAllTypes{repeated_string: ['foo']}).?repeated_string.value()") + .getAst(); + + List result = (List) cel.createProgram(ast).eval(); + + assertThat(result).containsExactly("foo"); + } + + @Test + public void optionalFieldSelection_onProtoMessage_indexValue() throws Exception { + Cel cel = newCelBuilder().build(); + CelAbstractSyntaxTree ast = + cel.compile( + "optional.of(TestAllTypes{repeated_string: ['foo']}).?repeated_string[0].value()") + .getAst(); + + String result = (String) cel.createProgram(ast).eval(); + + assertThat(result).isEqualTo("foo"); + } + @Test public void optionalFieldSelection_onProtoMessage_chainedSuccess() throws Exception { Cel cel = diff --git a/runtime/src/main/java/dev/cel/runtime/DescriptorMessageProvider.java b/runtime/src/main/java/dev/cel/runtime/DescriptorMessageProvider.java index e6782a206..e8f87f118 100644 --- a/runtime/src/main/java/dev/cel/runtime/DescriptorMessageProvider.java +++ b/runtime/src/main/java/dev/cel/runtime/DescriptorMessageProvider.java @@ -140,28 +140,32 @@ public Object createMessage(String messageName, Map values) { @Nullable @SuppressWarnings("unchecked") public Object selectField(Object message, String fieldName) { + boolean isOptionalMessage = false; if (message instanceof Optional) { - Optional> optionalMap = (Optional>) message; - if (!optionalMap.isPresent()) { - return Optional.empty(); - } - - Map unwrappedMap = optionalMap.get(); - if (!unwrappedMap.containsKey(fieldName)) { + isOptionalMessage = true; + Optional optionalMessage = (Optional) message; + if (!optionalMessage.isPresent()) { return Optional.empty(); } - return Optional.of(unwrappedMap.get(fieldName)); + message = optionalMessage.get(); } if (message instanceof Map) { Map map = (Map) message; if (map.containsKey(fieldName)) { - return map.get(fieldName); + Object mapValue = map.get(fieldName); + return isOptionalMessage ? Optional.of(mapValue) : mapValue; + } + + if (isOptionalMessage) { + return Optional.empty(); + } else { + throw new CelRuntimeException( + new IllegalArgumentException( + String.format("key '%s' is not present in map.", fieldName)), + CelErrorCode.ATTRIBUTE_NOT_FOUND); } - throw new CelRuntimeException( - new IllegalArgumentException(String.format("key '%s' is not present in map.", fieldName)), - CelErrorCode.ATTRIBUTE_NOT_FOUND); } MessageOrBuilder typedMessage = assertFullProtoMessage(message); From 7e244b8e655484ab1535f773a68b3f3c1f4bea4e Mon Sep 17 00:00:00 2001 From: CEL Dev Team Date: Thu, 4 Apr 2024 19:16:16 -0700 Subject: [PATCH 068/486] Add `load()` statements for the builtin Bazel java rules Loads are being added in preparation for moving the rules out of Bazel and into `rules_java`. PiperOrigin-RevId: 622039796 --- testing.bzl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/testing.bzl b/testing.bzl index 026cdcb13..89450efc4 100644 --- a/testing.bzl +++ b/testing.bzl @@ -13,9 +13,10 @@ # limitations under the License. # From: https://github.com/google/guice/blob/master/test_defs.bzl - """starlark macros to generate test suites.""" +load("@rules_java//java:defs.bzl", "java_test") + _TEMPLATE = """package {VAR_PACKAGE}; import org.junit.runners.Suite; import org.junit.runner.RunWith; @@ -84,7 +85,7 @@ def junit4_test_suites( package_name = package_name.replace("/", "."), ) - native.java_test( + java_test( name = "AllTestsSuite", test_class = (package_name + "/" + suite_name).replace("/", "."), srcs = [":" + suite_name], From 432a9540503c0dfbb484c63c37e5b0987fda0ab5 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Fri, 5 Apr 2024 11:46:38 -0700 Subject: [PATCH 069/486] Add a SubexpressionOptimizer baseline test case for fully extractable presence tests Note that this isn't actually rewriting the AST in the most optimized form. Example: `has({'a': true}.a) && has({'a': true}.a)` should rewrite to: `cel.@block([has({'a': true}.a)], @index0 && @index0`)., not `cel.@block([{"a": true}], has(@index0.a) && has(@index0.a))`. This will be addressed with the incoming mutable AST enhancements. PiperOrigin-RevId: 622240518 --- .../SubexpressionOptimizerBaselineTest.java | 1 + ...old_before_subexpression_unparsed.baseline | 16 ++++++ ...ion_ast_block_common_subexpr_only.baseline | 37 ++++++++++++++ ...ssion_ast_block_recursion_depth_1.baseline | 37 ++++++++++++++ ...ssion_ast_block_recursion_depth_2.baseline | 37 ++++++++++++++ ...ssion_ast_block_recursion_depth_3.baseline | 37 ++++++++++++++ ...ssion_ast_block_recursion_depth_4.baseline | 37 ++++++++++++++ ...ssion_ast_block_recursion_depth_5.baseline | 37 ++++++++++++++ ...ssion_ast_block_recursion_depth_6.baseline | 37 ++++++++++++++ ...ssion_ast_block_recursion_depth_7.baseline | 37 ++++++++++++++ ...ssion_ast_block_recursion_depth_8.baseline | 37 ++++++++++++++ ...ssion_ast_block_recursion_depth_9.baseline | 37 ++++++++++++++ .../subexpression_ast_cascaded_binds.baseline | 50 +++++++++++++++++++ .../resources/subexpression_unparsed.baseline | 16 ++++++ 14 files changed, 453 insertions(+) diff --git a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerBaselineTest.java b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerBaselineTest.java index ca3e0f77a..2cd093ab1 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerBaselineTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerBaselineTest.java @@ -465,6 +465,7 @@ private enum CseTestCase { MACRO_SHADOWED_VARIABLE("[x - 1 > 3 ? x - 1 : 5].exists(x, x - 1 > 3) || x - 1 > 3"), MACRO_SHADOWED_VARIABLE_2("[\"foo\", \"bar\"].map(x, [x + x, x + x]).map(x, [x + x, x + x])"), PRESENCE_TEST("has({'a': true}.a) && {'a':true}['a']"), + PRESENCE_TEST_2("has({'a': true}.a) && has({'a': true}.a)"), PRESENCE_TEST_WITH_TERNARY( "(has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : 0) == 10"), PRESENCE_TEST_WITH_TERNARY_2( diff --git a/optimizer/src/test/resources/constfold_before_subexpression_unparsed.baseline b/optimizer/src/test/resources/constfold_before_subexpression_unparsed.baseline index 2ebaf7ac2..849e8d5ca 100644 --- a/optimizer/src/test/resources/constfold_before_subexpression_unparsed.baseline +++ b/optimizer/src/test/resources/constfold_before_subexpression_unparsed.baseline @@ -430,6 +430,22 @@ Result: true [BLOCK_RECURSION_DEPTH_8]: true [BLOCK_RECURSION_DEPTH_9]: true +Test case: PRESENCE_TEST_2 +Source: has({'a': true}.a) && has({'a': true}.a) +=====> +Result: true +[CASCADED_BINDS]: true +[BLOCK_COMMON_SUBEXPR_ONLY]: true +[BLOCK_RECURSION_DEPTH_1]: true +[BLOCK_RECURSION_DEPTH_2]: true +[BLOCK_RECURSION_DEPTH_3]: true +[BLOCK_RECURSION_DEPTH_4]: true +[BLOCK_RECURSION_DEPTH_5]: true +[BLOCK_RECURSION_DEPTH_6]: true +[BLOCK_RECURSION_DEPTH_7]: true +[BLOCK_RECURSION_DEPTH_8]: true +[BLOCK_RECURSION_DEPTH_9]: true + Test case: PRESENCE_TEST_WITH_TERNARY Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : 0) == 10 =====> diff --git a/optimizer/src/test/resources/subexpression_ast_block_common_subexpr_only.baseline b/optimizer/src/test/resources/subexpression_ast_block_common_subexpr_only.baseline index 960821d8a..d3026dd15 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_common_subexpr_only.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_common_subexpr_only.baseline @@ -2228,6 +2228,43 @@ CALL [1] { } } } +Test case: PRESENCE_TEST_2 +Source: has({'a': true}.a) && has({'a': true}.a) +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: "a" } + } + value: { + CONSTANT [6] { value: true } + } + } + } + } + } + CALL [7] { + function: _&&_ + args: { + SELECT [8] { + IDENT [9] { + name: @index0 + }.a~presence_test + } + SELECT [10] { + IDENT [11] { + name: @index0 + }.a~presence_test + } + } + } + } +} Test case: PRESENCE_TEST_WITH_TERNARY Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : 0) == 10 =====> diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_1.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_1.baseline index 3b4233150..4a37c61ff 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_1.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_1.baseline @@ -2846,6 +2846,43 @@ CALL [1] { } } } +Test case: PRESENCE_TEST_2 +Source: has({'a': true}.a) && has({'a': true}.a) +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: "a" } + } + value: { + CONSTANT [6] { value: true } + } + } + } + } + } + CALL [7] { + function: _&&_ + args: { + SELECT [8] { + IDENT [9] { + name: @index0 + }.a~presence_test + } + SELECT [10] { + IDENT [11] { + name: @index0 + }.a~presence_test + } + } + } + } +} Test case: PRESENCE_TEST_WITH_TERNARY Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : 0) == 10 =====> diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_2.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_2.baseline index e294e828b..47c8e9e13 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_2.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_2.baseline @@ -2629,6 +2629,43 @@ CALL [1] { } } } +Test case: PRESENCE_TEST_2 +Source: has({'a': true}.a) && has({'a': true}.a) +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: "a" } + } + value: { + CONSTANT [6] { value: true } + } + } + } + } + } + CALL [7] { + function: _&&_ + args: { + SELECT [8] { + IDENT [9] { + name: @index0 + }.a~presence_test + } + SELECT [10] { + IDENT [11] { + name: @index0 + }.a~presence_test + } + } + } + } +} Test case: PRESENCE_TEST_WITH_TERNARY Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : 0) == 10 =====> diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_3.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_3.baseline index 6e9a08799..ae572aed0 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_3.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_3.baseline @@ -2384,6 +2384,43 @@ CALL [1] { } } } +Test case: PRESENCE_TEST_2 +Source: has({'a': true}.a) && has({'a': true}.a) +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: "a" } + } + value: { + CONSTANT [6] { value: true } + } + } + } + } + } + CALL [7] { + function: _&&_ + args: { + SELECT [8] { + IDENT [9] { + name: @index0 + }.a~presence_test + } + SELECT [10] { + IDENT [11] { + name: @index0 + }.a~presence_test + } + } + } + } +} Test case: PRESENCE_TEST_WITH_TERNARY Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : 0) == 10 =====> diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_4.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_4.baseline index 9b7787c5a..d7df4463a 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_4.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_4.baseline @@ -2321,6 +2321,43 @@ CALL [1] { } } } +Test case: PRESENCE_TEST_2 +Source: has({'a': true}.a) && has({'a': true}.a) +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: "a" } + } + value: { + CONSTANT [6] { value: true } + } + } + } + } + } + CALL [7] { + function: _&&_ + args: { + SELECT [8] { + IDENT [9] { + name: @index0 + }.a~presence_test + } + SELECT [10] { + IDENT [11] { + name: @index0 + }.a~presence_test + } + } + } + } +} Test case: PRESENCE_TEST_WITH_TERNARY Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : 0) == 10 =====> diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_5.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_5.baseline index 470c6a612..ce5eafd5f 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_5.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_5.baseline @@ -2291,6 +2291,43 @@ CALL [1] { } } } +Test case: PRESENCE_TEST_2 +Source: has({'a': true}.a) && has({'a': true}.a) +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: "a" } + } + value: { + CONSTANT [6] { value: true } + } + } + } + } + } + CALL [7] { + function: _&&_ + args: { + SELECT [8] { + IDENT [9] { + name: @index0 + }.a~presence_test + } + SELECT [10] { + IDENT [11] { + name: @index0 + }.a~presence_test + } + } + } + } +} Test case: PRESENCE_TEST_WITH_TERNARY Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : 0) == 10 =====> diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_6.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_6.baseline index 107cf04c7..614a372a6 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_6.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_6.baseline @@ -2285,6 +2285,43 @@ CALL [1] { } } } +Test case: PRESENCE_TEST_2 +Source: has({'a': true}.a) && has({'a': true}.a) +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: "a" } + } + value: { + CONSTANT [6] { value: true } + } + } + } + } + } + CALL [7] { + function: _&&_ + args: { + SELECT [8] { + IDENT [9] { + name: @index0 + }.a~presence_test + } + SELECT [10] { + IDENT [11] { + name: @index0 + }.a~presence_test + } + } + } + } +} Test case: PRESENCE_TEST_WITH_TERNARY Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : 0) == 10 =====> diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_7.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_7.baseline index 866f2c073..773c56aa2 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_7.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_7.baseline @@ -2282,6 +2282,43 @@ CALL [1] { } } } +Test case: PRESENCE_TEST_2 +Source: has({'a': true}.a) && has({'a': true}.a) +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: "a" } + } + value: { + CONSTANT [6] { value: true } + } + } + } + } + } + CALL [7] { + function: _&&_ + args: { + SELECT [8] { + IDENT [9] { + name: @index0 + }.a~presence_test + } + SELECT [10] { + IDENT [11] { + name: @index0 + }.a~presence_test + } + } + } + } +} Test case: PRESENCE_TEST_WITH_TERNARY Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : 0) == 10 =====> diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_8.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_8.baseline index 7da4bdebb..1d8371442 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_8.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_8.baseline @@ -2264,6 +2264,43 @@ CALL [1] { } } } +Test case: PRESENCE_TEST_2 +Source: has({'a': true}.a) && has({'a': true}.a) +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: "a" } + } + value: { + CONSTANT [6] { value: true } + } + } + } + } + } + CALL [7] { + function: _&&_ + args: { + SELECT [8] { + IDENT [9] { + name: @index0 + }.a~presence_test + } + SELECT [10] { + IDENT [11] { + name: @index0 + }.a~presence_test + } + } + } + } +} Test case: PRESENCE_TEST_WITH_TERNARY Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : 0) == 10 =====> diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_9.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_9.baseline index b20801a0f..cd73ba02a 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_9.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_9.baseline @@ -2252,6 +2252,43 @@ CALL [1] { } } } +Test case: PRESENCE_TEST_2 +Source: has({'a': true}.a) && has({'a': true}.a) +=====> +CALL [1] { + function: cel.@block + args: { + CREATE_LIST [2] { + elements: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: "a" } + } + value: { + CONSTANT [6] { value: true } + } + } + } + } + } + CALL [7] { + function: _&&_ + args: { + SELECT [8] { + IDENT [9] { + name: @index0 + }.a~presence_test + } + SELECT [10] { + IDENT [11] { + name: @index0 + }.a~presence_test + } + } + } + } +} Test case: PRESENCE_TEST_WITH_TERNARY Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : 0) == 10 =====> diff --git a/optimizer/src/test/resources/subexpression_ast_cascaded_binds.baseline b/optimizer/src/test/resources/subexpression_ast_cascaded_binds.baseline index 08e584050..78f8c433b 100644 --- a/optimizer/src/test/resources/subexpression_ast_cascaded_binds.baseline +++ b/optimizer/src/test/resources/subexpression_ast_cascaded_binds.baseline @@ -2949,6 +2949,56 @@ COMPREHENSION [1] { } } } +Test case: PRESENCE_TEST_2 +Source: has({'a': true}.a) && has({'a': true}.a) +=====> +COMPREHENSION [1] { + iter_var: #unused + iter_range: { + CREATE_LIST [2] { + elements: { + } + } + } + accu_var: @r0 + accu_init: { + CREATE_MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: "a" } + } + value: { + CONSTANT [6] { value: true } + } + } + } + } + loop_condition: { + CONSTANT [7] { value: false } + } + loop_step: { + IDENT [8] { + name: @r0 + } + } + result: { + CALL [9] { + function: _&&_ + args: { + SELECT [10] { + IDENT [11] { + name: @r0 + }.a~presence_test + } + SELECT [12] { + IDENT [13] { + name: @r0 + }.a~presence_test + } + } + } + } +} Test case: PRESENCE_TEST_WITH_TERNARY Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : 0) == 10 =====> diff --git a/optimizer/src/test/resources/subexpression_unparsed.baseline b/optimizer/src/test/resources/subexpression_unparsed.baseline index 83a434ac4..b38a971aa 100644 --- a/optimizer/src/test/resources/subexpression_unparsed.baseline +++ b/optimizer/src/test/resources/subexpression_unparsed.baseline @@ -430,6 +430,22 @@ Result: true [BLOCK_RECURSION_DEPTH_8]: cel.@block([{"a": true}], has(@index0.a) && @index0["a"]) [BLOCK_RECURSION_DEPTH_9]: cel.@block([{"a": true}], has(@index0.a) && @index0["a"]) +Test case: PRESENCE_TEST_2 +Source: has({'a': true}.a) && has({'a': true}.a) +=====> +Result: true +[CASCADED_BINDS]: cel.bind(@r0, {"a": true}, has(@r0.a) && has(@r0.a)) +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([{"a": true}], has(@index0.a) && has(@index0.a)) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([{"a": true}], has(@index0.a) && has(@index0.a)) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([{"a": true}], has(@index0.a) && has(@index0.a)) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([{"a": true}], has(@index0.a) && has(@index0.a)) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([{"a": true}], has(@index0.a) && has(@index0.a)) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([{"a": true}], has(@index0.a) && has(@index0.a)) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([{"a": true}], has(@index0.a) && has(@index0.a)) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([{"a": true}], has(@index0.a) && has(@index0.a)) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([{"a": true}], has(@index0.a) && has(@index0.a)) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([{"a": true}], has(@index0.a) && has(@index0.a)) + Test case: PRESENCE_TEST_WITH_TERNARY Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : 0) == 10 =====> From bbe5ed47b854898bb9b3cf9e5486cc44f795a035 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Tue, 9 Apr 2024 12:33:51 -0700 Subject: [PATCH 070/486] Rename MutableAst to AstMutator PiperOrigin-RevId: 623249439 --- .../{MutableAst.java => AstMutator.java} | 28 ++++++++-------- .../main/java/dev/cel/optimizer/BUILD.bazel | 2 +- .../optimizers/ConstantFoldingOptimizer.java | 33 ++++++++++--------- .../optimizers/SubexpressionOptimizer.java | 28 ++++++++-------- ...utableAstTest.java => AstMutatorTest.java} | 14 ++++---- .../SubexpressionOptimizerTest.java | 8 ++--- 6 files changed, 57 insertions(+), 56 deletions(-) rename optimizer/src/main/java/dev/cel/optimizer/{MutableAst.java => AstMutator.java} (98%) rename optimizer/src/test/java/dev/cel/optimizer/{MutableAstTest.java => AstMutatorTest.java} (99%) diff --git a/optimizer/src/main/java/dev/cel/optimizer/MutableAst.java b/optimizer/src/main/java/dev/cel/optimizer/AstMutator.java similarity index 98% rename from optimizer/src/main/java/dev/cel/optimizer/MutableAst.java rename to optimizer/src/main/java/dev/cel/optimizer/AstMutator.java index 225f7a385..60161350d 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/MutableAst.java +++ b/optimizer/src/main/java/dev/cel/optimizer/AstMutator.java @@ -51,14 +51,14 @@ import java.util.function.Predicate; import java.util.stream.Collectors; -/** MutableAst contains logic for mutating a {@link CelAbstractSyntaxTree}. */ +/** AstMutator contains logic for mutating a {@link CelAbstractSyntaxTree}. */ @Immutable -public final class MutableAst { +public final class AstMutator { private static final ExprIdGenerator NO_OP_ID_GENERATOR = id -> id; private final long iterationLimit; /** - * Returns a new instance of a Mutable AST with the iteration limit set. + * Returns a new instance of a AST Mutator with the iteration limit set. * *

Mutation is performed by walking the existing AST until the expression node to replace is * found, then the new subtree is walked to complete the mutation. Visiting of each node @@ -67,11 +67,11 @@ public final class MutableAst { * * @param iterationLimit Must be greater than 0. */ - public static MutableAst newInstance(long iterationLimit) { - return new MutableAst(iterationLimit); + public static AstMutator newInstance(long iterationLimit) { + return new AstMutator(iterationLimit); } - private MutableAst(long iterationLimit) { + private AstMutator(long iterationLimit) { Preconditions.checkState(iterationLimit > 0L); this.iterationLimit = iterationLimit; } @@ -773,15 +773,15 @@ private CelExpr.Builder mutateExpr( CelExpr.Builder root, CelExpr.Builder newExpr, long exprIdToReplace) { - MutableExprVisitor mutableAst = + MutableExprVisitor astMutator = MutableExprVisitor.newInstance(idGenerator, newExpr, exprIdToReplace, iterationLimit); - return mutableAst.visit(root); + return astMutator.visit(root); } private CelExpr.Builder renumberExprIds(ExprIdGenerator idGenerator, CelExpr.Builder root) { - MutableExprVisitor mutableAst = + MutableExprVisitor astMutator = MutableExprVisitor.newInstance(idGenerator, root, Integer.MIN_VALUE, iterationLimit); - return mutableAst.visit(root); + return astMutator.visit(root); } private static long getMaxId(CelAbstractSyntaxTree ast) { @@ -831,7 +831,7 @@ public abstract static class MangledComprehensionAst { private static MangledComprehensionAst of( CelAbstractSyntaxTree ast, ImmutableMap mangledComprehensionMap) { - return new AutoValue_MutableAst_MangledComprehensionAst(ast, mangledComprehensionMap); + return new AutoValue_AstMutator_MangledComprehensionAst(ast, mangledComprehensionMap); } } @@ -851,7 +851,7 @@ public abstract static class MangledComprehensionType { private static MangledComprehensionType of( Optional iterVarType, Optional resultType) { Preconditions.checkArgument(iterVarType.isPresent() || resultType.isPresent()); - return new AutoValue_MutableAst_MangledComprehensionType(iterVarType, resultType); + return new AutoValue_AstMutator_MangledComprehensionType(iterVarType, resultType); } } @@ -869,7 +869,7 @@ public abstract static class MangledComprehensionName { public abstract String resultName(); private static MangledComprehensionName of(String iterVarName, String resultName) { - return new AutoValue_MutableAst_MangledComprehensionName(iterVarName, resultName); + return new AutoValue_AstMutator_MangledComprehensionName(iterVarName, resultName); } } @@ -889,7 +889,7 @@ abstract static class BindMacro { abstract CelExpr bindMacro(); private static BindMacro of(CelExpr bindExpr, CelExpr bindMacro) { - return new AutoValue_MutableAst_BindMacro(bindExpr, bindMacro); + return new AutoValue_AstMutator_BindMacro(bindExpr, bindMacro); } } } diff --git a/optimizer/src/main/java/dev/cel/optimizer/BUILD.bazel b/optimizer/src/main/java/dev/cel/optimizer/BUILD.bazel index b4a674cb3..7e2022ab1 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/BUILD.bazel +++ b/optimizer/src/main/java/dev/cel/optimizer/BUILD.bazel @@ -79,7 +79,7 @@ java_library( java_library( name = "mutable_ast", srcs = [ - "MutableAst.java", + "AstMutator.java", "MutableExprVisitor.java", ], tags = [ diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java b/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java index f913c3d37..83100d183 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java @@ -32,9 +32,9 @@ import dev.cel.common.navigation.CelNavigableAst; import dev.cel.common.navigation.CelNavigableExpr; import dev.cel.extensions.CelOptionalLibrary.Function; +import dev.cel.optimizer.AstMutator; import dev.cel.optimizer.CelAstOptimizer; import dev.cel.optimizer.CelOptimizationException; -import dev.cel.optimizer.MutableAst; import dev.cel.parser.Operator; import dev.cel.runtime.CelEvaluationException; import java.util.Collection; @@ -73,7 +73,7 @@ public static ConstantFoldingOptimizer newInstance( 0, Optional.empty(), Function.OPTIONAL_NONE.getFunction(), ImmutableList.of()); private final ConstantFoldingOptions constantFoldingOptions; - private final MutableAst mutableAst; + private final AstMutator astMutator; @Override public OptimizationResult optimize(CelNavigableAst navigableAst, Cel cel) @@ -117,7 +117,7 @@ public OptimizationResult optimize(CelNavigableAst navigableAst, Cel cel) // If the output is a list, map, or struct which contains optional entries, then prune it // to make sure that the optionals, if resolved, do not surface in the output literal. CelAbstractSyntaxTree newAst = pruneOptionalElements(navigableAst); - return OptimizationResult.create(mutableAst.renumberIdsConsecutively(newAst)); + return OptimizationResult.create(astMutator.renumberIdsConsecutively(newAst)); } private static boolean canFold(CelNavigableExpr navigableExpr) { @@ -236,7 +236,7 @@ private Optional maybeFold( } return maybeAdaptEvaluatedResult(result) - .map(celExpr -> mutableAst.replaceSubtree(ast, celExpr, node.id())); + .map(celExpr -> astMutator.replaceSubtree(ast, celExpr, node.id())); } private Optional maybeAdaptEvaluatedResult(Object result) { @@ -289,7 +289,7 @@ private Optional maybeRewriteOptional( // An empty optional value was encountered. Rewrite the tree with optional.none call. // This is to account for other optional functions returning an empty optional value // e.g: optional.ofNonZeroValue(0) - return Optional.of(mutableAst.replaceSubtree(ast, OPTIONAL_NONE_EXPR, expr.id())); + return Optional.of(astMutator.replaceSubtree(ast, OPTIONAL_NONE_EXPR, expr.id())); } } else if (!expr.callOrDefault().function().equals(Function.OPTIONAL_OF.getFunction())) { Object unwrappedResult = optResult.get(); @@ -309,7 +309,7 @@ private Optional maybeRewriteOptional( .build()) .build()) .build(); - return Optional.of(mutableAst.replaceSubtree(ast, newOptionalOfCall, expr.id())); + return Optional.of(astMutator.replaceSubtree(ast, newOptionalOfCall, expr.id())); } return Optional.empty(); @@ -338,7 +338,7 @@ private Optional maybePruneBranches( } CelExpr result = cond.constant().booleanValue() ? truthy : falsy; - return Optional.of(mutableAst.replaceSubtree(ast, result, expr.id())); + return Optional.of(astMutator.replaceSubtree(ast, result, expr.id())); } else if (function.equals(Operator.IN.getFunction())) { CelExpr callArg = call.args().get(1); if (!callArg.exprKind().getKind().equals(Kind.CREATE_LIST)) { @@ -348,7 +348,7 @@ private Optional maybePruneBranches( CelCreateList haystack = callArg.createList(); if (haystack.elements().isEmpty()) { return Optional.of( - mutableAst.replaceSubtree( + astMutator.replaceSubtree( ast, CelExpr.newBuilder().setConstant(CelConstant.ofValue(false)).build(), expr.id())); @@ -363,7 +363,7 @@ private Optional maybePruneBranches( if (elem.constantOrDefault().equals(needleValue) || elem.identOrDefault().equals(needleValue)) { return Optional.of( - mutableAst.replaceSubtree( + astMutator.replaceSubtree( ast, CelExpr.newBuilder().setConstant(CelConstant.ofValue(true)).build(), expr.id())); @@ -396,16 +396,17 @@ private Optional maybeShortCircuitCall( } if (arg.constant().booleanValue() == shortCircuit) { - return Optional.of(mutableAst.replaceSubtree(ast, arg, expr.id())); + return Optional.of(astMutator.replaceSubtree(ast, arg, expr.id())); } } ImmutableList newArgs = newArgsBuilder.build(); if (newArgs.isEmpty()) { - return Optional.of(mutableAst.replaceSubtree(ast, call.args().get(0), expr.id())); + CelExpr shortCircuitTarget = call.args().get(0); // either args(0) or args(1) would work here + return Optional.of(astMutator.replaceSubtree(ast, shortCircuitTarget, expr.id())); } if (newArgs.size() == 1) { - return Optional.of(mutableAst.replaceSubtree(ast, newArgs.get(0), expr.id())); + return Optional.of(astMutator.replaceSubtree(ast, newArgs.get(0), expr.id())); } // TODO: Support folding variadic AND/ORs. @@ -483,7 +484,7 @@ private CelAbstractSyntaxTree pruneOptionalListElements(CelAbstractSyntaxTree as updatedIndicesBuilder.add(newOptIndex); } - return mutableAst.replaceSubtree( + return astMutator.replaceSubtree( ast, CelExpr.newBuilder() .setCreateList( @@ -530,7 +531,7 @@ private CelAbstractSyntaxTree pruneOptionalMapElements(CelAbstractSyntaxTree ast } if (modified) { - return mutableAst.replaceSubtree( + return astMutator.replaceSubtree( ast, CelExpr.newBuilder() .setCreateMap( @@ -576,7 +577,7 @@ private CelAbstractSyntaxTree pruneOptionalStructElements( } if (modified) { - return mutableAst.replaceSubtree( + return astMutator.replaceSubtree( ast, CelExpr.newBuilder() .setCreateStruct( @@ -622,6 +623,6 @@ public static Builder newBuilder() { private ConstantFoldingOptimizer(ConstantFoldingOptions constantFoldingOptions) { this.constantFoldingOptions = constantFoldingOptions; - this.mutableAst = MutableAst.newInstance(constantFoldingOptions.maxIterationLimit()); + this.astMutator = AstMutator.newInstance(constantFoldingOptions.maxIterationLimit()); } } diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java index 2ecc21d16..57b9c7a6f 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java @@ -51,9 +51,9 @@ import dev.cel.common.types.SimpleType; import dev.cel.extensions.CelOptionalLibrary; import dev.cel.extensions.CelOptionalLibrary.Function; +import dev.cel.optimizer.AstMutator; +import dev.cel.optimizer.AstMutator.MangledComprehensionAst; import dev.cel.optimizer.CelAstOptimizer; -import dev.cel.optimizer.MutableAst; -import dev.cel.optimizer.MutableAst.MangledComprehensionAst; import dev.cel.parser.Operator; import java.util.ArrayList; import java.util.Arrays; @@ -107,7 +107,7 @@ public class SubexpressionOptimizer implements CelAstOptimizer { Extension.create("cel_block", Version.of(1L, 1L), Component.COMPONENT_RUNTIME); private final SubexpressionOptimizerOptions cseOptions; - private final MutableAst mutableAst; + private final AstMutator astMutator; private final ImmutableSet cseEliminableFunctions; /** @@ -140,7 +140,7 @@ public OptimizationResult optimize(CelNavigableAst navigableAst, Cel cel) { private OptimizationResult optimizeUsingCelBlock(CelNavigableAst navigableAst, Cel cel) { MangledComprehensionAst mangledComprehensionAst = - mutableAst.mangleComprehensionIdentifierNames( + astMutator.mangleComprehensionIdentifierNames( navigableAst.getAst(), MANGLED_COMPREHENSION_IDENTIFIER_PREFIX, MANGLED_COMPREHENSION_RESULT_PREFIX); @@ -176,7 +176,7 @@ private OptimizationResult optimizeUsingCelBlock(CelNavigableAst navigableAst, C "No value present for expr ID: " + semanticallyEqualNode.id())); astToModify = - mutableAst.replaceSubtree( + astMutator.replaceSubtree( astToModify, CelExpr.newBuilder() .setIdent(CelIdent.newBuilder().setName(blockIdentifier).build()) @@ -235,8 +235,8 @@ private OptimizationResult optimizeUsingCelBlock(CelNavigableAst navigableAst, C // Wrap the optimized expression in cel.block astToModify = - mutableAst.wrapAstWithNewCelBlock(CEL_BLOCK_FUNCTION, astToModify, subexpressions); - astToModify = mutableAst.renumberIdsConsecutively(astToModify); + astMutator.wrapAstWithNewCelBlock(CEL_BLOCK_FUNCTION, astToModify, subexpressions); + astToModify = astMutator.renumberIdsConsecutively(astToModify); // Tag the AST with cel.block designated as an extension astToModify = tagAstExtension(astToModify); @@ -359,7 +359,7 @@ private static ImmutableList newBlockIndexVariableDeclarations( private OptimizationResult optimizeUsingCelBind(CelNavigableAst navigableAst) { CelAbstractSyntaxTree astToModify = - mutableAst + astMutator .mangleComprehensionIdentifierNames( navigableAst.getAst(), MANGLED_COMPREHENSION_IDENTIFIER_PREFIX, @@ -395,7 +395,7 @@ private OptimizationResult optimizeUsingCelBind(CelNavigableAst navigableAst) { "No value present for expr ID: " + semanticallyEqualNode.id())); astToModify = - mutableAst.replaceSubtree( + astMutator.replaceSubtree( astToModify, CelExpr.newBuilder() .setIdent(CelIdent.newBuilder().setName(bindIdentifier).build()) @@ -414,7 +414,7 @@ private OptimizationResult optimizeUsingCelBind(CelNavigableAst navigableAst) { // Insert the new bind call astToModify = - mutableAst.replaceSubtreeWithNewBindMacro( + astMutator.replaceSubtreeWithNewBindMacro( astToModify, bindIdentifier, cseCandidate, lca.expr(), lca.id()); // Retain the existing macro calls in case if the bind identifiers are replacing a subtree @@ -436,7 +436,7 @@ private OptimizationResult optimizeUsingCelBind(CelNavigableAst navigableAst) { return OptimizationResult.create(astToModify); } - astToModify = mutableAst.renumberIdsConsecutively(astToModify); + astToModify = astMutator.renumberIdsConsecutively(astToModify); return OptimizationResult.create(astToModify); } @@ -653,14 +653,14 @@ private CelExpr normalizeForEquality(CelExpr celExpr) { .setSelect(presenceTestExpr.select().toBuilder().setTestOnly(false).build()) .build(); - celExpr = mutableAst.replaceSubtree(celExpr, newExpr, newExpr.id()); + celExpr = astMutator.replaceSubtree(celExpr, newExpr, newExpr.id()); } if (iterCount >= cseOptions.iterationLimit()) { throw new IllegalStateException("Max iteration count reached."); } - return mutableAst.clearExprIds(celExpr); + return astMutator.clearExprIds(celExpr); } @VisibleForTesting @@ -778,7 +778,7 @@ public static Builder newBuilder() { private SubexpressionOptimizer(SubexpressionOptimizerOptions cseOptions) { this.cseOptions = cseOptions; - this.mutableAst = MutableAst.newInstance(cseOptions.iterationLimit()); + this.astMutator = AstMutator.newInstance(cseOptions.iterationLimit()); this.cseEliminableFunctions = ImmutableSet.builder() .addAll(CSE_DEFAULT_ELIMINABLE_FUNCTIONS) diff --git a/optimizer/src/test/java/dev/cel/optimizer/MutableAstTest.java b/optimizer/src/test/java/dev/cel/optimizer/AstMutatorTest.java similarity index 99% rename from optimizer/src/test/java/dev/cel/optimizer/MutableAstTest.java rename to optimizer/src/test/java/dev/cel/optimizer/AstMutatorTest.java index 25cc48f9f..6eb0e04b2 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/MutableAstTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/AstMutatorTest.java @@ -53,7 +53,7 @@ import org.junit.runner.RunWith; @RunWith(TestParameterInjector.class) -public class MutableAstTest { +public class AstMutatorTest { private static final Cel CEL = CelFactory.standardCelBuilder() .setStandardMacros(CelStandardMacro.STANDARD_MACROS) @@ -67,7 +67,7 @@ public class MutableAstTest { .build(); private static final CelUnparser CEL_UNPARSER = CelUnparserFactory.newUnparser(); - private static final MutableAst MUTABLE_AST = MutableAst.newInstance(1000); + private static final AstMutator MUTABLE_AST = AstMutator.newInstance(1000); @Test public void constExpr() throws Exception { @@ -82,7 +82,7 @@ public void constExpr() throws Exception { } @Test - public void mutableAst_returnsParsedAst() throws Exception { + public void astMutator_returnsParsedAst() throws Exception { CelAbstractSyntaxTree ast = CEL.compile("10").getAst(); CelAbstractSyntaxTree mutatedAst = @@ -94,7 +94,7 @@ public void mutableAst_returnsParsedAst() throws Exception { } @Test - public void mutableAst_nonMacro_sourceCleared() throws Exception { + public void astMutator_nonMacro_sourceCleared() throws Exception { CelAbstractSyntaxTree ast = CEL.compile("10").getAst(); CelAbstractSyntaxTree mutatedAst = @@ -109,7 +109,7 @@ public void mutableAst_nonMacro_sourceCleared() throws Exception { } @Test - public void mutableAst_macro_sourceMacroCallsPopulated() throws Exception { + public void astMutator_macro_sourceMacroCallsPopulated() throws Exception { CelAbstractSyntaxTree ast = CEL.compile("has(TestAllTypes{}.single_int32)").getAst(); CelAbstractSyntaxTree mutatedAst = @@ -973,13 +973,13 @@ public void mangleComprehensionVariable_hasMacro_noOp() throws Exception { @Test public void replaceSubtree_iterationLimitReached_throws() throws Exception { CelAbstractSyntaxTree ast = CEL.compile("true && false").getAst(); - MutableAst mutableAst = MutableAst.newInstance(1); + AstMutator astMutator = AstMutator.newInstance(1); IllegalStateException e = assertThrows( IllegalStateException.class, () -> - mutableAst.replaceSubtree( + astMutator.replaceSubtree( ast, CelExpr.ofConstantExpr(0, CelConstant.ofValue(false)), 1)); assertThat(e).hasMessageThat().isEqualTo("Max iteration count reached."); diff --git a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java index a67bb5258..6eb4a2f52 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java @@ -45,10 +45,10 @@ import dev.cel.common.types.SimpleType; import dev.cel.common.types.StructTypeReference; import dev.cel.extensions.CelExtensions; +import dev.cel.optimizer.AstMutator; import dev.cel.optimizer.CelOptimizationException; import dev.cel.optimizer.CelOptimizer; import dev.cel.optimizer.CelOptimizerFactory; -import dev.cel.optimizer.MutableAst; import dev.cel.optimizer.optimizers.SubexpressionOptimizer.SubexpressionOptimizerOptions; import dev.cel.parser.CelStandardMacro; import dev.cel.parser.CelUnparser; @@ -555,7 +555,7 @@ public void verifyOptimizedAstCorrectness_indexIsNotForwardReferencing_throws(St */ private static CelAbstractSyntaxTree compileUsingInternalFunctions(String expression) throws CelValidationException { - MutableAst mutableAst = MutableAst.newInstance(1000); + AstMutator astMutator = AstMutator.newInstance(1000); CelAbstractSyntaxTree astToModify = CEL_FOR_EVALUATING_BLOCK.compile(expression).getAst(); while (true) { CelExpr celExpr = @@ -571,7 +571,7 @@ private static CelAbstractSyntaxTree compileUsingInternalFunctions(String expres break; } astToModify = - mutableAst.replaceSubtree( + astMutator.replaceSubtree( astToModify, celExpr.toBuilder() .setCall(celExpr.call().toBuilder().setFunction("cel.@block").build()) @@ -594,7 +594,7 @@ private static CelAbstractSyntaxTree compileUsingInternalFunctions(String expres } String internalIdentName = "@" + celExpr.ident().name(); astToModify = - mutableAst.replaceSubtree( + astMutator.replaceSubtree( astToModify, celExpr.toBuilder() .setIdent(celExpr.ident().toBuilder().setName(internalIdentName).build()) From dec5452e7343c6b819ecb69052ea43b224b4bcec Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Wed, 10 Apr 2024 14:59:49 -0700 Subject: [PATCH 071/486] Implement CelMutableExpr PiperOrigin-RevId: 623615293 --- common/ast/BUILD.bazel | 5 + .../main/java/dev/cel/common/ast/BUILD.bazel | 16 ++ .../dev/cel/common/ast/CelMutableExpr.java | 157 ++++++++++++++++++ .../test/java/dev/cel/common/ast/BUILD.bazel | 2 + .../cel/common/ast/CelMutableExprTest.java | 126 ++++++++++++++ 5 files changed, 306 insertions(+) create mode 100644 common/src/main/java/dev/cel/common/ast/CelMutableExpr.java create mode 100644 common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java diff --git a/common/ast/BUILD.bazel b/common/ast/BUILD.bazel index 91097daf4..cd18dca31 100644 --- a/common/ast/BUILD.bazel +++ b/common/ast/BUILD.bazel @@ -32,3 +32,8 @@ java_library( name = "expr_util", exports = ["//common/src/main/java/dev/cel/common/ast:expr_util"], ) + +java_library( + name = "mutable_ast", + exports = ["//common/src/main/java/dev/cel/common/ast:mutable_ast"], +) diff --git a/common/src/main/java/dev/cel/common/ast/BUILD.bazel b/common/src/main/java/dev/cel/common/ast/BUILD.bazel index ec79dbed2..08e388712 100644 --- a/common/src/main/java/dev/cel/common/ast/BUILD.bazel +++ b/common/src/main/java/dev/cel/common/ast/BUILD.bazel @@ -31,6 +31,11 @@ EXPR_FACTORY_SOURCES = [ "CelExprIdGeneratorFactory.java", ] +# keep sorted +MUTABLE_AST_SOURCES = [ + "CelMutableExpr.java", +] + java_library( name = "ast", srcs = AST_SOURCES, @@ -109,3 +114,14 @@ java_library( "@maven//:com_google_guava_guava", ], ) + +java_library( + name = "mutable_ast", + srcs = MUTABLE_AST_SOURCES, + tags = [ + ], + deps = [ + ":ast", + "@maven//:com_google_guava_guava", + ], +) diff --git a/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java b/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java new file mode 100644 index 000000000..45e45852c --- /dev/null +++ b/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java @@ -0,0 +1,157 @@ +// Copyright 2024 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.common.ast; + +import static com.google.common.base.Preconditions.checkArgument; + +import dev.cel.common.ast.CelExpr.CelNotSet; +import dev.cel.common.ast.CelExpr.ExprKind; +import dev.cel.common.ast.CelExpr.ExprKind.Kind; + +/** + * An abstract representation of a common expression that allows mutation in any of its properties. + * The expressions are semantically the same as that of the immutable {@link CelExpr}. + * + *

This allows for an efficient optimization of an AST without having to traverse and rebuild the + * entire tree. + * + *

This class is not thread-safe by design. + */ +public final class CelMutableExpr { + private long id; + private ExprKind.Kind exprKind; + private CelNotSet notSet; + private CelConstant constant; + private int hash = 0; + + public long id() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public ExprKind.Kind getKind() { + return exprKind; + } + + public CelNotSet notSet() { + checkExprKind(Kind.NOT_SET); + return notSet; + } + + public CelConstant constant() { + checkExprKind(Kind.CONSTANT); + return constant; + } + + public void setConstant(CelConstant constant) { + this.exprKind = ExprKind.Kind.CONSTANT; + this.constant = constant; + } + + public static CelMutableExpr ofConstant(CelConstant constant) { + return ofConstant(0L, constant); + } + + public static CelMutableExpr ofConstant(long id, CelConstant constant) { + return new CelMutableExpr(id, constant); + } + + public static CelMutableExpr ofNotSet() { + return ofNotSet(0L); + } + + public static CelMutableExpr ofNotSet(long id) { + return new CelMutableExpr(id); + } + + private CelMutableExpr(long id, CelConstant mutableConstant) { + this.id = id; + setConstant(mutableConstant); + } + + private CelMutableExpr(long id) { + this(); + this.id = id; + } + + private CelMutableExpr() { + this.notSet = CelExpr.newBuilder().build().exprKind().notSet(); + this.exprKind = ExprKind.Kind.NOT_SET; + } + + private Object exprValue() { + switch (this.exprKind) { + case NOT_SET: + return notSet(); + case CONSTANT: + return constant(); + case IDENT: + case SELECT: + case CALL: + case CREATE_LIST: + case CREATE_STRUCT: + case CREATE_MAP: + case COMPREHENSION: + // fall-through (not implemented yet) + } + + throw new IllegalStateException("Unexpected expr kind: " + this.exprKind); + } + + private void checkExprKind(ExprKind.Kind exprKind) { + checkArgument(this.exprKind.equals(exprKind), "Invalid ExprKind: %s", exprKind); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof CelMutableExpr) { + CelMutableExpr that = (CelMutableExpr) obj; + if (this.id != that.id() || !this.exprKind.equals(that.getKind())) { + return false; + } + // When both objects' hashes are cached and they do not match, they can never be equal. + if (this.hash != 0 && that.hash != 0 && this.hash != that.hash) { + return false; + } + return this.exprValue().equals(that.exprValue()); + } + + return false; + } + + @Override + public int hashCode() { + if (hash == 0) { + int h = 1; + h *= 1000003; + h ^= (int) ((id >>> 32) ^ id); + h *= 1000003; + h ^= this.exprValue().hashCode(); + + if (h == 0) { + h = 1; + } + hash = h; + } + + return hash; + } +} diff --git a/common/src/test/java/dev/cel/common/ast/BUILD.bazel b/common/src/test/java/dev/cel/common/ast/BUILD.bazel index 595d516ee..4c74f4964 100644 --- a/common/src/test/java/dev/cel/common/ast/BUILD.bazel +++ b/common/src/test/java/dev/cel/common/ast/BUILD.bazel @@ -18,6 +18,7 @@ java_library( "//common/ast:expr_converter", "//common/ast:expr_factory", "//common/ast:expr_v1alpha1_converter", + "//common/ast:mutable_ast", "//common/resources/testdata/proto3:test_all_types_java_proto", "//common/types", "//compiler", @@ -28,6 +29,7 @@ java_library( "@cel_spec//proto/cel/expr:expr_java_proto", "@com_google_googleapis//google/api/expr/v1alpha1:expr_java_proto", "@maven//:com_google_guava_guava", + "@maven//:com_google_guava_guava_testlib", "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_testparameterinjector_test_parameter_injector", "@maven//:junit_junit", diff --git a/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java b/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java new file mode 100644 index 000000000..97304fd7d --- /dev/null +++ b/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java @@ -0,0 +1,126 @@ +// Copyright 2024 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.common.ast; + +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertThrows; + +import com.google.common.testing.EqualsTester; +import com.google.testing.junit.testparameterinjector.TestParameter; +import com.google.testing.junit.testparameterinjector.TestParameterInjector; +import dev.cel.common.ast.CelExpr.ExprKind.Kind; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(TestParameterInjector.class) +public class CelMutableExprTest { + + @Test + public void ofNotSet() { + CelMutableExpr mutableExpr = CelMutableExpr.ofNotSet(); + + assertThat(mutableExpr.id()).isEqualTo(0L); + assertThat(mutableExpr.notSet()).isNotNull(); + } + + @Test + public void ofNotSet_withId() { + CelMutableExpr mutableExpr = CelMutableExpr.ofNotSet(1L); + + assertThat(mutableExpr.id()).isEqualTo(1L); + assertThat(mutableExpr.notSet()).isNotNull(); + } + + @Test + public void ofConstant() { + CelMutableExpr mutableExpr = CelMutableExpr.ofConstant(CelConstant.ofValue(5L)); + + assertThat(mutableExpr.id()).isEqualTo(0L); + assertThat(mutableExpr.constant()).isEqualTo(CelConstant.ofValue(5L)); + } + + @Test + public void ofConstant_withId() { + CelMutableExpr mutableExpr = CelMutableExpr.ofConstant(1L, CelConstant.ofValue(5L)); + + assertThat(mutableExpr.id()).isEqualTo(1L); + assertThat(mutableExpr.constant()).isEqualTo(CelConstant.ofValue(5L)); + } + + @Test + public void setId_success() { + CelMutableExpr mutableExpr = CelMutableExpr.ofConstant(CelConstant.ofValue(5L)); + + mutableExpr.setId(2L); + + assertThat(mutableExpr.id()).isEqualTo(2L); + } + + @Test + public void equalityTest() { + new EqualsTester() + .addEqualityGroup(CelMutableExpr.ofNotSet()) + .addEqualityGroup(CelMutableExpr.ofNotSet(1L), CelMutableExpr.ofNotSet(1L)) + .addEqualityGroup(CelMutableExpr.ofConstant(1L, CelConstant.ofValue(2L))) + .addEqualityGroup( + CelMutableExpr.ofConstant(5L, CelConstant.ofValue("hello")), + CelMutableExpr.ofConstant(5L, CelConstant.ofValue("hello"))) + .testEquals(); + } + + @SuppressWarnings("Immutable") // Mutable by design + private enum MutableExprKindTestCase { + NOT_SET(CelMutableExpr.ofNotSet(1L)), + CONSTANT(CelMutableExpr.ofConstant(CelConstant.ofValue(2L))); + + private final CelMutableExpr mutableExpr; + + MutableExprKindTestCase(CelMutableExpr mutableExpr) { + this.mutableExpr = mutableExpr; + } + } + + @Test + public void getExprValue_invalidKind_throws(@TestParameter MutableExprKindTestCase testCase) { + Kind testCaseKind = testCase.mutableExpr.getKind(); + if (!testCaseKind.equals(Kind.NOT_SET)) { + assertThrows(IllegalArgumentException.class, testCase.mutableExpr::notSet); + } + if (!testCaseKind.equals(Kind.CONSTANT)) { + assertThrows(IllegalArgumentException.class, testCase.mutableExpr::constant); + } + } + + @SuppressWarnings("Immutable") // Mutable by design + private enum HashCodeTestCase { + NOT_SET(CelMutableExpr.ofNotSet(1L), -722379961), + CONSTANT(CelMutableExpr.ofConstant(2L, CelConstant.ofValue("test")), -724279919); + + private final CelMutableExpr mutableExpr; + private final int expectedHashCode; + + HashCodeTestCase(CelMutableExpr mutableExpr, int expectedHashCode) { + this.mutableExpr = mutableExpr; + this.expectedHashCode = expectedHashCode; + } + } + + @Test + public void hashCodeTest(@TestParameter HashCodeTestCase testCase) { + assertThat(testCase.mutableExpr.hashCode()).isEqualTo(testCase.expectedHashCode); + // Run it twice to ensure cached value is stable + assertThat(testCase.mutableExpr.hashCode()).isEqualTo(testCase.expectedHashCode); + } +} From 33a7b6f6a51a9dfde6897a4f2e907c316011a068 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Wed, 10 Apr 2024 15:14:19 -0700 Subject: [PATCH 072/486] Add CelMutableIdent PiperOrigin-RevId: 623619641 --- .../dev/cel/common/ast/CelMutableExpr.java | 75 +++++++++++++++++-- .../cel/common/ast/CelMutableExprTest.java | 39 +++++++++- 2 files changed, 107 insertions(+), 7 deletions(-) diff --git a/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java b/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java index 45e45852c..db3a6286a 100644 --- a/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java +++ b/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java @@ -15,6 +15,7 @@ package dev.cel.common.ast; import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; import dev.cel.common.ast.CelExpr.CelNotSet; import dev.cel.common.ast.CelExpr.ExprKind; @@ -34,6 +35,7 @@ public final class CelMutableExpr { private ExprKind.Kind exprKind; private CelNotSet notSet; private CelConstant constant; + private CelMutableIdent ident; private int hash = 0; public long id() { @@ -58,17 +60,58 @@ public CelConstant constant() { return constant; } + public CelMutableIdent ident() { + checkExprKind(Kind.IDENT); + return ident; + } + public void setConstant(CelConstant constant) { this.exprKind = ExprKind.Kind.CONSTANT; - this.constant = constant; + this.constant = checkNotNull(constant); } - public static CelMutableExpr ofConstant(CelConstant constant) { - return ofConstant(0L, constant); + public void setIdent(CelMutableIdent ident) { + this.exprKind = ExprKind.Kind.IDENT; + this.ident = checkNotNull(ident); } - public static CelMutableExpr ofConstant(long id, CelConstant constant) { - return new CelMutableExpr(id, constant); + /** A mutable identifier expression. */ + public static final class CelMutableIdent { + private String name = ""; + + public String name() { + return name; + } + + public void setName(String name) { + this.name = checkNotNull(name); + } + + public static CelMutableIdent create(String name) { + return new CelMutableIdent(name); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof CelMutableIdent) { + CelMutableIdent that = (CelMutableIdent) obj; + return this.name.equals(that.name); + } + + return false; + } + + @Override + public int hashCode() { + return name.hashCode(); + } + + private CelMutableIdent(String name) { + this.name = checkNotNull(name); + } } public static CelMutableExpr ofNotSet() { @@ -79,11 +122,32 @@ public static CelMutableExpr ofNotSet(long id) { return new CelMutableExpr(id); } + public static CelMutableExpr ofConstant(CelConstant constant) { + return ofConstant(0L, constant); + } + + public static CelMutableExpr ofConstant(long id, CelConstant constant) { + return new CelMutableExpr(id, constant); + } + + public static CelMutableExpr ofIdent(String name) { + return ofIdent(0, name); + } + + public static CelMutableExpr ofIdent(long id, String name) { + return new CelMutableExpr(id, CelMutableIdent.create(name)); + } + private CelMutableExpr(long id, CelConstant mutableConstant) { this.id = id; setConstant(mutableConstant); } + private CelMutableExpr(long id, CelMutableIdent mutableIdent) { + this.id = id; + setIdent(mutableIdent); + } + private CelMutableExpr(long id) { this(); this.id = id; @@ -101,6 +165,7 @@ private Object exprValue() { case CONSTANT: return constant(); case IDENT: + return ident(); case SELECT: case CALL: case CREATE_LIST: diff --git a/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java b/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java index 97304fd7d..3d44ac857 100644 --- a/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java +++ b/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java @@ -21,6 +21,7 @@ import com.google.testing.junit.testparameterinjector.TestParameter; import com.google.testing.junit.testparameterinjector.TestParameterInjector; import dev.cel.common.ast.CelExpr.ExprKind.Kind; +import dev.cel.common.ast.CelMutableExpr.CelMutableIdent; import org.junit.Test; import org.junit.runner.RunWith; @@ -59,6 +60,31 @@ public void ofConstant_withId() { assertThat(mutableExpr.constant()).isEqualTo(CelConstant.ofValue(5L)); } + @Test + public void ofIdent() { + CelMutableExpr mutableExpr = CelMutableExpr.ofIdent("x"); + + assertThat(mutableExpr.id()).isEqualTo(0L); + assertThat(mutableExpr.ident().name()).isEqualTo("x"); + } + + @Test + public void ofIdent_withId() { + CelMutableExpr mutableExpr = CelMutableExpr.ofIdent(1L, "x"); + + assertThat(mutableExpr.id()).isEqualTo(1L); + assertThat(mutableExpr.ident().name()).isEqualTo("x"); + } + + @Test + public void mutableIdent_setName() { + CelMutableIdent ident = CelMutableIdent.create("x"); + + ident.setName("y"); + + assertThat(ident.name()).isEqualTo("y"); + } + @Test public void setId_success() { CelMutableExpr mutableExpr = CelMutableExpr.ofConstant(CelConstant.ofValue(5L)); @@ -77,13 +103,17 @@ public void equalityTest() { .addEqualityGroup( CelMutableExpr.ofConstant(5L, CelConstant.ofValue("hello")), CelMutableExpr.ofConstant(5L, CelConstant.ofValue("hello"))) + .addEqualityGroup(CelMutableExpr.ofIdent("x")) + .addEqualityGroup(CelMutableExpr.ofIdent(2L, "y"), CelMutableExpr.ofIdent(2L, "y")) .testEquals(); } @SuppressWarnings("Immutable") // Mutable by design private enum MutableExprKindTestCase { NOT_SET(CelMutableExpr.ofNotSet(1L)), - CONSTANT(CelMutableExpr.ofConstant(CelConstant.ofValue(2L))); + CONSTANT(CelMutableExpr.ofConstant(CelConstant.ofValue(2L))), + IDENT(CelMutableExpr.ofIdent("test")), + ; private final CelMutableExpr mutableExpr; @@ -101,12 +131,17 @@ public void getExprValue_invalidKind_throws(@TestParameter MutableExprKindTestCa if (!testCaseKind.equals(Kind.CONSTANT)) { assertThrows(IllegalArgumentException.class, testCase.mutableExpr::constant); } + if (!testCaseKind.equals(Kind.IDENT)) { + assertThrows(IllegalArgumentException.class, testCase.mutableExpr::ident); + } } @SuppressWarnings("Immutable") // Mutable by design private enum HashCodeTestCase { NOT_SET(CelMutableExpr.ofNotSet(1L), -722379961), - CONSTANT(CelMutableExpr.ofConstant(2L, CelConstant.ofValue("test")), -724279919); + CONSTANT(CelMutableExpr.ofConstant(2L, CelConstant.ofValue("test")), -724279919), + IDENT(CelMutableExpr.ofIdent("x"), -721379855), + ; private final CelMutableExpr mutableExpr; private final int expectedHashCode; From facc16e0472ad2852c8ae2de1db4055c4865689d Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Wed, 10 Apr 2024 15:34:08 -0700 Subject: [PATCH 073/486] Add CelMutableSelect PiperOrigin-RevId: 623625147 --- .../dev/cel/common/ast/CelMutableExpr.java | 96 +++++++++++++++++++ .../cel/common/ast/CelMutableExprTest.java | 55 +++++++++++ 2 files changed, 151 insertions(+) diff --git a/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java b/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java index db3a6286a..58780e445 100644 --- a/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java +++ b/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java @@ -36,6 +36,7 @@ public final class CelMutableExpr { private CelNotSet notSet; private CelConstant constant; private CelMutableIdent ident; + private CelMutableSelect select; private int hash = 0; public long id() { @@ -65,6 +66,11 @@ public CelMutableIdent ident() { return ident; } + public CelMutableSelect select() { + checkExprKind(Kind.SELECT); + return select; + } + public void setConstant(CelConstant constant) { this.exprKind = ExprKind.Kind.CONSTANT; this.constant = checkNotNull(constant); @@ -75,6 +81,11 @@ public void setIdent(CelMutableIdent ident) { this.ident = checkNotNull(ident); } + public void setSelect(CelMutableSelect select) { + this.exprKind = ExprKind.Kind.SELECT; + this.select = checkNotNull(select); + } + /** A mutable identifier expression. */ public static final class CelMutableIdent { private String name = ""; @@ -114,6 +125,77 @@ private CelMutableIdent(String name) { } } + /** A mutable field selection expression. e.g. `request.auth`. */ + public static final class CelMutableSelect { + private CelMutableExpr operand; + private String field = ""; + private boolean testOnly; + + public CelMutableExpr operand() { + return operand; + } + + public void setOperand(CelMutableExpr operand) { + this.operand = checkNotNull(operand); + } + + public String field() { + return field; + } + + public void setField(String field) { + this.field = checkNotNull(field); + } + + public boolean testOnly() { + return testOnly; + } + + public void setTestOnly(boolean testOnly) { + this.testOnly = testOnly; + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof CelMutableSelect) { + CelMutableSelect that = (CelMutableSelect) obj; + return this.operand.equals(that.operand()) + && this.field.equals(that.field()) + && this.testOnly == that.testOnly(); + } + return false; + } + + @Override + public int hashCode() { + int h = 1; + h *= 1000003; + h ^= operand.hashCode(); + h *= 1000003; + h ^= field.hashCode(); + h *= 1000003; + h ^= testOnly ? 1231 : 1237; + return h; + } + + public static CelMutableSelect create(CelMutableExpr operand, String field) { + return new CelMutableSelect(operand, field, false); + } + + public static CelMutableSelect create(CelMutableExpr operand, String field, boolean testOnly) { + return new CelMutableSelect(operand, field, testOnly); + } + + private CelMutableSelect(CelMutableExpr operand, String field, boolean testOnly) { + this.operand = checkNotNull(operand); + this.field = checkNotNull(field); + this.testOnly = testOnly; + } + } + public static CelMutableExpr ofNotSet() { return ofNotSet(0L); } @@ -138,6 +220,14 @@ public static CelMutableExpr ofIdent(long id, String name) { return new CelMutableExpr(id, CelMutableIdent.create(name)); } + public static CelMutableExpr ofSelect(CelMutableSelect mutableSelect) { + return ofSelect(0, mutableSelect); + } + + public static CelMutableExpr ofSelect(long id, CelMutableSelect mutableSelect) { + return new CelMutableExpr(id, mutableSelect); + } + private CelMutableExpr(long id, CelConstant mutableConstant) { this.id = id; setConstant(mutableConstant); @@ -148,6 +238,11 @@ private CelMutableExpr(long id, CelMutableIdent mutableIdent) { setIdent(mutableIdent); } + private CelMutableExpr(long id, CelMutableSelect mutableSelect) { + this.id = id; + setSelect(mutableSelect); + } + private CelMutableExpr(long id) { this(); this.id = id; @@ -167,6 +262,7 @@ private Object exprValue() { case IDENT: return ident(); case SELECT: + return select(); case CALL: case CREATE_LIST: case CREATE_STRUCT: diff --git a/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java b/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java index 3d44ac857..73d595c66 100644 --- a/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java +++ b/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java @@ -22,6 +22,7 @@ import com.google.testing.junit.testparameterinjector.TestParameterInjector; import dev.cel.common.ast.CelExpr.ExprKind.Kind; import dev.cel.common.ast.CelMutableExpr.CelMutableIdent; +import dev.cel.common.ast.CelMutableExpr.CelMutableSelect; import org.junit.Test; import org.junit.runner.RunWith; @@ -85,6 +86,44 @@ public void mutableIdent_setName() { assertThat(ident.name()).isEqualTo("y"); } + @Test + public void ofSelect() { + CelMutableExpr mutableExpr = + CelMutableExpr.ofSelect(CelMutableSelect.create(CelMutableExpr.ofIdent("x"), "field")); + + assertThat(mutableExpr.id()).isEqualTo(0L); + assertThat(mutableExpr.select().testOnly()).isFalse(); + assertThat(mutableExpr.select().field()).isEqualTo("field"); + assertThat(mutableExpr.select().operand()).isEqualTo(CelMutableExpr.ofIdent("x")); + } + + @Test + public void ofSelect_withId() { + CelMutableExpr mutableExpr = + CelMutableExpr.ofSelect( + 1L, + CelMutableSelect.create(CelMutableExpr.ofIdent("x"), "field", /* testOnly= */ true)); + + assertThat(mutableExpr.id()).isEqualTo(1L); + assertThat(mutableExpr.select().testOnly()).isTrue(); + assertThat(mutableExpr.select().field()).isEqualTo("field"); + assertThat(mutableExpr.select().operand()).isEqualTo(CelMutableExpr.ofIdent("x")); + } + + @Test + public void mutableSelect_setters() { + CelMutableSelect select = + CelMutableSelect.create(CelMutableExpr.ofIdent("x"), "field", /* testOnly= */ true); + + select.setOperand(CelMutableExpr.ofConstant(CelConstant.ofValue(1L))); + select.setField("field2"); + select.setTestOnly(false); + + assertThat(select.operand()).isEqualTo(CelMutableExpr.ofConstant(CelConstant.ofValue(1L))); + assertThat(select.field()).isEqualTo("field2"); + assertThat(select.testOnly()).isFalse(); + } + @Test public void setId_success() { CelMutableExpr mutableExpr = CelMutableExpr.ofConstant(CelConstant.ofValue(5L)); @@ -105,6 +144,13 @@ public void equalityTest() { CelMutableExpr.ofConstant(5L, CelConstant.ofValue("hello"))) .addEqualityGroup(CelMutableExpr.ofIdent("x")) .addEqualityGroup(CelMutableExpr.ofIdent(2L, "y"), CelMutableExpr.ofIdent(2L, "y")) + .addEqualityGroup( + CelMutableExpr.ofSelect(CelMutableSelect.create(CelMutableExpr.ofIdent("y"), "field"))) + .addEqualityGroup( + CelMutableExpr.ofSelect( + 4L, CelMutableSelect.create(CelMutableExpr.ofIdent("x"), "test")), + CelMutableExpr.ofSelect( + 4L, CelMutableSelect.create(CelMutableExpr.ofIdent("x"), "test"))) .testEquals(); } @@ -113,6 +159,7 @@ private enum MutableExprKindTestCase { NOT_SET(CelMutableExpr.ofNotSet(1L)), CONSTANT(CelMutableExpr.ofConstant(CelConstant.ofValue(2L))), IDENT(CelMutableExpr.ofIdent("test")), + SELECT(CelMutableExpr.ofSelect(CelMutableSelect.create(CelMutableExpr.ofNotSet(), "field"))), ; private final CelMutableExpr mutableExpr; @@ -134,6 +181,9 @@ public void getExprValue_invalidKind_throws(@TestParameter MutableExprKindTestCa if (!testCaseKind.equals(Kind.IDENT)) { assertThrows(IllegalArgumentException.class, testCase.mutableExpr::ident); } + if (!testCaseKind.equals(Kind.SELECT)) { + assertThrows(IllegalArgumentException.class, testCase.mutableExpr::select); + } } @SuppressWarnings("Immutable") // Mutable by design @@ -141,6 +191,11 @@ private enum HashCodeTestCase { NOT_SET(CelMutableExpr.ofNotSet(1L), -722379961), CONSTANT(CelMutableExpr.ofConstant(2L, CelConstant.ofValue("test")), -724279919), IDENT(CelMutableExpr.ofIdent("x"), -721379855), + SELECT( + CelMutableExpr.ofSelect( + 4L, + CelMutableSelect.create(CelMutableExpr.ofIdent("y"), "field", /* testOnly= */ true)), + 1458249843), ; private final CelMutableExpr mutableExpr; From d7b7a3097e251091b3d1050ebed27319bf387b4e Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Wed, 10 Apr 2024 15:55:20 -0700 Subject: [PATCH 074/486] Add CelMutableCall PiperOrigin-RevId: 623630568 --- .../dev/cel/common/ast/CelMutableExpr.java | 134 ++++++++++++++++ .../cel/common/ast/CelMutableExprTest.java | 143 ++++++++++++++++++ 2 files changed, 277 insertions(+) diff --git a/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java b/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java index 58780e445..1cdf32804 100644 --- a/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java +++ b/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java @@ -20,6 +20,11 @@ import dev.cel.common.ast.CelExpr.CelNotSet; import dev.cel.common.ast.CelExpr.ExprKind; import dev.cel.common.ast.CelExpr.ExprKind.Kind; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Optional; /** * An abstract representation of a common expression that allows mutation in any of its properties. @@ -37,6 +42,7 @@ public final class CelMutableExpr { private CelConstant constant; private CelMutableIdent ident; private CelMutableSelect select; + private CelMutableCall call; private int hash = 0; public long id() { @@ -71,6 +77,11 @@ public CelMutableSelect select() { return select; } + public CelMutableCall call() { + checkExprKind(Kind.CALL); + return call; + } + public void setConstant(CelConstant constant) { this.exprKind = ExprKind.Kind.CONSTANT; this.constant = checkNotNull(constant); @@ -86,6 +97,11 @@ public void setSelect(CelMutableSelect select) { this.select = checkNotNull(select); } + public void setCall(CelMutableCall call) { + this.exprKind = ExprKind.Kind.CALL; + this.call = checkNotNull(call); + } + /** A mutable identifier expression. */ public static final class CelMutableIdent { private String name = ""; @@ -196,6 +212,110 @@ private CelMutableSelect(CelMutableExpr operand, String field, boolean testOnly) } } + /** A mutable call expression, including calls to predefined functions and operators. */ + public static final class CelMutableCall { + private Optional target; + private String function; + private List args; + + public Optional target() { + return target; + } + + public void setTarget(CelMutableExpr target) { + this.target = Optional.of(target); + } + + public String function() { + return function; + } + + public void setFunction(String function) { + this.function = checkNotNull(function); + } + + public List args() { + return args; + } + + public void clearArgs() { + args.clear(); + } + + public void addArgs(CelMutableExpr... exprs) { + addArgs(Arrays.asList(checkNotNull(exprs))); + } + + public void addArgs(Iterable exprs) { + exprs.forEach(e -> args.add(checkNotNull(e))); + } + + public void setArgs(Collection exprs) { + this.args = new ArrayList<>(checkNotNull(exprs)); + } + + public void setArg(int index, CelMutableExpr arg) { + checkArgument(index >= 0 && index < args.size()); + args.set(index, checkNotNull(arg)); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof CelMutableCall) { + CelMutableCall that = (CelMutableCall) obj; + return this.target.equals(that.target()) + && this.function.equals(that.function()) + && this.args.equals(that.args()); + } + + return false; + } + + @Override + public int hashCode() { + int h = 1; + h *= 1000003; + h ^= target.hashCode(); + h *= 1000003; + h ^= function.hashCode(); + h *= 1000003; + h ^= args.hashCode(); + return h; + } + + public static CelMutableCall create(String function, CelMutableExpr... args) { + return create(function, Arrays.asList(checkNotNull(args))); + } + + public static CelMutableCall create(String function, List args) { + return new CelMutableCall(function, args); + } + + public static CelMutableCall create( + CelMutableExpr target, String function, CelMutableExpr... args) { + return create(target, function, Arrays.asList(checkNotNull(args))); + } + + public static CelMutableCall create( + CelMutableExpr target, String function, List args) { + return new CelMutableCall(target, function, args); + } + + private CelMutableCall(String function, List args) { + this.target = Optional.empty(); + this.function = checkNotNull(function); + this.args = new ArrayList<>(checkNotNull(args)); + } + + private CelMutableCall(CelMutableExpr target, String function, List args) { + this(function, args); + this.target = Optional.of(target); + } + } + public static CelMutableExpr ofNotSet() { return ofNotSet(0L); } @@ -228,6 +348,14 @@ public static CelMutableExpr ofSelect(long id, CelMutableSelect mutableSelect) { return new CelMutableExpr(id, mutableSelect); } + public static CelMutableExpr ofCall(CelMutableCall mutableCall) { + return ofCall(0, mutableCall); + } + + public static CelMutableExpr ofCall(long id, CelMutableCall mutableCall) { + return new CelMutableExpr(id, mutableCall); + } + private CelMutableExpr(long id, CelConstant mutableConstant) { this.id = id; setConstant(mutableConstant); @@ -243,6 +371,11 @@ private CelMutableExpr(long id, CelMutableSelect mutableSelect) { setSelect(mutableSelect); } + private CelMutableExpr(long id, CelMutableCall mutableCall) { + this.id = id; + setCall(mutableCall); + } + private CelMutableExpr(long id) { this(); this.id = id; @@ -264,6 +397,7 @@ private Object exprValue() { case SELECT: return select(); case CALL: + return call(); case CREATE_LIST: case CREATE_STRUCT: case CREATE_MAP: diff --git a/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java b/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java index 73d595c66..dc207c655 100644 --- a/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java +++ b/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java @@ -17,12 +17,15 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertThrows; +import com.google.common.collect.ImmutableList; import com.google.common.testing.EqualsTester; import com.google.testing.junit.testparameterinjector.TestParameter; import com.google.testing.junit.testparameterinjector.TestParameterInjector; import dev.cel.common.ast.CelExpr.ExprKind.Kind; +import dev.cel.common.ast.CelMutableExpr.CelMutableCall; import dev.cel.common.ast.CelMutableExpr.CelMutableIdent; import dev.cel.common.ast.CelMutableExpr.CelMutableSelect; +import java.util.ArrayList; import org.junit.Test; import org.junit.runner.RunWith; @@ -124,6 +127,41 @@ public void mutableSelect_setters() { assertThat(select.testOnly()).isFalse(); } + @Test + public void ofCall() { + CelMutableExpr mutableExpr = + CelMutableExpr.ofCall( + CelMutableCall.create( + CelMutableExpr.ofConstant(CelConstant.ofValue("target")), + "function", + CelMutableExpr.ofConstant(CelConstant.ofValue("arg")))); + + assertThat(mutableExpr.id()).isEqualTo(0L); + assertThat(mutableExpr.call().target()) + .hasValue(CelMutableExpr.ofConstant(CelConstant.ofValue("target"))); + assertThat(mutableExpr.call().function()).isEqualTo("function"); + assertThat(mutableExpr.call().args()) + .containsExactly(CelMutableExpr.ofConstant(CelConstant.ofValue("arg"))); + } + + @Test + public void ofCall_withId() { + CelMutableExpr mutableExpr = + CelMutableExpr.ofCall( + 1L, + CelMutableCall.create( + CelMutableExpr.ofConstant(CelConstant.ofValue("target")), + "function", + CelMutableExpr.ofConstant(CelConstant.ofValue("arg")))); + + assertThat(mutableExpr.id()).isEqualTo(1L); + assertThat(mutableExpr.call().target()) + .hasValue(CelMutableExpr.ofConstant(CelConstant.ofValue("target"))); + assertThat(mutableExpr.call().function()).isEqualTo("function"); + assertThat(mutableExpr.call().args()) + .containsExactly(CelMutableExpr.ofConstant(CelConstant.ofValue("arg"))); + } + @Test public void setId_success() { CelMutableExpr mutableExpr = CelMutableExpr.ofConstant(CelConstant.ofValue(5L)); @@ -133,6 +171,85 @@ public void setId_success() { assertThat(mutableExpr.id()).isEqualTo(2L); } + @Test + public void mutableCall_setArgumentAtIndex() { + CelMutableCall call = + CelMutableCall.create("function", CelMutableExpr.ofConstant(CelConstant.ofValue(1L))); + + call.setArg(0, CelMutableExpr.ofConstant(CelConstant.ofValue("hello"))); + + assertThat(call.args()) + .containsExactly(CelMutableExpr.ofConstant(CelConstant.ofValue("hello"))); + assertThat(call.args()).isInstanceOf(ArrayList.class); + } + + @Test + public void mutableCall_setArguments() { + CelMutableCall call = + CelMutableCall.create("function", CelMutableExpr.ofConstant(CelConstant.ofValue(1L))); + + call.setArgs( + ImmutableList.of( + CelMutableExpr.ofConstant(CelConstant.ofValue(2)), + CelMutableExpr.ofConstant(CelConstant.ofValue(3)))); + + assertThat(call.args()) + .containsExactly( + CelMutableExpr.ofConstant(CelConstant.ofValue(2)), + CelMutableExpr.ofConstant(CelConstant.ofValue(3))) + .inOrder(); + assertThat(call.args()).isInstanceOf(ArrayList.class); + } + + @Test + public void mutableCall_addArguments() { + CelMutableCall call = + CelMutableCall.create("function", CelMutableExpr.ofConstant(CelConstant.ofValue(1L))); + + call.addArgs( + CelMutableExpr.ofConstant(CelConstant.ofValue(2)), + CelMutableExpr.ofConstant(CelConstant.ofValue(3))); + + assertThat(call.args()) + .containsExactly( + CelMutableExpr.ofConstant(CelConstant.ofValue(1)), + CelMutableExpr.ofConstant(CelConstant.ofValue(2)), + CelMutableExpr.ofConstant(CelConstant.ofValue(3))) + .inOrder(); + assertThat(call.args()).isInstanceOf(ArrayList.class); + } + + @Test + public void mutableCall_clearArguments() { + CelMutableCall call = + CelMutableCall.create( + "function", + CelMutableExpr.ofConstant(CelConstant.ofValue(1L)), + CelMutableExpr.ofConstant(CelConstant.ofValue(2L))); + + call.clearArgs(); + + assertThat(call.args()).isEmpty(); + } + + @Test + public void mutableCall_setTarget() { + CelMutableCall call = CelMutableCall.create("function"); + + call.setTarget(CelMutableExpr.ofConstant(CelConstant.ofValue("hello"))); + + assertThat(call.target()).hasValue(CelMutableExpr.ofConstant(CelConstant.ofValue("hello"))); + } + + @Test + public void mutableCall_setFunction() { + CelMutableCall call = CelMutableCall.create("function"); + + call.setFunction("function2"); + + assertThat(call.function()).isEqualTo("function2"); + } + @Test public void equalityTest() { new EqualsTester() @@ -151,6 +268,20 @@ public void equalityTest() { 4L, CelMutableSelect.create(CelMutableExpr.ofIdent("x"), "test")), CelMutableExpr.ofSelect( 4L, CelMutableSelect.create(CelMutableExpr.ofIdent("x"), "test"))) + .addEqualityGroup(CelMutableExpr.ofCall(CelMutableCall.create("function"))) + .addEqualityGroup( + CelMutableExpr.ofCall( + 5L, + CelMutableCall.create( + CelMutableExpr.ofConstant(CelConstant.ofValue("target")), + "function", + CelMutableExpr.ofConstant(CelConstant.ofValue("arg")))), + CelMutableExpr.ofCall( + 5L, + CelMutableCall.create( + CelMutableExpr.ofConstant(CelConstant.ofValue("target")), + "function", + CelMutableExpr.ofConstant(CelConstant.ofValue("arg"))))) .testEquals(); } @@ -160,6 +291,7 @@ private enum MutableExprKindTestCase { CONSTANT(CelMutableExpr.ofConstant(CelConstant.ofValue(2L))), IDENT(CelMutableExpr.ofIdent("test")), SELECT(CelMutableExpr.ofSelect(CelMutableSelect.create(CelMutableExpr.ofNotSet(), "field"))), + CALL(CelMutableExpr.ofCall(CelMutableCall.create("call"))), ; private final CelMutableExpr mutableExpr; @@ -184,6 +316,9 @@ public void getExprValue_invalidKind_throws(@TestParameter MutableExprKindTestCa if (!testCaseKind.equals(Kind.SELECT)) { assertThrows(IllegalArgumentException.class, testCase.mutableExpr::select); } + if (!testCaseKind.equals(Kind.CALL)) { + assertThrows(IllegalArgumentException.class, testCase.mutableExpr::call); + } } @SuppressWarnings("Immutable") // Mutable by design @@ -196,6 +331,14 @@ private enum HashCodeTestCase { 4L, CelMutableSelect.create(CelMutableExpr.ofIdent("y"), "field", /* testOnly= */ true)), 1458249843), + CALL( + CelMutableExpr.ofCall( + 5L, + CelMutableCall.create( + CelMutableExpr.ofConstant(CelConstant.ofValue("target")), + "function", + CelMutableExpr.ofConstant(CelConstant.ofValue("arg")))), + -1735261193), ; private final CelMutableExpr mutableExpr; From 1707b45e7347ae4d26c05552e3dd5783c3b4dbeb Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Thu, 11 Apr 2024 09:52:56 -0700 Subject: [PATCH 075/486] Add CelMutableCreateList PiperOrigin-RevId: 623856014 --- .../dev/cel/common/ast/CelMutableExpr.java | 93 +++++++++++++++++++ .../cel/common/ast/CelMutableExprTest.java | 74 ++++++++++++++- 2 files changed, 166 insertions(+), 1 deletion(-) diff --git a/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java b/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java index 1cdf32804..91602441a 100644 --- a/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java +++ b/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java @@ -43,6 +43,7 @@ public final class CelMutableExpr { private CelMutableIdent ident; private CelMutableSelect select; private CelMutableCall call; + private CelMutableCreateList createList; private int hash = 0; public long id() { @@ -82,6 +83,11 @@ public CelMutableCall call() { return call; } + public CelMutableCreateList createList() { + checkExprKind(Kind.CREATE_LIST); + return createList; + } + public void setConstant(CelConstant constant) { this.exprKind = ExprKind.Kind.CONSTANT; this.constant = checkNotNull(constant); @@ -102,6 +108,11 @@ public void setCall(CelMutableCall call) { this.call = checkNotNull(call); } + public void setCreateList(CelMutableCreateList createList) { + this.exprKind = ExprKind.Kind.CREATE_LIST; + this.createList = checkNotNull(createList); + } + /** A mutable identifier expression. */ public static final class CelMutableIdent { private String name = ""; @@ -316,6 +327,74 @@ private CelMutableCall(CelMutableExpr target, String function, ListLists may either be homogenous, e.g. `[1, 2, 3]`, or heterogeneous, e.g. `dyn([1, 'hello', + * 2.0])` + */ + public static final class CelMutableCreateList { + private final List elements; + private final List optionalIndices; + + public List elements() { + return elements; + } + + public void setElement(int index, CelMutableExpr element) { + checkArgument(index >= 0 && index < elements().size()); + elements.set(index, checkNotNull(element)); + } + + public List optionalIndices() { + return optionalIndices; + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof CelMutableCreateList) { + CelMutableCreateList that = (CelMutableCreateList) obj; + return this.elements.equals(that.elements()) + && this.optionalIndices.equals(that.optionalIndices()); + } + + return false; + } + + @Override + public int hashCode() { + int h = 1; + h *= 1000003; + h ^= elements.hashCode(); + h *= 1000003; + h ^= optionalIndices.hashCode(); + + return h; + } + + public static CelMutableCreateList create(CelMutableExpr... elements) { + return create(Arrays.asList(checkNotNull(elements))); + } + + public static CelMutableCreateList create(List elements) { + return create(elements, new ArrayList<>()); + } + + public static CelMutableCreateList create( + List mutableExprList, List optionalIndices) { + return new CelMutableCreateList(mutableExprList, optionalIndices); + } + + private CelMutableCreateList( + List mutableExprList, List optionalIndices) { + this.elements = new ArrayList<>(checkNotNull(mutableExprList)); + this.optionalIndices = new ArrayList<>(checkNotNull(optionalIndices)); + } + } + public static CelMutableExpr ofNotSet() { return ofNotSet(0L); } @@ -356,6 +435,14 @@ public static CelMutableExpr ofCall(long id, CelMutableCall mutableCall) { return new CelMutableExpr(id, mutableCall); } + public static CelMutableExpr ofCreateList(CelMutableCreateList mutableCreateList) { + return ofCreateList(0, mutableCreateList); + } + + public static CelMutableExpr ofCreateList(long id, CelMutableCreateList mutableCreateList) { + return new CelMutableExpr(id, mutableCreateList); + } + private CelMutableExpr(long id, CelConstant mutableConstant) { this.id = id; setConstant(mutableConstant); @@ -376,6 +463,11 @@ private CelMutableExpr(long id, CelMutableCall mutableCall) { setCall(mutableCall); } + private CelMutableExpr(long id, CelMutableCreateList mutableCreateList) { + this.id = id; + setCreateList(mutableCreateList); + } + private CelMutableExpr(long id) { this(); this.id = id; @@ -399,6 +491,7 @@ private Object exprValue() { case CALL: return call(); case CREATE_LIST: + return createList(); case CREATE_STRUCT: case CREATE_MAP: case COMPREHENSION: diff --git a/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java b/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java index dc207c655..5f984b301 100644 --- a/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java +++ b/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java @@ -23,6 +23,7 @@ import com.google.testing.junit.testparameterinjector.TestParameterInjector; import dev.cel.common.ast.CelExpr.ExprKind.Kind; import dev.cel.common.ast.CelMutableExpr.CelMutableCall; +import dev.cel.common.ast.CelMutableExpr.CelMutableCreateList; import dev.cel.common.ast.CelMutableExpr.CelMutableIdent; import dev.cel.common.ast.CelMutableExpr.CelMutableSelect; import java.util.ArrayList; @@ -250,6 +251,55 @@ public void mutableCall_setFunction() { assertThat(call.function()).isEqualTo("function2"); } + @Test + public void ofCreateList() { + CelMutableExpr mutableExpr = + CelMutableExpr.ofCreateList( + CelMutableCreateList.create( + CelMutableExpr.ofConstant(CelConstant.ofValue("element1")), + CelMutableExpr.ofConstant(CelConstant.ofValue("element2")))); + + assertThat(mutableExpr.id()).isEqualTo(0L); + assertThat(mutableExpr.createList().elements()) + .containsExactly( + CelMutableExpr.ofConstant(CelConstant.ofValue("element1")), + CelMutableExpr.ofConstant(CelConstant.ofValue("element2"))) + .inOrder(); + assertThat(mutableExpr.createList().optionalIndices()).isEmpty(); + } + + @Test + public void ofCreateList_withId() { + CelMutableExpr mutableExpr = + CelMutableExpr.ofCreateList( + 1L, + CelMutableCreateList.create( + ImmutableList.of( + CelMutableExpr.ofConstant(CelConstant.ofValue("element1")), + CelMutableExpr.ofConstant(CelConstant.ofValue("element2"))), + ImmutableList.of(0, 1))); + + assertThat(mutableExpr.id()).isEqualTo(1L); + assertThat(mutableExpr.createList().elements()) + .containsExactly( + CelMutableExpr.ofConstant(CelConstant.ofValue("element1")), + CelMutableExpr.ofConstant(CelConstant.ofValue("element2"))) + .inOrder(); + assertThat(mutableExpr.createList().optionalIndices()).containsExactly(0, 1).inOrder(); + } + + @Test + public void mutableCreateList_setElementAtIndex() { + CelMutableCreateList createList = + CelMutableCreateList.create(CelMutableExpr.ofConstant(CelConstant.ofValue("element1"))); + + createList.setElement(0, CelMutableExpr.ofConstant(CelConstant.ofValue("hello"))); + + assertThat(createList.elements()) + .containsExactly(CelMutableExpr.ofConstant(CelConstant.ofValue("hello"))); + assertThat(createList.elements()).isInstanceOf(ArrayList.class); + } + @Test public void equalityTest() { new EqualsTester() @@ -282,6 +332,18 @@ public void equalityTest() { CelMutableExpr.ofConstant(CelConstant.ofValue("target")), "function", CelMutableExpr.ofConstant(CelConstant.ofValue("arg"))))) + .addEqualityGroup(CelMutableExpr.ofCreateList(CelMutableCreateList.create())) + .addEqualityGroup( + CelMutableExpr.ofCreateList( + 6L, + CelMutableCreateList.create( + CelMutableExpr.ofConstant(CelConstant.ofValue("element1")), + CelMutableExpr.ofConstant(CelConstant.ofValue("element2")))), + CelMutableExpr.ofCreateList( + 6L, + CelMutableCreateList.create( + CelMutableExpr.ofConstant(CelConstant.ofValue("element1")), + CelMutableExpr.ofConstant(CelConstant.ofValue("element2"))))) .testEquals(); } @@ -292,7 +354,7 @@ private enum MutableExprKindTestCase { IDENT(CelMutableExpr.ofIdent("test")), SELECT(CelMutableExpr.ofSelect(CelMutableSelect.create(CelMutableExpr.ofNotSet(), "field"))), CALL(CelMutableExpr.ofCall(CelMutableCall.create("call"))), - ; + CREATE_LIST(CelMutableExpr.ofCreateList(CelMutableCreateList.create())); private final CelMutableExpr mutableExpr; @@ -319,6 +381,9 @@ public void getExprValue_invalidKind_throws(@TestParameter MutableExprKindTestCa if (!testCaseKind.equals(Kind.CALL)) { assertThrows(IllegalArgumentException.class, testCase.mutableExpr::call); } + if (!testCaseKind.equals(Kind.CREATE_LIST)) { + assertThrows(IllegalArgumentException.class, testCase.mutableExpr::createList); + } } @SuppressWarnings("Immutable") // Mutable by design @@ -339,6 +404,13 @@ private enum HashCodeTestCase { "function", CelMutableExpr.ofConstant(CelConstant.ofValue("arg")))), -1735261193), + CREATE_LIST( + CelMutableExpr.ofCreateList( + 6L, + CelMutableCreateList.create( + CelMutableExpr.ofConstant(CelConstant.ofValue("element1")), + CelMutableExpr.ofConstant(CelConstant.ofValue("element2")))), + 165341403), ; private final CelMutableExpr mutableExpr; From 2eb0c1fbe3c0d22adfeb32ae2a47c694516f7823 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Thu, 11 Apr 2024 10:36:18 -0700 Subject: [PATCH 076/486] Add CelMutableCreateStruct PiperOrigin-RevId: 623869827 --- .../dev/cel/common/ast/CelMutableExpr.java | 204 ++++++++++++++++-- .../cel/common/ast/CelMutableExprTest.java | 117 +++++++++- 2 files changed, 302 insertions(+), 19 deletions(-) diff --git a/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java b/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java index 91602441a..1a04ef513 100644 --- a/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java +++ b/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java @@ -38,12 +38,7 @@ public final class CelMutableExpr { private long id; private ExprKind.Kind exprKind; - private CelNotSet notSet; - private CelConstant constant; - private CelMutableIdent ident; - private CelMutableSelect select; - private CelMutableCall call; - private CelMutableCreateList createList; + private Object exprValue; private int hash = 0; public long id() { @@ -60,57 +55,67 @@ public ExprKind.Kind getKind() { public CelNotSet notSet() { checkExprKind(Kind.NOT_SET); - return notSet; + return (CelNotSet) exprValue; } public CelConstant constant() { checkExprKind(Kind.CONSTANT); - return constant; + return (CelConstant) exprValue; } public CelMutableIdent ident() { checkExprKind(Kind.IDENT); - return ident; + return (CelMutableIdent) exprValue; } public CelMutableSelect select() { checkExprKind(Kind.SELECT); - return select; + return (CelMutableSelect) exprValue; } public CelMutableCall call() { checkExprKind(Kind.CALL); - return call; + return (CelMutableCall) exprValue; } public CelMutableCreateList createList() { checkExprKind(Kind.CREATE_LIST); - return createList; + return (CelMutableCreateList) exprValue; + } + + public CelMutableCreateStruct createStruct() { + checkExprKind(Kind.CREATE_STRUCT); + return (CelMutableCreateStruct) exprValue; } public void setConstant(CelConstant constant) { this.exprKind = ExprKind.Kind.CONSTANT; - this.constant = checkNotNull(constant); + this.exprValue = checkNotNull(constant); } public void setIdent(CelMutableIdent ident) { this.exprKind = ExprKind.Kind.IDENT; - this.ident = checkNotNull(ident); + this.exprValue = checkNotNull(ident); } public void setSelect(CelMutableSelect select) { this.exprKind = ExprKind.Kind.SELECT; - this.select = checkNotNull(select); + this.exprValue = checkNotNull(select); } public void setCall(CelMutableCall call) { this.exprKind = ExprKind.Kind.CALL; - this.call = checkNotNull(call); + this.exprValue = checkNotNull(call); } public void setCreateList(CelMutableCreateList createList) { this.exprKind = ExprKind.Kind.CREATE_LIST; - this.createList = checkNotNull(createList); + this.exprValue = checkNotNull(createList); + } + + public void setCreateStruct(CelMutableCreateStruct createStruct) { + this.exprKind = ExprKind.Kind.CREATE_STRUCT; + this.exprValue = checkNotNull(createStruct); } /** A mutable identifier expression. */ @@ -395,6 +400,155 @@ private CelMutableCreateList( } } + /** + * A mutable list creation expression. + * + *

Lists may either be homogenous, e.g. `[1, 2, 3]`, or heterogeneous, e.g. `dyn([1, 'hello', + * 2.0])` + */ + public static final class CelMutableCreateStruct { + private String messageName = ""; + private List entries; + + public String messageName() { + return messageName; + } + + public void setMessageName(String messageName) { + this.messageName = checkNotNull(messageName); + } + + public List entries() { + return entries; + } + + public void setEntries(List entries) { + this.entries = checkNotNull(entries); + } + + public void setEntry(int index, CelMutableCreateStruct.Entry entry) { + checkArgument(index >= 0 && index < entries().size()); + entries.set(index, checkNotNull(entry)); + } + + /** Represents a mutable entry of the struct */ + public static final class Entry { + private long id; + private String fieldKey = ""; + private CelMutableExpr value; + private boolean optionalEntry; + + public long id() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String fieldKey() { + return fieldKey; + } + + public void setFieldKey(String fieldKey) { + this.fieldKey = checkNotNull(fieldKey); + } + + public CelMutableExpr value() { + return value; + } + + public void setValue(CelMutableExpr value) { + this.value = checkNotNull(value); + } + + public boolean optionalEntry() { + return optionalEntry; + } + + public void setOptionalEntry(boolean optionalEntry) { + this.optionalEntry = optionalEntry; + } + + public static Entry create(long id, String fieldKey, CelMutableExpr value) { + return create(id, fieldKey, value, false); + } + + public static Entry create( + long id, String fieldKey, CelMutableExpr value, boolean optionalEntry) { + return new Entry(id, fieldKey, value, optionalEntry); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof Entry) { + Entry that = (Entry) obj; + return this.id == that.id() + && this.fieldKey.equals(that.fieldKey()) + && this.value.equals(that.value()) + && this.optionalEntry == that.optionalEntry(); + } + return false; + } + + @Override + public int hashCode() { + int h = 1; + h *= 1000003; + h ^= (int) ((id >>> 32) ^ id); + h *= 1000003; + h ^= fieldKey.hashCode(); + h *= 1000003; + h ^= value.hashCode(); + h *= 1000003; + h ^= optionalEntry ? 1231 : 1237; + return h; + } + + private Entry(long id, String fieldKey, CelMutableExpr value, boolean optionalEntry) { + this.id = id; + this.fieldKey = checkNotNull(fieldKey); + this.value = checkNotNull(value); + this.optionalEntry = optionalEntry; + } + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof CelMutableCreateStruct) { + CelMutableCreateStruct that = (CelMutableCreateStruct) obj; + return this.messageName.equals(that.messageName()) && this.entries.equals(that.entries()); + } + return false; + } + + @Override + public int hashCode() { + int h = 1; + h *= 1000003; + h ^= messageName.hashCode(); + h *= 1000003; + h ^= entries.hashCode(); + return h; + } + + public static CelMutableCreateStruct create( + String messageName, List entries) { + return new CelMutableCreateStruct(messageName, entries); + } + + private CelMutableCreateStruct(String messageName, List entries) { + this.messageName = checkNotNull(messageName); + this.entries = new ArrayList<>(checkNotNull(entries)); + } + } + public static CelMutableExpr ofNotSet() { return ofNotSet(0L); } @@ -443,6 +597,14 @@ public static CelMutableExpr ofCreateList(long id, CelMutableCreateList mutableC return new CelMutableExpr(id, mutableCreateList); } + public static CelMutableExpr ofCreateStruct(CelMutableCreateStruct mutableCreateStruct) { + return ofCreateStruct(0, mutableCreateStruct); + } + + public static CelMutableExpr ofCreateStruct(long id, CelMutableCreateStruct mutableCreateStruct) { + return new CelMutableExpr(id, mutableCreateStruct); + } + private CelMutableExpr(long id, CelConstant mutableConstant) { this.id = id; setConstant(mutableConstant); @@ -468,13 +630,18 @@ private CelMutableExpr(long id, CelMutableCreateList mutableCreateList) { setCreateList(mutableCreateList); } + private CelMutableExpr(long id, CelMutableCreateStruct mutableCreateStruct) { + this.id = id; + setCreateStruct(mutableCreateStruct); + } + private CelMutableExpr(long id) { this(); this.id = id; } private CelMutableExpr() { - this.notSet = CelExpr.newBuilder().build().exprKind().notSet(); + this.exprValue = CelExpr.newBuilder().build().exprKind().notSet(); this.exprKind = ExprKind.Kind.NOT_SET; } @@ -493,6 +660,7 @@ private Object exprValue() { case CREATE_LIST: return createList(); case CREATE_STRUCT: + return createStruct(); case CREATE_MAP: case COMPREHENSION: // fall-through (not implemented yet) diff --git a/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java b/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java index 5f984b301..7f34c3974 100644 --- a/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java +++ b/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java @@ -24,6 +24,7 @@ import dev.cel.common.ast.CelExpr.ExprKind.Kind; import dev.cel.common.ast.CelMutableExpr.CelMutableCall; import dev.cel.common.ast.CelMutableExpr.CelMutableCreateList; +import dev.cel.common.ast.CelMutableExpr.CelMutableCreateStruct; import dev.cel.common.ast.CelMutableExpr.CelMutableIdent; import dev.cel.common.ast.CelMutableExpr.CelMutableSelect; import java.util.ArrayList; @@ -300,6 +301,78 @@ public void mutableCreateList_setElementAtIndex() { assertThat(createList.elements()).isInstanceOf(ArrayList.class); } + @Test + public void ofCreateStruct() { + CelMutableExpr mutableExpr = + CelMutableExpr.ofCreateStruct(CelMutableCreateStruct.create("message", ImmutableList.of())); + + assertThat(mutableExpr.id()).isEqualTo(0L); + assertThat(mutableExpr.createStruct().messageName()).isEqualTo("message"); + assertThat(mutableExpr.createStruct().entries()).isEmpty(); + } + + @Test + public void ofCreateStruct_withId() { + CelMutableExpr mutableExpr = + CelMutableExpr.ofCreateStruct( + 8L, + CelMutableCreateStruct.create( + "message", + ImmutableList.of( + CelMutableCreateStruct.Entry.create( + 9L, + "field", + CelMutableExpr.ofConstant(CelConstant.ofValue("value")), + /* optionalEntry= */ true)))); + + assertThat(mutableExpr.id()).isEqualTo(8L); + assertThat(mutableExpr.createStruct().messageName()).isEqualTo("message"); + assertThat(mutableExpr.createStruct().entries()) + .containsExactly( + CelMutableCreateStruct.Entry.create( + 9L, + "field", + CelMutableExpr.ofConstant(CelConstant.ofValue("value")), + /* optionalEntry= */ true)); + } + + @Test + public void mutableCreateStruct_setEntryAtIndex() { + CelMutableCreateStruct createStruct = + CelMutableCreateStruct.create( + "message", + ImmutableList.of( + CelMutableCreateStruct.Entry.create( + 1L, "field", CelMutableExpr.ofConstant(CelConstant.ofValue("value"))))); + CelMutableCreateStruct.Entry newEntry = + CelMutableCreateStruct.Entry.create( + 2L, + "field2", + CelMutableExpr.ofConstant(CelConstant.ofValue("value2")), + /* optionalEntry= */ true); + + createStruct.setEntry(0, newEntry); + + assertThat(createStruct.entries()).containsExactly(newEntry); + } + + @Test + public void mutableCreateStructEntry_setters() { + CelMutableCreateStruct.Entry createStructEntry = + CelMutableCreateStruct.Entry.create( + 1L, "field", CelMutableExpr.ofConstant(CelConstant.ofValue("value"))); + + createStructEntry.setId(2L); + createStructEntry.setFieldKey("field2"); + createStructEntry.setValue(CelMutableExpr.ofConstant(CelConstant.ofValue("value2"))); + createStructEntry.setOptionalEntry(true); + + assertThat(createStructEntry) + .isEqualTo( + CelMutableCreateStruct.Entry.create( + 2L, "field2", CelMutableExpr.ofConstant(CelConstant.ofValue("value2")), true)); + } + @Test public void equalityTest() { new EqualsTester() @@ -344,6 +417,30 @@ public void equalityTest() { CelMutableCreateList.create( CelMutableExpr.ofConstant(CelConstant.ofValue("element1")), CelMutableExpr.ofConstant(CelConstant.ofValue("element2"))))) + .addEqualityGroup( + CelMutableExpr.ofCreateStruct( + CelMutableCreateStruct.create("message", ImmutableList.of()))) + .addEqualityGroup( + CelMutableExpr.ofCreateStruct( + 7L, + CelMutableCreateStruct.create( + "message", + ImmutableList.of( + CelMutableCreateStruct.Entry.create( + 8L, + "field", + CelMutableExpr.ofConstant(CelConstant.ofValue("value")), + /* optionalEntry= */ true)))), + CelMutableExpr.ofCreateStruct( + 7L, + CelMutableCreateStruct.create( + "message", + ImmutableList.of( + CelMutableCreateStruct.Entry.create( + 8L, + "field", + CelMutableExpr.ofConstant(CelConstant.ofValue("value")), + /* optionalEntry= */ true))))) .testEquals(); } @@ -354,7 +451,10 @@ private enum MutableExprKindTestCase { IDENT(CelMutableExpr.ofIdent("test")), SELECT(CelMutableExpr.ofSelect(CelMutableSelect.create(CelMutableExpr.ofNotSet(), "field"))), CALL(CelMutableExpr.ofCall(CelMutableCall.create("call"))), - CREATE_LIST(CelMutableExpr.ofCreateList(CelMutableCreateList.create())); + CREATE_LIST(CelMutableExpr.ofCreateList(CelMutableCreateList.create())), + CREATE_STRUCT( + CelMutableExpr.ofCreateStruct( + CelMutableCreateStruct.create("message", ImmutableList.of()))); private final CelMutableExpr mutableExpr; @@ -384,6 +484,9 @@ public void getExprValue_invalidKind_throws(@TestParameter MutableExprKindTestCa if (!testCaseKind.equals(Kind.CREATE_LIST)) { assertThrows(IllegalArgumentException.class, testCase.mutableExpr::createList); } + if (!testCaseKind.equals(Kind.CREATE_STRUCT)) { + assertThrows(IllegalArgumentException.class, testCase.mutableExpr::createStruct); + } } @SuppressWarnings("Immutable") // Mutable by design @@ -411,6 +514,18 @@ private enum HashCodeTestCase { CelMutableExpr.ofConstant(CelConstant.ofValue("element1")), CelMutableExpr.ofConstant(CelConstant.ofValue("element2")))), 165341403), + CREATE_STRUCT( + CelMutableExpr.ofCreateStruct( + 7L, + CelMutableCreateStruct.create( + "message", + ImmutableList.of( + CelMutableCreateStruct.Entry.create( + 8L, + "field", + CelMutableExpr.ofConstant(CelConstant.ofValue("value")), + /* optionalEntry= */ true)))), + 2064611987), ; private final CelMutableExpr mutableExpr; From 66a376360bd7d8fdadae2dfc86a8ec31a2360449 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Thu, 11 Apr 2024 11:01:06 -0700 Subject: [PATCH 077/486] Add CelMutableCreateMap PiperOrigin-RevId: 623878063 --- .../dev/cel/common/ast/CelMutableExpr.java | 163 ++++++++++++++++++ .../cel/common/ast/CelMutableExprTest.java | 111 +++++++++++- 2 files changed, 273 insertions(+), 1 deletion(-) diff --git a/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java b/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java index 1a04ef513..09f10c330 100644 --- a/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java +++ b/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java @@ -88,6 +88,11 @@ public CelMutableCreateStruct createStruct() { return (CelMutableCreateStruct) exprValue; } + public CelMutableCreateMap createMap() { + checkExprKind(Kind.CREATE_MAP); + return (CelMutableCreateMap) exprValue; + } + public void setConstant(CelConstant constant) { this.exprKind = ExprKind.Kind.CONSTANT; this.exprValue = checkNotNull(constant); @@ -118,6 +123,11 @@ public void setCreateStruct(CelMutableCreateStruct createStruct) { this.exprValue = checkNotNull(createStruct); } + public void setCreateMap(CelMutableCreateMap createMap) { + this.exprKind = ExprKind.Kind.CREATE_MAP; + this.exprValue = checkNotNull(createMap); + } + /** A mutable identifier expression. */ public static final class CelMutableIdent { private String name = ""; @@ -549,6 +559,145 @@ private CelMutableCreateStruct(String messageName, ListMaps are constructed as `{'key_name': 'value'}`. + */ + public static final class CelMutableCreateMap { + private List entries; + + public List entries() { + return entries; + } + + public void setEntries(List entries) { + this.entries = checkNotNull(entries); + } + + public void setEntry(int index, CelMutableCreateMap.Entry entry) { + checkArgument(index >= 0 && index < entries().size()); + entries.set(index, checkNotNull(entry)); + } + + /** Represents an entry of the map */ + public static final class Entry { + private long id; + private CelMutableExpr key; + private CelMutableExpr value; + private boolean optionalEntry; + + public long id() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public CelMutableExpr key() { + return key; + } + + public void setKey(CelMutableExpr key) { + this.key = checkNotNull(key); + } + + public CelMutableExpr value() { + return value; + } + + public void setValue(CelMutableExpr value) { + this.value = checkNotNull(value); + } + + public boolean optionalEntry() { + return optionalEntry; + } + + public void setOptionalEntry(boolean optionalEntry) { + this.optionalEntry = optionalEntry; + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof Entry) { + Entry that = (Entry) obj; + return this.id == that.id() + && this.key.equals(that.key()) + && this.value.equals(that.value()) + && this.optionalEntry == that.optionalEntry(); + } + return false; + } + + @Override + public int hashCode() { + int h = 1; + h *= 1000003; + h ^= (int) ((id >>> 32) ^ id); + h *= 1000003; + h ^= key.hashCode(); + h *= 1000003; + h ^= value.hashCode(); + h *= 1000003; + h ^= optionalEntry ? 1231 : 1237; + return h; + } + + public static Entry create(CelMutableExpr key, CelMutableExpr value) { + return create(0, key, value, false); + } + + public static Entry create(long id, CelMutableExpr key, CelMutableExpr value) { + return create(id, key, value, false); + } + + public static Entry create( + long id, CelMutableExpr key, CelMutableExpr value, boolean optionalEntry) { + return new Entry(id, key, value, optionalEntry); + } + + private Entry(long id, CelMutableExpr key, CelMutableExpr value, boolean optionalEntry) { + this.id = id; + this.key = checkNotNull(key); + this.value = checkNotNull(value); + this.optionalEntry = optionalEntry; + } + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof CelMutableCreateMap) { + CelMutableCreateMap that = (CelMutableCreateMap) obj; + return this.entries.equals(that.entries()); + } + return false; + } + + @Override + public int hashCode() { + int h = 1; + h *= 1000003; + h ^= entries.hashCode(); + return h; + } + + public static CelMutableCreateMap create(List entries) { + return new CelMutableCreateMap(new ArrayList<>(entries)); + } + + private CelMutableCreateMap(List entries) { + this.entries = checkNotNull(entries); + } + } + public static CelMutableExpr ofNotSet() { return ofNotSet(0L); } @@ -605,6 +754,14 @@ public static CelMutableExpr ofCreateStruct(long id, CelMutableCreateStruct muta return new CelMutableExpr(id, mutableCreateStruct); } + public static CelMutableExpr ofCreateMap(CelMutableCreateMap mutableCreateMap) { + return ofCreateMap(0, mutableCreateMap); + } + + public static CelMutableExpr ofCreateMap(long id, CelMutableCreateMap mutableCreateMap) { + return new CelMutableExpr(id, mutableCreateMap); + } + private CelMutableExpr(long id, CelConstant mutableConstant) { this.id = id; setConstant(mutableConstant); @@ -635,6 +792,11 @@ private CelMutableExpr(long id, CelMutableCreateStruct mutableCreateStruct) { setCreateStruct(mutableCreateStruct); } + private CelMutableExpr(long id, CelMutableCreateMap mutableCreateMap) { + this.id = id; + setCreateMap(mutableCreateMap); + } + private CelMutableExpr(long id) { this(); this.id = id; @@ -662,6 +824,7 @@ private Object exprValue() { case CREATE_STRUCT: return createStruct(); case CREATE_MAP: + return createMap(); case COMPREHENSION: // fall-through (not implemented yet) } diff --git a/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java b/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java index 7f34c3974..612247f13 100644 --- a/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java +++ b/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java @@ -24,6 +24,7 @@ import dev.cel.common.ast.CelExpr.ExprKind.Kind; import dev.cel.common.ast.CelMutableExpr.CelMutableCall; import dev.cel.common.ast.CelMutableExpr.CelMutableCreateList; +import dev.cel.common.ast.CelMutableExpr.CelMutableCreateMap; import dev.cel.common.ast.CelMutableExpr.CelMutableCreateStruct; import dev.cel.common.ast.CelMutableExpr.CelMutableIdent; import dev.cel.common.ast.CelMutableExpr.CelMutableSelect; @@ -373,6 +374,81 @@ public void mutableCreateStructEntry_setters() { 2L, "field2", CelMutableExpr.ofConstant(CelConstant.ofValue("value2")), true)); } + @Test + public void ofCreateMap() { + CelMutableExpr mutableExpr = + CelMutableExpr.ofCreateMap(CelMutableCreateMap.create(ImmutableList.of())); + + assertThat(mutableExpr.id()).isEqualTo(0L); + assertThat(mutableExpr.createMap().entries()).isEmpty(); + } + + @Test + public void ofCreateMap_withId() { + CelMutableExpr mutableExpr = + CelMutableExpr.ofCreateMap( + 9L, + CelMutableCreateMap.create( + ImmutableList.of( + CelMutableCreateMap.Entry.create( + 10L, + CelMutableExpr.ofConstant(CelConstant.ofValue("key")), + CelMutableExpr.ofConstant(CelConstant.ofValue("value")), + /* optionalEntry= */ true)))); + + assertThat(mutableExpr.id()).isEqualTo(9L); + assertThat(mutableExpr.createMap().entries()) + .containsExactly( + CelMutableCreateMap.Entry.create( + 10L, + CelMutableExpr.ofConstant(CelConstant.ofValue("key")), + CelMutableExpr.ofConstant(CelConstant.ofValue("value")), + /* optionalEntry= */ true)); + } + + @Test + public void mutableCreateMap_setEntryAtIndex() { + CelMutableCreateMap createMap = + CelMutableCreateMap.create( + ImmutableList.of( + CelMutableCreateMap.Entry.create( + 10L, + CelMutableExpr.ofConstant(CelConstant.ofValue("key")), + CelMutableExpr.ofConstant(CelConstant.ofValue("value"))))); + CelMutableCreateMap.Entry newEntry = + CelMutableCreateMap.Entry.create( + 2L, + CelMutableExpr.ofConstant(CelConstant.ofValue("key2")), + CelMutableExpr.ofConstant(CelConstant.ofValue("value2")), + /* optionalEntry= */ true); + + createMap.setEntry(0, newEntry); + + assertThat(createMap.entries()).containsExactly(newEntry); + } + + @Test + public void mutableCreateMapEntry_setters() { + CelMutableCreateMap.Entry createMapEntry = + CelMutableCreateMap.Entry.create( + 1L, + CelMutableExpr.ofConstant(CelConstant.ofValue("key")), + CelMutableExpr.ofConstant(CelConstant.ofValue("value"))); + + createMapEntry.setId(2L); + createMapEntry.setKey(CelMutableExpr.ofConstant(CelConstant.ofValue("key2"))); + createMapEntry.setValue(CelMutableExpr.ofConstant(CelConstant.ofValue("value2"))); + createMapEntry.setOptionalEntry(true); + + assertThat(createMapEntry) + .isEqualTo( + CelMutableCreateMap.Entry.create( + 2L, + CelMutableExpr.ofConstant(CelConstant.ofValue("key2")), + CelMutableExpr.ofConstant(CelConstant.ofValue("value2")), + true)); + } + @Test public void equalityTest() { new EqualsTester() @@ -441,6 +517,23 @@ public void equalityTest() { "field", CelMutableExpr.ofConstant(CelConstant.ofValue("value")), /* optionalEntry= */ true))))) + .addEqualityGroup( + CelMutableExpr.ofCreateMap(CelMutableCreateMap.create(ImmutableList.of()))) + .addEqualityGroup( + CelMutableCreateMap.create( + ImmutableList.of( + CelMutableCreateMap.Entry.create( + 9L, + CelMutableExpr.ofConstant(CelConstant.ofValue("key")), + CelMutableExpr.ofConstant(CelConstant.ofValue("value")), + /* optionalEntry= */ true))), + CelMutableCreateMap.create( + ImmutableList.of( + CelMutableCreateMap.Entry.create( + 9L, + CelMutableExpr.ofConstant(CelConstant.ofValue("key")), + CelMutableExpr.ofConstant(CelConstant.ofValue("value")), + /* optionalEntry= */ true)))) .testEquals(); } @@ -454,7 +547,9 @@ private enum MutableExprKindTestCase { CREATE_LIST(CelMutableExpr.ofCreateList(CelMutableCreateList.create())), CREATE_STRUCT( CelMutableExpr.ofCreateStruct( - CelMutableCreateStruct.create("message", ImmutableList.of()))); + CelMutableCreateStruct.create("message", ImmutableList.of()))), + CREATE_MAP(CelMutableExpr.ofCreateMap(CelMutableCreateMap.create(ImmutableList.of()))), + ; private final CelMutableExpr mutableExpr; @@ -487,6 +582,9 @@ public void getExprValue_invalidKind_throws(@TestParameter MutableExprKindTestCa if (!testCaseKind.equals(Kind.CREATE_STRUCT)) { assertThrows(IllegalArgumentException.class, testCase.mutableExpr::createStruct); } + if (!testCaseKind.equals(Kind.CREATE_MAP)) { + assertThrows(IllegalArgumentException.class, testCase.mutableExpr::createMap); + } } @SuppressWarnings("Immutable") // Mutable by design @@ -526,6 +624,17 @@ private enum HashCodeTestCase { CelMutableExpr.ofConstant(CelConstant.ofValue("value")), /* optionalEntry= */ true)))), 2064611987), + CREATE_MAP( + CelMutableExpr.ofCreateMap( + 8L, + CelMutableCreateMap.create( + ImmutableList.of( + CelMutableCreateMap.Entry.create( + 9L, + CelMutableExpr.ofConstant(CelConstant.ofValue("key")), + CelMutableExpr.ofConstant(CelConstant.ofValue("value")), + /* optionalEntry= */ true)))), + 1260717292), ; private final CelMutableExpr mutableExpr; From b412d7626fe4bcdfd66d2ab756d5e75f4ca7edaa Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Thu, 11 Apr 2024 11:15:27 -0700 Subject: [PATCH 078/486] Add CelMutableComprehension PiperOrigin-RevId: 623883065 --- .../dev/cel/common/ast/CelMutableExpr.java | 168 +++++++++++++++++- .../cel/common/ast/CelMutableExprTest.java | 133 +++++++++++++- 2 files changed, 295 insertions(+), 6 deletions(-) diff --git a/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java b/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java index 09f10c330..e6362af23 100644 --- a/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java +++ b/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java @@ -93,6 +93,11 @@ public CelMutableCreateMap createMap() { return (CelMutableCreateMap) exprValue; } + public CelMutableComprehension comprehension() { + checkExprKind(Kind.COMPREHENSION); + return (CelMutableComprehension) exprValue; + } + public void setConstant(CelConstant constant) { this.exprKind = ExprKind.Kind.CONSTANT; this.exprValue = checkNotNull(constant); @@ -128,6 +133,11 @@ public void setCreateMap(CelMutableCreateMap createMap) { this.exprValue = checkNotNull(createMap); } + public void setComprehension(CelMutableComprehension comprehension) { + this.exprKind = ExprKind.Kind.COMPREHENSION; + this.exprValue = checkNotNull(comprehension); + } + /** A mutable identifier expression. */ public static final class CelMutableIdent { private String name = ""; @@ -698,6 +708,147 @@ private CelMutableCreateMap(List entries) { } } + /** A mutable comprehension expression applied to a list or map. */ + public static final class CelMutableComprehension { + + private String iterVar; + + private CelMutableExpr iterRange; + + private String accuVar; + + private CelMutableExpr accuInit; + + private CelMutableExpr loopCondition; + + private CelMutableExpr loopStep; + + private CelMutableExpr result; + + public String iterVar() { + return iterVar; + } + + public void setIterVar(String iterVar) { + this.iterVar = checkNotNull(iterVar); + } + + public CelMutableExpr iterRange() { + return iterRange; + } + + public void setIterRange(CelMutableExpr iterRange) { + this.iterRange = checkNotNull(iterRange); + } + + public String accuVar() { + return accuVar; + } + + public void setAccuVar(String accuVar) { + this.accuVar = checkNotNull(accuVar); + } + + public CelMutableExpr accuInit() { + return accuInit; + } + + public void setAccuInit(CelMutableExpr accuInit) { + this.accuInit = checkNotNull(accuInit); + } + + public CelMutableExpr loopCondition() { + return loopCondition; + } + + public void setLoopCondition(CelMutableExpr loopCondition) { + this.loopCondition = checkNotNull(loopCondition); + } + + public CelMutableExpr loopStep() { + return loopStep; + } + + public void setLoopStep(CelMutableExpr loopStep) { + this.loopStep = checkNotNull(loopStep); + } + + public CelMutableExpr result() { + return result; + } + + public void setResult(CelMutableExpr result) { + this.result = checkNotNull(result); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof CelMutableComprehension) { + CelMutableComprehension that = (CelMutableComprehension) obj; + return this.iterVar.equals(that.iterVar()) + && this.accuVar.equals(that.accuVar()) + && this.iterRange.equals(that.iterRange()) + && this.accuInit.equals(that.accuInit()) + && this.loopCondition.equals(that.loopCondition()) + && this.loopStep.equals(that.loopStep()) + && this.result.equals(that.result()); + } + return false; + } + + @Override + public int hashCode() { + int h = 1; + h *= 1000003; + h ^= iterVar.hashCode(); + h *= 1000003; + h ^= iterRange.hashCode(); + h *= 1000003; + h ^= accuVar.hashCode(); + h *= 1000003; + h ^= accuInit.hashCode(); + h *= 1000003; + h ^= loopCondition.hashCode(); + h *= 1000003; + h ^= loopStep.hashCode(); + h *= 1000003; + h ^= result.hashCode(); + return h; + } + + public static CelMutableComprehension create( + String iterVar, + CelMutableExpr iterRange, + String accuVar, + CelMutableExpr accuInit, + CelMutableExpr loopCondition, + CelMutableExpr loopStep, + CelMutableExpr result) { + return new CelMutableComprehension( + iterVar, iterRange, accuVar, accuInit, loopCondition, loopStep, result); + } + + private CelMutableComprehension( + String iterVar, + CelMutableExpr iterRange, + String accuVar, + CelMutableExpr accuInit, + CelMutableExpr loopCondition, + CelMutableExpr loopStep, + CelMutableExpr result) { + this.iterVar = checkNotNull(iterVar); + this.iterRange = checkNotNull(iterRange); + this.accuVar = checkNotNull(accuVar); + this.accuInit = checkNotNull(accuInit); + this.loopCondition = checkNotNull(loopCondition); + this.loopStep = checkNotNull(loopStep); + this.result = checkNotNull(result); + } + } + public static CelMutableExpr ofNotSet() { return ofNotSet(0L); } @@ -762,6 +913,11 @@ public static CelMutableExpr ofCreateMap(long id, CelMutableCreateMap mutableCre return new CelMutableExpr(id, mutableCreateMap); } + public static CelMutableExpr ofComprehension( + long id, CelMutableComprehension mutableComprehension) { + return new CelMutableExpr(id, mutableComprehension); + } + private CelMutableExpr(long id, CelConstant mutableConstant) { this.id = id; setConstant(mutableConstant); @@ -797,6 +953,11 @@ private CelMutableExpr(long id, CelMutableCreateMap mutableCreateMap) { setCreateMap(mutableCreateMap); } + private CelMutableExpr(long id, CelMutableComprehension mutableComprehension) { + this.id = id; + setComprehension(mutableComprehension); + } + private CelMutableExpr(long id) { this(); this.id = id; @@ -826,7 +987,7 @@ private Object exprValue() { case CREATE_MAP: return createMap(); case COMPREHENSION: - // fall-through (not implemented yet) + return comprehension(); } throw new IllegalStateException("Unexpected expr kind: " + this.exprKind); @@ -846,10 +1007,7 @@ public boolean equals(Object obj) { if (this.id != that.id() || !this.exprKind.equals(that.getKind())) { return false; } - // When both objects' hashes are cached and they do not match, they can never be equal. - if (this.hash != 0 && that.hash != 0 && this.hash != that.hash) { - return false; - } + return this.exprValue().equals(that.exprValue()); } diff --git a/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java b/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java index 612247f13..d0591cb58 100644 --- a/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java +++ b/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java @@ -23,6 +23,7 @@ import com.google.testing.junit.testparameterinjector.TestParameterInjector; import dev.cel.common.ast.CelExpr.ExprKind.Kind; import dev.cel.common.ast.CelMutableExpr.CelMutableCall; +import dev.cel.common.ast.CelMutableExpr.CelMutableComprehension; import dev.cel.common.ast.CelMutableExpr.CelMutableCreateList; import dev.cel.common.ast.CelMutableExpr.CelMutableCreateMap; import dev.cel.common.ast.CelMutableExpr.CelMutableCreateStruct; @@ -449,6 +450,73 @@ public void mutableCreateMapEntry_setters() { true)); } + @Test + public void ofComprehension_withId() { + CelMutableExpr mutableExpr = + CelMutableExpr.ofComprehension( + 10L, + CelMutableComprehension.create( + "iterVar", + CelMutableExpr.ofCreateList( + CelMutableCreateList.create( + CelMutableExpr.ofConstant(CelConstant.ofValue(true)))), + "accuVar", + CelMutableExpr.ofConstant(CelConstant.ofValue(true)), + CelMutableExpr.ofConstant(CelConstant.ofValue(true)), + CelMutableExpr.ofConstant(CelConstant.ofValue(true)), + CelMutableExpr.ofIdent("__result__"))); + + assertThat(mutableExpr.id()).isEqualTo(10L); + assertThat(mutableExpr.comprehension()) + .isEqualTo( + CelMutableComprehension.create( + "iterVar", + CelMutableExpr.ofCreateList( + CelMutableCreateList.create( + CelMutableExpr.ofConstant(CelConstant.ofValue(true)))), + "accuVar", + CelMutableExpr.ofConstant(CelConstant.ofValue(true)), + CelMutableExpr.ofConstant(CelConstant.ofValue(true)), + CelMutableExpr.ofConstant(CelConstant.ofValue(true)), + CelMutableExpr.ofIdent("__result__"))); + } + + @Test + public void mutableComprehension_setters() { + CelMutableComprehension mutableComprehension = + CelMutableComprehension.create( + "iterVar", + CelMutableExpr.ofNotSet(), + "accuVar", + CelMutableExpr.ofNotSet(), + CelMutableExpr.ofNotSet(), + CelMutableExpr.ofNotSet(), + CelMutableExpr.ofNotSet()); + + mutableComprehension.setIterVar("iterVar2"); + mutableComprehension.setAccuVar("accuVar2"); + mutableComprehension.setIterRange( + CelMutableExpr.ofCreateList( + CelMutableCreateList.create(CelMutableExpr.ofConstant(CelConstant.ofValue(true))))); + mutableComprehension.setAccuInit(CelMutableExpr.ofConstant(CelConstant.ofValue(true))); + mutableComprehension.setLoopCondition(CelMutableExpr.ofConstant(CelConstant.ofValue(true))); + mutableComprehension.setLoopStep(CelMutableExpr.ofConstant(CelConstant.ofValue(true))); + mutableComprehension.setResult(CelMutableExpr.ofIdent("__result__")); + + assertThat(mutableComprehension) + .isEqualTo( + CelMutableComprehension.create( + "iterVar2", + CelMutableExpr.ofCreateList( + CelMutableCreateList.create( + CelMutableExpr.ofConstant(CelConstant.ofValue(true)))), + "accuVar2", + CelMutableExpr.ofConstant(CelConstant.ofValue(true)), + CelMutableExpr.ofConstant(CelConstant.ofValue(true)), + CelMutableExpr.ofConstant(CelConstant.ofValue(true)), + CelMutableExpr.ofIdent("__result__"))); + } + @Test public void equalityTest() { new EqualsTester() @@ -534,6 +602,42 @@ public void equalityTest() { CelMutableExpr.ofConstant(CelConstant.ofValue("key")), CelMutableExpr.ofConstant(CelConstant.ofValue("value")), /* optionalEntry= */ true)))) + .addEqualityGroup( + CelMutableExpr.ofComprehension( + 10L, + CelMutableComprehension.create( + "iterVar", + CelMutableExpr.ofNotSet(), + "accuVar", + CelMutableExpr.ofNotSet(), + CelMutableExpr.ofNotSet(), + CelMutableExpr.ofNotSet(), + CelMutableExpr.ofNotSet()))) + .addEqualityGroup( + CelMutableExpr.ofComprehension( + 11L, + CelMutableComprehension.create( + "iterVar", + CelMutableExpr.ofCreateList( + CelMutableCreateList.create( + CelMutableExpr.ofConstant(CelConstant.ofValue(true)))), + "accuVar", + CelMutableExpr.ofConstant(CelConstant.ofValue(true)), + CelMutableExpr.ofConstant(CelConstant.ofValue(true)), + CelMutableExpr.ofConstant(CelConstant.ofValue(true)), + CelMutableExpr.ofIdent("__result__"))), + CelMutableExpr.ofComprehension( + 11L, + CelMutableComprehension.create( + "iterVar", + CelMutableExpr.ofCreateList( + CelMutableCreateList.create( + CelMutableExpr.ofConstant(CelConstant.ofValue(true)))), + "accuVar", + CelMutableExpr.ofConstant(CelConstant.ofValue(true)), + CelMutableExpr.ofConstant(CelConstant.ofValue(true)), + CelMutableExpr.ofConstant(CelConstant.ofValue(true)), + CelMutableExpr.ofIdent("__result__")))) .testEquals(); } @@ -549,6 +653,17 @@ private enum MutableExprKindTestCase { CelMutableExpr.ofCreateStruct( CelMutableCreateStruct.create("message", ImmutableList.of()))), CREATE_MAP(CelMutableExpr.ofCreateMap(CelMutableCreateMap.create(ImmutableList.of()))), + COMPREHENSION( + CelMutableExpr.ofComprehension( + 10L, + CelMutableComprehension.create( + "iterVar", + CelMutableExpr.ofNotSet(), + "accuVar", + CelMutableExpr.ofNotSet(), + CelMutableExpr.ofNotSet(), + CelMutableExpr.ofNotSet(), + CelMutableExpr.ofNotSet()))), ; private final CelMutableExpr mutableExpr; @@ -585,6 +700,9 @@ public void getExprValue_invalidKind_throws(@TestParameter MutableExprKindTestCa if (!testCaseKind.equals(Kind.CREATE_MAP)) { assertThrows(IllegalArgumentException.class, testCase.mutableExpr::createMap); } + if (!testCaseKind.equals(Kind.COMPREHENSION)) { + assertThrows(IllegalArgumentException.class, testCase.mutableExpr::comprehension); + } } @SuppressWarnings("Immutable") // Mutable by design @@ -635,7 +753,20 @@ private enum HashCodeTestCase { CelMutableExpr.ofConstant(CelConstant.ofValue("value")), /* optionalEntry= */ true)))), 1260717292), - ; + COMPREHENSION( + CelMutableExpr.ofComprehension( + 10L, + CelMutableComprehension.create( + "iterVar", + CelMutableExpr.ofCreateList( + CelMutableCreateList.create( + CelMutableExpr.ofConstant(CelConstant.ofValue(true)))), + "accuVar", + CelMutableExpr.ofConstant(CelConstant.ofValue(true)), + CelMutableExpr.ofConstant(CelConstant.ofValue(true)), + CelMutableExpr.ofConstant(CelConstant.ofValue(true)), + CelMutableExpr.ofIdent("__result__"))), + -1006359408); private final CelMutableExpr mutableExpr; private final int expectedHashCode; From 5cdae24e57ae679bf20b776fb6fe3aaf28d4bbc2 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Thu, 11 Apr 2024 11:30:15 -0700 Subject: [PATCH 079/486] Remove cached hashcode from MutableExpr PiperOrigin-RevId: 623887941 --- .../dev/cel/common/ast/CelMutableExpr.java | 20 ++++++------------- .../cel/common/ast/CelMutableExprTest.java | 10 ++++++++++ 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java b/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java index e6362af23..023584c32 100644 --- a/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java +++ b/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java @@ -39,7 +39,6 @@ public final class CelMutableExpr { private long id; private ExprKind.Kind exprKind; private Object exprValue; - private int hash = 0; public long id() { return id; @@ -1016,19 +1015,12 @@ public boolean equals(Object obj) { @Override public int hashCode() { - if (hash == 0) { - int h = 1; - h *= 1000003; - h ^= (int) ((id >>> 32) ^ id); - h *= 1000003; - h ^= this.exprValue().hashCode(); - - if (h == 0) { - h = 1; - } - hash = h; - } + int h = 1; + h *= 1000003; + h ^= (int) ((id >>> 32) ^ id); + h *= 1000003; + h ^= this.exprValue().hashCode(); - return hash; + return h; } } diff --git a/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java b/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java index d0591cb58..41b2c44b9 100644 --- a/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java +++ b/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java @@ -783,4 +783,14 @@ public void hashCodeTest(@TestParameter HashCodeTestCase testCase) { // Run it twice to ensure cached value is stable assertThat(testCase.mutableExpr.hashCode()).isEqualTo(testCase.expectedHashCode); } + + @Test + public void propertyMutated_hashCodeChanged() { + CelMutableExpr mutableExpr = CelMutableExpr.ofIdent("x"); + int originalHash = mutableExpr.hashCode(); + + mutableExpr.ident().setName("y"); + + assertThat(originalHash).isNotEqualTo(mutableExpr.hashCode()); + } } From 1cd3ab1c2cce72182ebd1b41e96c0c947fe3e1ef Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Thu, 11 Apr 2024 11:44:14 -0700 Subject: [PATCH 080/486] Add copy constructor to deep copy mutable expressions PiperOrigin-RevId: 623892544 --- .../dev/cel/common/ast/CelMutableExpr.java | 104 ++++++++++ .../cel/common/ast/CelMutableExprTest.java | 195 ++++++++++++++++++ 2 files changed, 299 insertions(+) diff --git a/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java b/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java index 023584c32..7b84826f1 100644 --- a/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java +++ b/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java @@ -171,6 +171,10 @@ public int hashCode() { return name.hashCode(); } + private CelMutableIdent deepCopy() { + return new CelMutableIdent(name); + } + private CelMutableIdent(String name) { this.name = checkNotNull(name); } @@ -206,6 +210,10 @@ public void setTestOnly(boolean testOnly) { this.testOnly = testOnly; } + private CelMutableSelect deepCopy() { + return create(newInstance(operand()), field, testOnly); + } + @Override public boolean equals(Object obj) { if (obj == this) { @@ -321,6 +329,13 @@ public int hashCode() { return h; } + private CelMutableCall deepCopy() { + List copiedArgs = deepCopyList(args); + return target().isPresent() + ? create(newInstance(target.get()), function, copiedArgs) + : create(function, copiedArgs); + } + public static CelMutableCall create(String function, CelMutableExpr... args) { return create(function, Arrays.asList(checkNotNull(args))); } @@ -399,6 +414,10 @@ public int hashCode() { return h; } + private CelMutableCreateList deepCopy() { + return create(deepCopyList(elements), optionalIndices); + } + public static CelMutableCreateList create(CelMutableExpr... elements) { return create(Arrays.asList(checkNotNull(elements))); } @@ -489,6 +508,10 @@ public void setOptionalEntry(boolean optionalEntry) { this.optionalEntry = optionalEntry; } + private Entry deepCopy() { + return create(id, fieldKey, newInstance(value), optionalEntry); + } + public static Entry create(long id, String fieldKey, CelMutableExpr value) { return create(id, fieldKey, value, false); } @@ -557,6 +580,15 @@ public int hashCode() { return h; } + private CelMutableCreateStruct deepCopy() { + ArrayList copiedEntries = new ArrayList<>(); + for (CelMutableCreateStruct.Entry entry : entries) { + copiedEntries.add(entry.deepCopy()); + } + + return create(messageName, copiedEntries); + } + public static CelMutableCreateStruct create( String messageName, List entries) { return new CelMutableCreateStruct(messageName, entries); @@ -657,6 +689,10 @@ public int hashCode() { return h; } + private Entry deepCopy() { + return create(id, newInstance(key), newInstance(value), optionalEntry); + } + public static Entry create(CelMutableExpr key, CelMutableExpr value) { return create(0, key, value, false); } @@ -698,6 +734,15 @@ public int hashCode() { return h; } + private CelMutableCreateMap deepCopy() { + ArrayList copiedEntries = new ArrayList<>(); + for (CelMutableCreateMap.Entry entry : entries) { + copiedEntries.add(entry.deepCopy()); + } + + return create(copiedEntries); + } + public static CelMutableCreateMap create(List entries) { return new CelMutableCreateMap(new ArrayList<>(entries)); } @@ -818,6 +863,17 @@ public int hashCode() { return h; } + private CelMutableComprehension deepCopy() { + return create( + iterVar, + newInstance(iterRange), + accuVar, + newInstance(accuInit), + newInstance(loopCondition), + newInstance(loopStep), + newInstance(result)); + } + public static CelMutableComprehension create( String iterVar, CelMutableExpr iterRange, @@ -917,6 +973,11 @@ public static CelMutableExpr ofComprehension( return new CelMutableExpr(id, mutableComprehension); } + /** Constructs a deep copy of the mutable expression. */ + public static CelMutableExpr newInstance(CelMutableExpr other) { + return new CelMutableExpr(other); + } + private CelMutableExpr(long id, CelConstant mutableConstant) { this.id = id; setConstant(mutableConstant); @@ -967,6 +1028,40 @@ private CelMutableExpr() { this.exprKind = ExprKind.Kind.NOT_SET; } + private CelMutableExpr(CelMutableExpr other) { + checkNotNull(other); + this.id = other.id; + this.exprKind = other.exprKind; + switch (other.getKind()) { + case CONSTANT: + this.exprValue = other.exprValue; // Constant is immutable. + break; + case IDENT: + this.exprValue = other.ident().deepCopy(); + break; + case SELECT: + this.exprValue = other.select().deepCopy(); + break; + case CALL: + this.exprValue = other.call().deepCopy(); + break; + case CREATE_LIST: + this.exprValue = other.createList().deepCopy(); + break; + case CREATE_STRUCT: + this.exprValue = other.createStruct().deepCopy(); + break; + case CREATE_MAP: + this.exprValue = other.createMap().deepCopy(); + break; + case COMPREHENSION: + this.exprValue = other.comprehension().deepCopy(); + break; + default: + throw new IllegalStateException("Unexpected expr kind: " + this.exprKind); + } + } + private Object exprValue() { switch (this.exprKind) { case NOT_SET: @@ -992,6 +1087,15 @@ private Object exprValue() { throw new IllegalStateException("Unexpected expr kind: " + this.exprKind); } + private static List deepCopyList(List elements) { + ArrayList copiedArgs = new ArrayList<>(); + for (CelMutableExpr arg : elements) { + copiedArgs.add(newInstance(arg)); + } + + return copiedArgs; + } + private void checkExprKind(ExprKind.Kind exprKind) { checkArgument(this.exprKind.equals(exprKind), "Invalid ExprKind: %s", exprKind); } diff --git a/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java b/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java index 41b2c44b9..90901fc05 100644 --- a/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java +++ b/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java @@ -19,6 +19,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.testing.EqualsTester; +import com.google.common.truth.Correspondence; import com.google.testing.junit.testparameterinjector.TestParameter; import com.google.testing.junit.testparameterinjector.TestParameterInjector; import dev.cel.common.ast.CelExpr.ExprKind.Kind; @@ -68,6 +69,19 @@ public void ofConstant_withId() { assertThat(mutableExpr.constant()).isEqualTo(CelConstant.ofValue(5L)); } + @Test + public void mutableConstant_deepCopy() { + CelMutableExpr mutableExpr = CelMutableExpr.ofConstant(1L, CelConstant.ofValue(5L)); + + CelMutableExpr deepCopiedExpr = CelMutableExpr.newInstance(mutableExpr); + + assertThat(mutableExpr).isEqualTo(deepCopiedExpr); + assertThat(mutableExpr.constant()).isEqualTo(deepCopiedExpr.constant()); + assertThat(mutableExpr).isNotSameInstanceAs(deepCopiedExpr); + // The stored constant itself is immutable, thus remain referentially equal when copied. + assertThat(mutableExpr.constant()).isSameInstanceAs(deepCopiedExpr.constant()); + } + @Test public void ofIdent() { CelMutableExpr mutableExpr = CelMutableExpr.ofIdent("x"); @@ -93,6 +107,18 @@ public void mutableIdent_setName() { assertThat(ident.name()).isEqualTo("y"); } + @Test + public void mutableIdent_deepCopy() { + CelMutableExpr mutableExpr = CelMutableExpr.ofIdent(1L, "x"); + + CelMutableExpr deepCopiedExpr = CelMutableExpr.newInstance(mutableExpr); + + assertThat(mutableExpr).isEqualTo(deepCopiedExpr); + assertThat(mutableExpr.ident()).isEqualTo(deepCopiedExpr.ident()); + assertThat(mutableExpr).isNotSameInstanceAs(deepCopiedExpr); + assertThat(mutableExpr.ident()).isNotSameInstanceAs(deepCopiedExpr.ident()); + } + @Test public void ofSelect() { CelMutableExpr mutableExpr = @@ -131,6 +157,21 @@ public void mutableSelect_setters() { assertThat(select.testOnly()).isFalse(); } + @Test + public void mutableSelect_deepCopy() { + CelMutableExpr mutableExpr = + CelMutableExpr.ofSelect( + 1L, + CelMutableSelect.create(CelMutableExpr.ofIdent("x"), "field", /* testOnly= */ true)); + + CelMutableExpr deepCopiedExpr = CelMutableExpr.newInstance(mutableExpr); + + assertThat(mutableExpr).isEqualTo(deepCopiedExpr); + assertThat(mutableExpr.select()).isEqualTo(deepCopiedExpr.select()); + assertThat(mutableExpr).isNotSameInstanceAs(deepCopiedExpr); + assertThat(mutableExpr.select()).isNotSameInstanceAs(deepCopiedExpr.select()); + } + @Test public void ofCall() { CelMutableExpr mutableExpr = @@ -245,6 +286,24 @@ public void mutableCall_setTarget() { assertThat(call.target()).hasValue(CelMutableExpr.ofConstant(CelConstant.ofValue("hello"))); } + @Test + public void mutableCall_deepCopy() { + CelMutableExpr mutableExpr = + CelMutableExpr.ofCall( + 1L, + CelMutableCall.create( + CelMutableExpr.ofConstant(CelConstant.ofValue("target")), + "function", + CelMutableExpr.ofConstant(CelConstant.ofValue("arg")))); + + CelMutableExpr deepCopiedExpr = CelMutableExpr.newInstance(mutableExpr); + + assertThat(mutableExpr).isEqualTo(deepCopiedExpr); + assertThat(mutableExpr.call()).isEqualTo(deepCopiedExpr.call()); + assertThat(mutableExpr).isNotSameInstanceAs(deepCopiedExpr); + assertThat(mutableExpr.call()).isNotSameInstanceAs(deepCopiedExpr.call()); + } + @Test public void mutableCall_setFunction() { CelMutableCall call = CelMutableCall.create("function"); @@ -303,6 +362,29 @@ public void mutableCreateList_setElementAtIndex() { assertThat(createList.elements()).isInstanceOf(ArrayList.class); } + @Test + @SuppressWarnings("ReferenceEquality") // test only on iterating through elements + public void mutableCreateList_deepCopy() { + CelMutableExpr mutableExpr = + CelMutableExpr.ofCreateList( + CelMutableCreateList.create( + CelMutableExpr.ofConstant(CelConstant.ofValue("element1")), + CelMutableExpr.ofConstant(CelConstant.ofValue("element2")))); + + CelMutableExpr deepCopiedExpr = CelMutableExpr.newInstance(mutableExpr); + + assertThat(mutableExpr).isEqualTo(deepCopiedExpr); + assertThat(mutableExpr.createList()).isEqualTo(deepCopiedExpr.createList()); + assertThat(mutableExpr).isNotSameInstanceAs(deepCopiedExpr); + assertThat(mutableExpr.createList()).isNotSameInstanceAs(deepCopiedExpr.createList()); + assertThat(mutableExpr.createList().elements()) + .comparingElementsUsing( + Correspondence.from( + (e1, e2) -> e1 != e2 && e1.equals(e2), + "are only value equal and not referentially equal")) + .containsExactlyElementsIn(deepCopiedExpr.createList().elements()); + } + @Test public void ofCreateStruct() { CelMutableExpr mutableExpr = @@ -375,6 +457,41 @@ public void mutableCreateStructEntry_setters() { 2L, "field2", CelMutableExpr.ofConstant(CelConstant.ofValue("value2")), true)); } + @Test + @SuppressWarnings("ReferenceEquality") // test only on iterating through elements + public void mutableCreateStruct_deepCopy() { + CelMutableExpr mutableExpr = + CelMutableExpr.ofCreateStruct( + 8L, + CelMutableCreateStruct.create( + "message", + ImmutableList.of( + CelMutableCreateStruct.Entry.create( + 8L, + "field", + CelMutableExpr.ofConstant(CelConstant.ofValue("value")), + /* optionalEntry= */ true)))); + + CelMutableExpr deepCopiedExpr = CelMutableExpr.newInstance(mutableExpr); + + assertThat(mutableExpr).isEqualTo(deepCopiedExpr); + assertThat(mutableExpr.createStruct()).isEqualTo(deepCopiedExpr.createStruct()); + assertThat(mutableExpr).isNotSameInstanceAs(deepCopiedExpr); + assertThat(mutableExpr.createStruct()).isNotSameInstanceAs(deepCopiedExpr.createStruct()); + assertThat(mutableExpr.createStruct().entries()) + .isNotSameInstanceAs(deepCopiedExpr.createStruct().entries()); + assertThat(mutableExpr.createStruct().entries()) + .comparingElementsUsing( + Correspondence.from( + (e1, e2) -> + e1 != e2 + && e1.equals(e2) + && e1.value() != e2.value() + && e1.value().equals(e2.value()), + "are only value equal and not referentially equal")) + .containsExactlyElementsIn(deepCopiedExpr.createStruct().entries()); + } + @Test public void ofCreateMap() { CelMutableExpr mutableExpr = @@ -450,6 +567,40 @@ public void mutableCreateMapEntry_setters() { true)); } + @Test + @SuppressWarnings("ReferenceEquality") // test only on iterating through elements + public void mutableCreateMap_deepCopy() { + CelMutableExpr mutableExpr = + CelMutableExpr.ofCreateMap( + 9L, + CelMutableCreateMap.create( + ImmutableList.of( + CelMutableCreateMap.Entry.create( + 10L, + CelMutableExpr.ofConstant(CelConstant.ofValue("key")), + CelMutableExpr.ofConstant(CelConstant.ofValue("value")), + /* optionalEntry= */ true)))); + + CelMutableExpr deepCopiedExpr = CelMutableExpr.newInstance(mutableExpr); + + assertThat(mutableExpr).isEqualTo(deepCopiedExpr); + assertThat(mutableExpr.createMap()).isEqualTo(deepCopiedExpr.createMap()); + assertThat(mutableExpr).isNotSameInstanceAs(deepCopiedExpr); + assertThat(mutableExpr.createMap()).isNotSameInstanceAs(deepCopiedExpr.createMap()); + assertThat(mutableExpr.createMap().entries()) + .comparingElementsUsing( + Correspondence.from( + (e1, e2) -> + e1 != e2 + && e1.equals(e2) + && e1.key() != e2.key() + && e1.key().equals(e2.key()) + && e1.value() != e2.value() + && e1.value().equals(e2.value()), + "are only value equal and not referentially equal")) + .containsExactlyElementsIn(deepCopiedExpr.createMap().entries()); + } + @Test public void ofComprehension_withId() { CelMutableExpr mutableExpr = @@ -517,6 +668,50 @@ public void mutableComprehension_setters() { CelMutableExpr.ofIdent("__result__"))); } + @Test + public void mutableComprehension_deepCopy() { + CelMutableExpr mutableExpr = + CelMutableExpr.ofComprehension( + 10L, + CelMutableComprehension.create( + "iterVar", + CelMutableExpr.ofCreateList( + CelMutableCreateList.create( + CelMutableExpr.ofConstant(CelConstant.ofValue(true)))), + "accuVar", + CelMutableExpr.ofConstant(CelConstant.ofValue(true)), + CelMutableExpr.ofConstant(CelConstant.ofValue(true)), + CelMutableExpr.ofConstant(CelConstant.ofValue(true)), + CelMutableExpr.ofIdent("__result__"))); + + CelMutableExpr deepCopiedExpr = CelMutableExpr.newInstance(mutableExpr); + + assertThat(mutableExpr).isEqualTo(deepCopiedExpr); + assertThat(mutableExpr).isNotSameInstanceAs(deepCopiedExpr); + assertThat(mutableExpr.comprehension()).isEqualTo(deepCopiedExpr.comprehension()); + assertThat(mutableExpr.comprehension()).isNotSameInstanceAs(deepCopiedExpr.comprehension()); + assertThat(mutableExpr.comprehension().accuInit()) + .isEqualTo(deepCopiedExpr.comprehension().accuInit()); + assertThat(mutableExpr.comprehension().accuInit()) + .isNotSameInstanceAs(deepCopiedExpr.comprehension().accuInit()); + assertThat(mutableExpr.comprehension().iterRange()) + .isEqualTo(deepCopiedExpr.comprehension().iterRange()); + assertThat(mutableExpr.comprehension().iterRange()) + .isNotSameInstanceAs(deepCopiedExpr.comprehension().iterRange()); + assertThat(mutableExpr.comprehension().loopCondition()) + .isEqualTo(deepCopiedExpr.comprehension().loopCondition()); + assertThat(mutableExpr.comprehension().loopCondition()) + .isNotSameInstanceAs(deepCopiedExpr.comprehension().loopCondition()); + assertThat(mutableExpr.comprehension().loopStep()) + .isEqualTo(deepCopiedExpr.comprehension().loopStep()); + assertThat(mutableExpr.comprehension().loopStep()) + .isNotSameInstanceAs(deepCopiedExpr.comprehension().loopStep()); + assertThat(mutableExpr.comprehension().result()) + .isEqualTo(deepCopiedExpr.comprehension().result()); + assertThat(mutableExpr.comprehension().result()) + .isNotSameInstanceAs(deepCopiedExpr.comprehension().result()); + } + @Test public void equalityTest() { new EqualsTester() From 8b68baf1acdb63369e8dc896f1880f2fc4bd2081 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Mon, 15 Apr 2024 13:33:55 -0700 Subject: [PATCH 081/486] Remove main AutoValue dependency from the published jar auto_value_annotations is still required for dependencies to compile autovalue annotated public classes(e.g: CelOptions) Fixes https://github.com/google/cel-java/issues/313 PiperOrigin-RevId: 625066521 --- BUILD.bazel | 1 - 1 file changed, 1 deletion(-) diff --git a/BUILD.bazel b/BUILD.bazel index 0a86ecbce..23ba57ee2 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -73,7 +73,6 @@ java_library( ], neverlink = 1, exports = [ - "@maven//:com_google_auto_value_auto_value", "@maven//:com_google_auto_value_auto_value_annotations", ], ) From ba2bfe062210f91f65801f9292023604b15952f6 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Tue, 16 Apr 2024 10:30:52 -0700 Subject: [PATCH 082/486] Add a converter for adapting between CelExpr and CelMutableExpr PiperOrigin-RevId: 625378157 --- .../main/java/dev/cel/common/ast/BUILD.bazel | 1 + .../common/ast/CelMutableExprConverter.java | 237 ++++++++++ .../ast/CelMutableExprConverterTest.java | 438 ++++++++++++++++++ 3 files changed, 676 insertions(+) create mode 100644 common/src/main/java/dev/cel/common/ast/CelMutableExprConverter.java create mode 100644 common/src/test/java/dev/cel/common/ast/CelMutableExprConverterTest.java diff --git a/common/src/main/java/dev/cel/common/ast/BUILD.bazel b/common/src/main/java/dev/cel/common/ast/BUILD.bazel index 08e388712..b26181303 100644 --- a/common/src/main/java/dev/cel/common/ast/BUILD.bazel +++ b/common/src/main/java/dev/cel/common/ast/BUILD.bazel @@ -34,6 +34,7 @@ EXPR_FACTORY_SOURCES = [ # keep sorted MUTABLE_AST_SOURCES = [ "CelMutableExpr.java", + "CelMutableExprConverter.java", ] java_library( diff --git a/common/src/main/java/dev/cel/common/ast/CelMutableExprConverter.java b/common/src/main/java/dev/cel/common/ast/CelMutableExprConverter.java new file mode 100644 index 000000000..64b9cdb10 --- /dev/null +++ b/common/src/main/java/dev/cel/common/ast/CelMutableExprConverter.java @@ -0,0 +1,237 @@ +// Copyright 2024 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.common.ast; + +import static com.google.common.collect.ImmutableList.toImmutableList; +import static java.util.stream.Collectors.toCollection; + +import com.google.common.collect.ImmutableList; +import dev.cel.common.ast.CelExpr.CelCall; +import dev.cel.common.ast.CelExpr.CelComprehension; +import dev.cel.common.ast.CelExpr.CelCreateList; +import dev.cel.common.ast.CelExpr.CelCreateMap; +import dev.cel.common.ast.CelExpr.CelCreateStruct; +import dev.cel.common.ast.CelExpr.CelSelect; +import dev.cel.common.ast.CelMutableExpr.CelMutableCall; +import dev.cel.common.ast.CelMutableExpr.CelMutableComprehension; +import dev.cel.common.ast.CelMutableExpr.CelMutableCreateList; +import dev.cel.common.ast.CelMutableExpr.CelMutableCreateMap; +import dev.cel.common.ast.CelMutableExpr.CelMutableCreateStruct; +import dev.cel.common.ast.CelMutableExpr.CelMutableSelect; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +/** + * Converts a mutable Expression Tree {@link CelMutableExpr} into the CEL native representation of + * Expression tree {@link CelExpr} and vice versa. + */ +public final class CelMutableExprConverter { + + public static CelMutableExpr fromCelExpr(CelExpr celExpr) { + CelExpr.ExprKind celExprKind = celExpr.exprKind(); + switch (celExprKind.getKind()) { + case CONSTANT: + return CelMutableExpr.ofConstant(celExpr.id(), celExpr.constant()); + case IDENT: + return CelMutableExpr.ofIdent(celExpr.id(), celExpr.ident().name()); + case SELECT: + CelSelect select = celExpr.select(); + CelMutableExpr operand = fromCelExpr(select.operand()); + return CelMutableExpr.ofSelect( + celExpr.id(), CelMutableSelect.create(operand, select.field(), select.testOnly())); + case CALL: + CelCall celCall = celExprKind.call(); + List args = + celCall.args().stream() + .map(CelMutableExprConverter::fromCelExpr) + .collect(toCollection(ArrayList::new)); + CelMutableCall mutableCall = + celCall.target().isPresent() + ? CelMutableCall.create( + fromCelExpr(celCall.target().get()), celCall.function(), args) + : CelMutableCall.create(celCall.function(), args); + + return CelMutableExpr.ofCall(celExpr.id(), mutableCall); + case CREATE_LIST: + CelCreateList createList = celExpr.createList(); + return CelMutableExpr.ofCreateList( + celExpr.id(), + CelMutableCreateList.create( + fromCelExprList(createList.elements()), createList.optionalIndices())); + case CREATE_STRUCT: + return CelMutableExpr.ofCreateStruct( + celExpr.id(), fromCelStructToMutableStruct(celExpr.createStruct())); + case CREATE_MAP: + return CelMutableExpr.ofCreateMap( + celExpr.id(), fromCelMapToMutableMap(celExpr.createMap())); + case COMPREHENSION: + CelComprehension celComprehension = celExprKind.comprehension(); + CelMutableComprehension mutableComprehension = + CelMutableComprehension.create( + celComprehension.iterVar(), + fromCelExpr(celComprehension.iterRange()), + celComprehension.accuVar(), + fromCelExpr(celComprehension.accuInit()), + fromCelExpr(celComprehension.loopCondition()), + fromCelExpr(celComprehension.loopStep()), + fromCelExpr(celComprehension.result())); + return CelMutableExpr.ofComprehension(celExpr.id(), mutableComprehension); + case NOT_SET: + return CelMutableExpr.ofNotSet(celExpr.id()); + } + + throw new IllegalArgumentException( + "Unexpected expression kind case: " + celExpr.exprKind().getKind()); + } + + private static List fromCelExprList(Iterable celExprList) { + ArrayList mutableExprList = new ArrayList<>(); + for (CelExpr celExpr : celExprList) { + mutableExprList.add(fromCelExpr(celExpr)); + } + return mutableExprList; + } + + private static CelMutableCreateStruct fromCelStructToMutableStruct( + CelCreateStruct celCreateStruct) { + List entries = new ArrayList<>(); + for (CelCreateStruct.Entry celStructExprEntry : celCreateStruct.entries()) { + entries.add( + CelMutableCreateStruct.Entry.create( + celStructExprEntry.id(), + celStructExprEntry.fieldKey(), + fromCelExpr(celStructExprEntry.value()), + celStructExprEntry.optionalEntry())); + } + + return CelMutableCreateStruct.create(celCreateStruct.messageName(), entries); + } + + private static CelMutableCreateMap fromCelMapToMutableMap(CelCreateMap celCreateMap) { + List entries = new ArrayList<>(); + for (CelCreateMap.Entry celMapExprEntry : celCreateMap.entries()) { + entries.add( + CelMutableCreateMap.Entry.create( + celMapExprEntry.id(), + fromCelExpr(celMapExprEntry.key()), + fromCelExpr(celMapExprEntry.value()), + celMapExprEntry.optionalEntry())); + } + + return CelMutableCreateMap.create(entries); + } + + /////////////////////// + + public static CelExpr fromMutableExpr(CelMutableExpr mutableExpr) { + long id = mutableExpr.id(); + switch (mutableExpr.getKind()) { + case CONSTANT: + return CelExpr.ofConstantExpr(id, mutableExpr.constant()); + case IDENT: + return CelExpr.ofIdentExpr(id, mutableExpr.ident().name()); + case SELECT: + CelMutableSelect select = mutableExpr.select(); + CelExpr operand = fromMutableExpr(select.operand()); + return CelExpr.ofSelectExpr(id, operand, select.field(), select.testOnly()); + case CALL: + CelMutableCall mutableCall = mutableExpr.call(); + ImmutableList args = + mutableCall.args().stream() + .map(CelMutableExprConverter::fromMutableExpr) + .collect(toImmutableList()); + Optional targetExpr = + mutableCall.target().map(CelMutableExprConverter::fromMutableExpr); + return CelExpr.ofCallExpr(id, targetExpr, mutableCall.function(), args); + case CREATE_LIST: + CelMutableCreateList mutableCreateList = mutableExpr.createList(); + return CelExpr.ofCreateListExpr( + id, + fromMutableExprList(mutableCreateList.elements()), + ImmutableList.copyOf(mutableCreateList.optionalIndices())); + case CREATE_STRUCT: + CelMutableCreateStruct mutableCreateStruct = mutableExpr.createStruct(); + return CelExpr.newBuilder() + .setId(id) + .setCreateStruct(fromMutableStructToCelStruct(mutableCreateStruct)) + .build(); + case CREATE_MAP: + CelMutableCreateMap mutableCreateMap = mutableExpr.createMap(); + return CelExpr.newBuilder() + .setId(id) + .setCreateMap(fromMutableMapToCelMap(mutableCreateMap)) + .build(); + case COMPREHENSION: + CelMutableComprehension mutableComprehension = mutableExpr.comprehension(); + return CelExpr.ofComprehension( + id, + mutableComprehension.iterVar(), + fromMutableExpr(mutableComprehension.iterRange()), + mutableComprehension.accuVar(), + fromMutableExpr(mutableComprehension.accuInit()), + fromMutableExpr(mutableComprehension.loopCondition()), + fromMutableExpr(mutableComprehension.loopStep()), + fromMutableExpr(mutableComprehension.result())); + case NOT_SET: + return CelExpr.ofNotSet(id); + } + + throw new IllegalArgumentException("Unexpected expression kind case: " + mutableExpr.getKind()); + } + + private static ImmutableList fromMutableExprList( + Iterable mutableExprList) { + ImmutableList.Builder celExprList = ImmutableList.builder(); + for (CelMutableExpr mutableExpr : mutableExprList) { + celExprList.add(fromMutableExpr(mutableExpr)); + } + return celExprList.build(); + } + + private static CelCreateStruct fromMutableStructToCelStruct( + CelMutableCreateStruct mutableCreateStruct) { + List entries = new ArrayList<>(); + for (CelMutableCreateStruct.Entry mutableStructEntry : mutableCreateStruct.entries()) { + entries.add( + CelExpr.ofCreateStructEntryExpr( + mutableStructEntry.id(), + mutableStructEntry.fieldKey(), + fromMutableExpr(mutableStructEntry.value()), + mutableStructEntry.optionalEntry())); + } + + return CelCreateStruct.newBuilder() + .setMessageName(mutableCreateStruct.messageName()) + .addEntries(entries) + .build(); + } + + private static CelCreateMap fromMutableMapToCelMap(CelMutableCreateMap mutableCreateMap) { + List entries = new ArrayList<>(); + for (CelMutableCreateMap.Entry mutableMapEntry : mutableCreateMap.entries()) { + entries.add( + CelExpr.ofCreateMapEntryExpr( + mutableMapEntry.id(), + fromMutableExpr(mutableMapEntry.key()), + fromMutableExpr(mutableMapEntry.value()), + mutableMapEntry.optionalEntry())); + } + + return CelCreateMap.newBuilder().addEntries(entries).build(); + } + + private CelMutableExprConverter() {} +} diff --git a/common/src/test/java/dev/cel/common/ast/CelMutableExprConverterTest.java b/common/src/test/java/dev/cel/common/ast/CelMutableExprConverterTest.java new file mode 100644 index 000000000..44a020a0e --- /dev/null +++ b/common/src/test/java/dev/cel/common/ast/CelMutableExprConverterTest.java @@ -0,0 +1,438 @@ +// Copyright 2024 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.common.ast; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.common.collect.ImmutableList; +import com.google.common.primitives.UnsignedLong; +import com.google.protobuf.ByteString; +import com.google.protobuf.NullValue; +import com.google.testing.junit.testparameterinjector.TestParameter; +import com.google.testing.junit.testparameterinjector.TestParameterInjector; +import dev.cel.common.ast.CelExpr.CelCall; +import dev.cel.common.ast.CelExpr.CelCreateList; +import dev.cel.common.ast.CelExpr.CelCreateStruct; +import dev.cel.common.ast.CelMutableExpr.CelMutableCall; +import dev.cel.common.ast.CelMutableExpr.CelMutableComprehension; +import dev.cel.common.ast.CelMutableExpr.CelMutableCreateList; +import dev.cel.common.ast.CelMutableExpr.CelMutableCreateMap; +import dev.cel.common.ast.CelMutableExpr.CelMutableCreateStruct; +import dev.cel.common.ast.CelMutableExpr.CelMutableSelect; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(TestParameterInjector.class) +public class CelMutableExprConverterTest { + @SuppressWarnings("Immutable") // Mutable by design + private enum ConstantTestCase { + NOT_SET( + CelMutableExpr.ofConstant(1, CelConstant.ofNotSet()), + CelExpr.ofConstantExpr(1, CelConstant.ofNotSet())), + NULL( + CelMutableExpr.ofConstant(1, CelConstant.ofValue(NullValue.NULL_VALUE)), + CelExpr.ofConstantExpr(1, CelConstant.ofValue(NullValue.NULL_VALUE))), + BOOLEAN( + CelMutableExpr.ofConstant(1, CelConstant.ofValue(true)), + CelExpr.ofConstantExpr(1, CelConstant.ofValue(true))), + INT64( + CelMutableExpr.ofConstant(1, CelConstant.ofValue(10)), + CelExpr.ofConstantExpr(1, CelConstant.ofValue(10))), + UINT64( + CelMutableExpr.ofConstant(1, CelConstant.ofValue(UnsignedLong.valueOf(15))), + CelExpr.ofConstantExpr(1, CelConstant.ofValue(UnsignedLong.valueOf(15)))), + DOUBLE( + CelMutableExpr.ofConstant(1, CelConstant.ofValue(1.5)), + CelExpr.ofConstantExpr(1, CelConstant.ofValue(1.5))), + STRING( + CelMutableExpr.ofConstant(1, CelConstant.ofValue("Test")), + CelExpr.ofConstantExpr(1, CelConstant.ofValue("Test"))), + BYTES( + CelMutableExpr.ofConstant(1, CelConstant.ofValue(ByteString.copyFromUtf8("TEST"))), + CelExpr.ofConstantExpr(1, CelConstant.ofValue(ByteString.copyFromUtf8("TEST")))); + + final CelMutableExpr mutableExpr; + final CelExpr celExpr; + + ConstantTestCase(CelMutableExpr mutableExpr, CelExpr celExpr) { + this.mutableExpr = mutableExpr; + this.celExpr = celExpr; + } + } + + @Test + public void convertConstant_bidirectional(@TestParameter ConstantTestCase constantTestCase) { + CelExpr convertedCelExpr = + CelMutableExprConverter.fromMutableExpr(constantTestCase.mutableExpr); + CelMutableExpr convertedMutableExpr = + CelMutableExprConverter.fromCelExpr(constantTestCase.celExpr); + + assertThat(convertedCelExpr).isEqualTo(constantTestCase.celExpr); + assertThat(convertedMutableExpr).isEqualTo(constantTestCase.mutableExpr); + } + + @Test + public void convertMutableNotSet_toCelNotSet() { + CelMutableExpr mutableExpr = CelMutableExpr.ofNotSet(1L); + + CelExpr celExpr = CelMutableExprConverter.fromMutableExpr(mutableExpr); + + assertThat(celExpr).isEqualTo(CelExpr.ofNotSet(1L)); + } + + @Test + public void convertCelNotSet_toMutableNotSet() { + CelExpr celExpr = CelExpr.ofNotSet(1L); + + CelMutableExpr mutableExpr = CelMutableExprConverter.fromCelExpr(celExpr); + + assertThat(mutableExpr).isEqualTo(CelMutableExpr.ofNotSet(1L)); + } + + @Test + public void convertMutableIdent_toCelIdent() { + CelMutableExpr mutableExpr = CelMutableExpr.ofIdent(1L, "x"); + + CelExpr celExpr = CelMutableExprConverter.fromMutableExpr(mutableExpr); + + assertThat(celExpr).isEqualTo(CelExpr.ofIdentExpr(1L, "x")); + } + + @Test + public void convertCelIdent_toMutableIdent() { + CelExpr celExpr = CelExpr.ofIdentExpr(1L, "x"); + + CelMutableExpr mutableExpr = CelMutableExprConverter.fromCelExpr(celExpr); + + assertThat(mutableExpr).isEqualTo(CelMutableExpr.ofIdent(1L, "x")); + } + + @Test + public void convertMutableSelect_toCelSelect() { + CelMutableExpr mutableExpr = + CelMutableExpr.ofSelect( + 1L, + CelMutableSelect.create( + CelMutableExpr.ofIdent(2L, "x"), "field", /* testOnly= */ true)); + + CelExpr celExpr = CelMutableExprConverter.fromMutableExpr(mutableExpr); + + assertThat(celExpr) + .isEqualTo( + CelExpr.ofSelectExpr( + 1L, CelExpr.ofIdentExpr(2L, "x"), "field", /* isTestOnly= */ true)); + } + + @Test + public void convertCelSelect_toMutableSelect() { + CelExpr celExpr = + CelExpr.ofSelectExpr(1L, CelExpr.ofIdentExpr(2L, "x"), "field", /* isTestOnly= */ true); + + CelMutableExpr mutableExpr = CelMutableExprConverter.fromCelExpr(celExpr); + + assertThat(mutableExpr) + .isEqualTo( + CelMutableExpr.ofSelect( + 1L, + CelMutableSelect.create( + CelMutableExpr.ofIdent(2L, "x"), "field", /* testOnly= */ true))); + } + + @Test + public void convertMutableCall_toCelCall() { + CelMutableExpr mutableExpr = + CelMutableExpr.ofCall( + 1L, + CelMutableCall.create( + CelMutableExpr.ofConstant(2L, CelConstant.ofValue("target")), + "function", + CelMutableExpr.ofConstant(3L, CelConstant.ofValue("arg")))); + + CelExpr celExpr = CelMutableExprConverter.fromMutableExpr(mutableExpr); + + assertThat(celExpr) + .isEqualTo( + CelExpr.newBuilder() + .setId(1L) + .setCall( + CelCall.newBuilder() + .setFunction("function") + .setTarget(CelExpr.ofConstantExpr(2L, CelConstant.ofValue("target"))) + .addArgs(CelExpr.ofConstantExpr(3L, CelConstant.ofValue("arg"))) + .build()) + .build()); + } + + @Test + public void convertCelCall_toMutableCall() { + CelExpr celExpr = + CelExpr.newBuilder() + .setId(1L) + .setCall( + CelCall.newBuilder() + .setFunction("function") + .setTarget(CelExpr.ofConstantExpr(2L, CelConstant.ofValue("target"))) + .addArgs(CelExpr.ofConstantExpr(3L, CelConstant.ofValue("arg"))) + .build()) + .build(); + + CelMutableExpr mutableExpr = CelMutableExprConverter.fromCelExpr(celExpr); + + assertThat(mutableExpr) + .isEqualTo( + CelMutableExpr.ofCall( + 1L, + CelMutableCall.create( + CelMutableExpr.ofConstant(2L, CelConstant.ofValue("target")), + "function", + CelMutableExpr.ofConstant(3L, CelConstant.ofValue("arg"))))); + } + + @Test + public void convertMutableCreateList_toCelCreateList() { + CelMutableExpr mutableExpr = + CelMutableExpr.ofCreateList( + 1L, + CelMutableCreateList.create( + ImmutableList.of( + CelMutableExpr.ofConstant(2L, CelConstant.ofValue("element1")), + CelMutableExpr.ofConstant(3L, CelConstant.ofValue("element2"))), + ImmutableList.of(0, 1))); + + CelExpr celExpr = CelMutableExprConverter.fromMutableExpr(mutableExpr); + + assertThat(celExpr) + .isEqualTo( + CelExpr.ofCreateListExpr( + 1L, + ImmutableList.of( + CelExpr.ofConstantExpr(2L, CelConstant.ofValue("element1")), + CelExpr.ofConstantExpr(3L, CelConstant.ofValue("element2"))), + ImmutableList.of(0, 1))); + } + + @Test + public void convertCelCreateList_toMutableCreateList() { + CelExpr celExpr = + CelExpr.ofCreateListExpr( + 1L, + ImmutableList.of( + CelExpr.ofConstantExpr(2L, CelConstant.ofValue("element1")), + CelExpr.ofConstantExpr(3L, CelConstant.ofValue("element2"))), + ImmutableList.of(0, 1)); + + CelMutableExpr mutableExpr = CelMutableExprConverter.fromCelExpr(celExpr); + + assertThat(mutableExpr) + .isEqualTo( + CelMutableExpr.ofCreateList( + 1L, + CelMutableCreateList.create( + ImmutableList.of( + CelMutableExpr.ofConstant(2L, CelConstant.ofValue("element1")), + CelMutableExpr.ofConstant(3L, CelConstant.ofValue("element2"))), + ImmutableList.of(0, 1)))); + } + + @Test + public void convertMutableCreateStruct_toCelCreateStruct() { + CelMutableExpr mutableExpr = + CelMutableExpr.ofCreateStruct( + 8L, + CelMutableCreateStruct.create( + "message", + ImmutableList.of( + CelMutableCreateStruct.Entry.create( + 9L, + "field", + CelMutableExpr.ofConstant(10L, CelConstant.ofValue("value")), + /* optionalEntry= */ true)))); + + CelExpr celExpr = CelMutableExprConverter.fromMutableExpr(mutableExpr); + + assertThat(celExpr) + .isEqualTo( + CelExpr.ofCreateStructExpr( + 8L, + "message", + ImmutableList.of( + CelCreateStruct.Entry.newBuilder() + .setId(9L) + .setFieldKey("field") + .setValue(CelExpr.ofConstantExpr(10L, CelConstant.ofValue("value"))) + .setOptionalEntry(true) + .build()))); + } + + @Test + public void convertCelCreateStruct_toMutableCreateStruct() { + CelExpr celExpr = + CelExpr.ofCreateStructExpr( + 8L, + "message", + ImmutableList.of( + CelCreateStruct.Entry.newBuilder() + .setId(9L) + .setFieldKey("field") + .setValue(CelExpr.ofConstantExpr(10L, CelConstant.ofValue("value"))) + .setOptionalEntry(true) + .build())); + + CelMutableExpr mutableExpr = CelMutableExprConverter.fromCelExpr(celExpr); + + assertThat(mutableExpr) + .isEqualTo( + CelMutableExpr.ofCreateStruct( + 8L, + CelMutableCreateStruct.create( + "message", + ImmutableList.of( + CelMutableCreateStruct.Entry.create( + 9L, + "field", + CelMutableExpr.ofConstant(10L, CelConstant.ofValue("value")), + /* optionalEntry= */ true))))); + } + + @Test + public void convertMutableCreateMap_toCelCreateMap() { + CelMutableExpr mutableExpr = + CelMutableExpr.ofCreateMap( + 9L, + CelMutableCreateMap.create( + ImmutableList.of( + CelMutableCreateMap.Entry.create( + 10L, + CelMutableExpr.ofConstant(11L, CelConstant.ofValue("key")), + CelMutableExpr.ofConstant(12L, CelConstant.ofValue("value")), + /* optionalEntry= */ true)))); + + CelExpr celExpr = CelMutableExprConverter.fromMutableExpr(mutableExpr); + + assertThat(celExpr) + .isEqualTo( + CelExpr.ofCreateMapExpr( + 9L, + ImmutableList.of( + CelExpr.ofCreateMapEntryExpr( + 10L, + CelExpr.ofConstantExpr(11L, CelConstant.ofValue("key")), + CelExpr.ofConstantExpr(12L, CelConstant.ofValue("value")), + true)))); + } + + @Test + public void convertCelCreateMap_toMutableCreateMap() { + CelExpr celExpr = + CelExpr.ofCreateMapExpr( + 9L, + ImmutableList.of( + CelExpr.ofCreateMapEntryExpr( + 10L, + CelExpr.ofConstantExpr(11L, CelConstant.ofValue("key")), + CelExpr.ofConstantExpr(12L, CelConstant.ofValue("value")), + true))); + + CelMutableExpr mutableExpr = CelMutableExprConverter.fromCelExpr(celExpr); + + assertThat(mutableExpr) + .isEqualTo( + CelMutableExpr.ofCreateMap( + 9L, + CelMutableCreateMap.create( + ImmutableList.of( + CelMutableCreateMap.Entry.create( + 10L, + CelMutableExpr.ofConstant(11L, CelConstant.ofValue("key")), + CelMutableExpr.ofConstant(12L, CelConstant.ofValue("value")), + /* optionalEntry= */ true))))); + } + + @Test + public void convertMutableComprehension_toCelComprehension() { + CelMutableExpr mutableExpr = + CelMutableExpr.ofComprehension( + 1L, + CelMutableComprehension.create( + "iterVar", + CelMutableExpr.ofCreateList( + 2L, + CelMutableCreateList.create( + CelMutableExpr.ofConstant(3L, CelConstant.ofValue(true)))), + "accuVar", + CelMutableExpr.ofConstant(4L, CelConstant.ofValue(true)), + CelMutableExpr.ofConstant(5L, CelConstant.ofValue(true)), + CelMutableExpr.ofConstant(6L, CelConstant.ofValue(true)), + CelMutableExpr.ofIdent(7L, "__result__"))); + + CelExpr celExpr = CelMutableExprConverter.fromMutableExpr(mutableExpr); + + assertThat(celExpr) + .isEqualTo( + CelExpr.ofComprehension( + 1L, + "iterVar", + CelExpr.newBuilder() + .setId(2L) + .setCreateList( + CelCreateList.newBuilder() + .addElements(CelExpr.ofConstantExpr(3L, CelConstant.ofValue(true))) + .build()) + .build(), + "accuVar", + CelExpr.ofConstantExpr(4L, CelConstant.ofValue(true)), + CelExpr.ofConstantExpr(5L, CelConstant.ofValue(true)), + CelExpr.ofConstantExpr(6L, CelConstant.ofValue(true)), + CelExpr.ofIdentExpr(7L, "__result__"))); + } + + @Test + public void convertCelComprehension_toMutableComprehension() { + CelExpr celExpr = + CelExpr.ofComprehension( + 1L, + "iterVar", + CelExpr.newBuilder() + .setId(2L) + .setCreateList( + CelCreateList.newBuilder() + .addElements(CelExpr.ofConstantExpr(3L, CelConstant.ofValue(true))) + .build()) + .build(), + "accuVar", + CelExpr.ofConstantExpr(4L, CelConstant.ofValue(true)), + CelExpr.ofConstantExpr(5L, CelConstant.ofValue(true)), + CelExpr.ofConstantExpr(6L, CelConstant.ofValue(true)), + CelExpr.ofIdentExpr(7L, "__result__")); + + CelMutableExpr mutableExpr = CelMutableExprConverter.fromCelExpr(celExpr); + + assertThat(mutableExpr) + .isEqualTo( + CelMutableExpr.ofComprehension( + 1L, + CelMutableComprehension.create( + "iterVar", + CelMutableExpr.ofCreateList( + 2L, + CelMutableCreateList.create( + CelMutableExpr.ofConstant(3L, CelConstant.ofValue(true)))), + "accuVar", + CelMutableExpr.ofConstant(4L, CelConstant.ofValue(true)), + CelMutableExpr.ofConstant(5L, CelConstant.ofValue(true)), + CelMutableExpr.ofConstant(6L, CelConstant.ofValue(true)), + CelMutableExpr.ofIdent(7L, "__result__")))); + } +} From cd407c7acf0ca2b9678792afb83a959909e6fb45 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Tue, 16 Apr 2024 10:38:58 -0700 Subject: [PATCH 083/486] Specify better error message and code for invalid field selections PiperOrigin-RevId: 625380961 --- .../src/main/java/dev/cel/runtime/BUILD.bazel | 2 ++ .../runtime/DescriptorMessageProvider.java | 18 +++++------ .../RuntimeTypeProviderLegacyImpl.java | 30 ++++++++++++++++--- .../DescriptorMessageProviderTest.java | 4 +-- runtime/src/test/resources/dyn_error.baseline | 23 ++++++++++++++ .../dev/cel/testing/BaseInterpreterTest.java | 15 ++++++++++ 6 files changed, 77 insertions(+), 15 deletions(-) create mode 100644 runtime/src/test/resources/dyn_error.baseline diff --git a/runtime/src/main/java/dev/cel/runtime/BUILD.bazel b/runtime/src/main/java/dev/cel/runtime/BUILD.bazel index f9d3dc6a2..335c6e332 100644 --- a/runtime/src/main/java/dev/cel/runtime/BUILD.bazel +++ b/runtime/src/main/java/dev/cel/runtime/BUILD.bazel @@ -220,7 +220,9 @@ java_library( srcs = ["RuntimeTypeProviderLegacyImpl.java"], deps = [ ":unknown_attributes", + "//common:error_codes", "//common:options", + "//common:runtime_exception", "//common/annotations", "//common/internal:cel_descriptor_pools", "//common/internal:dynamic_proto", diff --git a/runtime/src/main/java/dev/cel/runtime/DescriptorMessageProvider.java b/runtime/src/main/java/dev/cel/runtime/DescriptorMessageProvider.java index e8f87f118..5c0931a00 100644 --- a/runtime/src/main/java/dev/cel/runtime/DescriptorMessageProvider.java +++ b/runtime/src/main/java/dev/cel/runtime/DescriptorMessageProvider.java @@ -168,7 +168,7 @@ public Object selectField(Object message, String fieldName) { } } - MessageOrBuilder typedMessage = assertFullProtoMessage(message); + MessageOrBuilder typedMessage = assertFullProtoMessage(message, fieldName); FieldDescriptor fieldDescriptor = findField(typedMessage.getDescriptorForType(), fieldName); // check whether the field is a wrapper type, then test has and return null if (isWrapperType(fieldDescriptor) && !typedMessage.hasField(fieldDescriptor)) { @@ -202,7 +202,7 @@ public Object hasField(Object message, String fieldName) { return map.containsKey(fieldName); } - MessageOrBuilder typedMessage = assertFullProtoMessage(message); + MessageOrBuilder typedMessage = assertFullProtoMessage(message, fieldName); FieldDescriptor fieldDescriptor = findField(typedMessage.getDescriptorForType(), fieldName); if (fieldDescriptor.isRepeated()) { return typedMessage.getRepeatedFieldCount(fieldDescriptor) > 0; @@ -228,16 +228,16 @@ private FieldDescriptor findField(Descriptor descriptor, String fieldName) { return fieldDescriptor; } - private static MessageOrBuilder assertFullProtoMessage(Object candidate) { + private static MessageOrBuilder assertFullProtoMessage(Object candidate, String fieldName) { if (!(candidate instanceof MessageOrBuilder)) { - // This is an internal error. It should not happen for type checked expressions. + // This can happen when the field selection is done on dyn, and it is not a message. throw new CelRuntimeException( - new IllegalStateException( + new IllegalArgumentException( String.format( - "[internal] expected an instance of 'com.google.protobuf.MessageOrBuilder' " - + "but found '%s'", - candidate.getClass().getName())), - CelErrorCode.INTERNAL_ERROR); + "Error resolving field '%s'. Field selections must be performed on messages or" + + " maps.", + fieldName)), + CelErrorCode.ATTRIBUTE_NOT_FOUND); } return (MessageOrBuilder) candidate; } diff --git a/runtime/src/main/java/dev/cel/runtime/RuntimeTypeProviderLegacyImpl.java b/runtime/src/main/java/dev/cel/runtime/RuntimeTypeProviderLegacyImpl.java index 841d702a2..96dc40d0c 100644 --- a/runtime/src/main/java/dev/cel/runtime/RuntimeTypeProviderLegacyImpl.java +++ b/runtime/src/main/java/dev/cel/runtime/RuntimeTypeProviderLegacyImpl.java @@ -19,7 +19,9 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; import com.google.errorprone.annotations.Immutable; +import dev.cel.common.CelErrorCode; import dev.cel.common.CelOptions; +import dev.cel.common.CelRuntimeException; import dev.cel.common.annotations.Internal; import dev.cel.common.internal.CelDescriptorPool; import dev.cel.common.internal.DynamicProto; @@ -69,8 +71,18 @@ public Object createMessage(String messageName, Map values) { @Override @SuppressWarnings("unchecked") public Object selectField(Object message, String fieldName) { - SelectableValue selectableValue = - (SelectableValue) protoCelValueConverter.fromJavaObjectToCelValue(message); + CelValue convertedCelValue = protoCelValueConverter.fromJavaObjectToCelValue(message); + if (!(convertedCelValue instanceof SelectableValue)) { + throw new CelRuntimeException( + new IllegalArgumentException( + String.format( + "Error resolving field '%s'. Field selections must be performed on messages or" + + " maps.", + fieldName)), + CelErrorCode.ATTRIBUTE_NOT_FOUND); + } + + SelectableValue selectableValue = (SelectableValue) convertedCelValue; return unwrapCelValue(selectableValue.select(StringValue.create(fieldName))); } @@ -78,8 +90,18 @@ public Object selectField(Object message, String fieldName) { @Override @SuppressWarnings("unchecked") public Object hasField(Object message, String fieldName) { - SelectableValue selectableValue = - (SelectableValue) protoCelValueConverter.fromJavaObjectToCelValue(message); + CelValue convertedCelValue = protoCelValueConverter.fromJavaObjectToCelValue(message); + if (!(convertedCelValue instanceof SelectableValue)) { + throw new CelRuntimeException( + new IllegalArgumentException( + String.format( + "Error resolving field '%s'. Field selections must be performed on messages or" + + " maps.", + fieldName)), + CelErrorCode.ATTRIBUTE_NOT_FOUND); + } + + SelectableValue selectableValue = (SelectableValue) convertedCelValue; return selectableValue.find(StringValue.create(fieldName)).isPresent(); } diff --git a/runtime/src/test/java/dev/cel/runtime/DescriptorMessageProviderTest.java b/runtime/src/test/java/dev/cel/runtime/DescriptorMessageProviderTest.java index 2421d2daf..afe7ca4c0 100644 --- a/runtime/src/test/java/dev/cel/runtime/DescriptorMessageProviderTest.java +++ b/runtime/src/test/java/dev/cel/runtime/DescriptorMessageProviderTest.java @@ -165,8 +165,8 @@ public void selectField_nonProtoObjectError() { CelRuntimeException e = Assert.assertThrows( CelRuntimeException.class, () -> provider.selectField("hello", "not_a_field")); - assertThat(e).hasCauseThat().isInstanceOf(IllegalStateException.class); - assertThat(e.getErrorCode()).isEqualTo(CelErrorCode.INTERNAL_ERROR); + assertThat(e).hasCauseThat().isInstanceOf(IllegalArgumentException.class); + assertThat(e.getErrorCode()).isEqualTo(CelErrorCode.ATTRIBUTE_NOT_FOUND); } @Test diff --git a/runtime/src/test/resources/dyn_error.baseline b/runtime/src/test/resources/dyn_error.baseline new file mode 100644 index 000000000..00a0766cd --- /dev/null +++ b/runtime/src/test/resources/dyn_error.baseline @@ -0,0 +1,23 @@ +Source: dyn('hello').invalid +=====> +bindings: {} +error: evaluation error at test_location:12: Error resolving field 'invalid'. Field selections must be performed on messages or maps. +error_code: ATTRIBUTE_NOT_FOUND + +Source: has(dyn('hello').invalid) +=====> +bindings: {} +error: evaluation error at test_location:3: Error resolving field 'invalid'. Field selections must be performed on messages or maps. +error_code: ATTRIBUTE_NOT_FOUND + +Source: dyn([]).invalid +=====> +bindings: {} +error: evaluation error at test_location:7: Error resolving field 'invalid'. Field selections must be performed on messages or maps. +error_code: ATTRIBUTE_NOT_FOUND + +Source: has(dyn([]).invalid) +=====> +bindings: {} +error: evaluation error at test_location:3: Error resolving field 'invalid'. Field selections must be performed on messages or maps. +error_code: ATTRIBUTE_NOT_FOUND diff --git a/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java b/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java index 88a4fd8ba..0addafaf9 100644 --- a/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java +++ b/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java @@ -1600,6 +1600,21 @@ public void dynConversions() throws Exception { runTest(Activation.EMPTY); } + @Test + public void dyn_error() throws Exception { + source = "dyn('hello').invalid"; + runTest(Activation.EMPTY); + + source = "has(dyn('hello').invalid)"; + runTest(Activation.EMPTY); + + source = "dyn([]).invalid"; + runTest(Activation.EMPTY); + + source = "has(dyn([]).invalid)"; + runTest(Activation.EMPTY); + } + // This lambda implements @Immutable interface 'Function', but 'InterpreterTest' has field 'eval' // of type 'com.google.api.expr.cel.testing.Eval', the declaration of // type From 38484af293725aaa62806480ec6d67b54a8097ac Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Tue, 16 Apr 2024 11:14:55 -0700 Subject: [PATCH 084/486] Introduce a common expression tree interface between CelExpr and CelMutableExpr PiperOrigin-RevId: 625393691 --- .../main/java/dev/cel/common/ast/BUILD.bazel | 1 + .../main/java/dev/cel/common/ast/CelExpr.java | 235 +++++---------- .../dev/cel/common/ast/CelMutableExpr.java | 93 ++++-- .../java/dev/cel/common/ast/Expression.java | 280 ++++++++++++++++++ 4 files changed, 413 insertions(+), 196 deletions(-) create mode 100644 common/src/main/java/dev/cel/common/ast/Expression.java diff --git a/common/src/main/java/dev/cel/common/ast/BUILD.bazel b/common/src/main/java/dev/cel/common/ast/BUILD.bazel index b26181303..ac4df5487 100644 --- a/common/src/main/java/dev/cel/common/ast/BUILD.bazel +++ b/common/src/main/java/dev/cel/common/ast/BUILD.bazel @@ -13,6 +13,7 @@ AST_SOURCES = [ "CelExpr.java", "CelExprFormatter.java", "CelReference.java", + "Expression.java", ] # keep sorted diff --git a/common/src/main/java/dev/cel/common/ast/CelExpr.java b/common/src/main/java/dev/cel/common/ast/CelExpr.java index f494aa114..3970c8598 100644 --- a/common/src/main/java/dev/cel/common/ast/CelExpr.java +++ b/common/src/main/java/dev/cel/common/ast/CelExpr.java @@ -31,104 +31,102 @@ import java.util.Optional; /** - * An abstract representation of a common expression. + * An abstract representation of a common expression. Refer to {@link Expression} for details. * *

This is the native type equivalent of Expr message in syntax.proto. - * - *

Expressions are abstractly represented as a collection of identifiers, select statements, - * function calls, literals, and comprehensions. All operators with the exception of the '.' - * operator are modelled as function calls. This makes it easy to represent new operators into the - * existing AST. - * - *

All references within expressions must resolve to a [Decl][] provided at type-check for an - * expression to be valid. A reference may either be a bare identifier `name` or a qualified - * identifier `google.api.name`. References may either refer to a value or a function declaration. - * - *

For example, the expression `google.api.name.startsWith('expr')` references the declaration - * `google.api.name` within a [Expr.Select][] expression, and the function declaration `startsWith`. */ @AutoValue @Internal @Immutable -public abstract class CelExpr { +public abstract class CelExpr implements Expression { - /** - * Required. An id assigned to this node by the parser which is unique in a given expression tree. - * This is used to associate type information and other attributes to a node in the parse tree. - */ + @Override public abstract long id(); /** Represents the variant of the expression. */ public abstract ExprKind exprKind(); + @Override + public ExprKind.Kind getKind() { + return exprKind().getKind(); + } + /** - * Gets the underlying constant expression. + * {@inheritDoc} * * @throws UnsupportedOperationException if expression is not {@link Kind#CONSTANT}. */ + @Override public CelConstant constant() { return exprKind().constant(); } /** - * Gets the underlying identifier expression. + * {@inheritDoc} * * @throws UnsupportedOperationException if expression is not {@link Kind#IDENT}. */ + @Override public CelIdent ident() { return exprKind().ident(); } /** - * Gets the underlying select expression. + * {@inheritDoc} * * @throws UnsupportedOperationException if expression is not {@link Kind#SELECT}. */ + @Override public CelSelect select() { return exprKind().select(); } /** - * Gets the underlying call expression. + * {@inheritDoc} * * @throws UnsupportedOperationException if expression is not {@link Kind#CALL}. */ + @Override public CelCall call() { return exprKind().call(); } /** - * Gets the underlying createList expression. + * {@inheritDoc} * * @throws UnsupportedOperationException if expression is not {@link Kind#CREATE_LIST}. */ + @Override public CelCreateList createList() { return exprKind().createList(); } /** - * Gets the underlying createStruct expression. + * {@inheritDoc} * * @throws UnsupportedOperationException if expression is not {@link Kind#CREATE_STRUCT}. */ + @Override public CelCreateStruct createStruct() { return exprKind().createStruct(); } /** - * Gets the underlying createMap expression. + * {@inheritDoc} * * @throws UnsupportedOperationException if expression is not {@link Kind#createMap}. */ + @Override public CelCreateMap createMap() { return exprKind().createMap(); } /** - * Gets the underlying comprehension expression. + * {@inheritDoc} * * @throws UnsupportedOperationException if expression is not {@link Kind#COMPREHENSION}. */ + @Override public CelComprehension comprehension() { return exprKind().comprehension(); } @@ -401,12 +399,9 @@ public abstract static class CelNotSet {} /** An identifier expression. e.g. `request`. */ @AutoValue @Immutable - public abstract static class CelIdent { - /** - * Required. Holds a single, unqualified identifier, possibly preceded by a '.'. - * - *

Qualified names are represented by the [Expr.Select][] expression. - */ + public abstract static class CelIdent implements Ident { + + @Override public abstract String name(); /** Builder for CelIdent. */ @@ -429,29 +424,15 @@ public static Builder newBuilder() { /** A field selection expression. e.g. `request.auth`. */ @AutoValue @Immutable - public abstract static class CelSelect { + public abstract static class CelSelect implements Expression.Select { - /** - * Required. The target of the selection expression. - * - *

For example, in the select expression `request.auth`, the `request` portion of the - * expression is the `operand`. - */ + @Override public abstract CelExpr operand(); - /** - * Required. The name of the field to select. - * - *

For example, in the select expression `request.auth`, the `auth` portion of the expression - * would be the `field`. - */ + @Override public abstract String field(); - /** - * Whether the select is to be interpreted as a field presence test. - * - *

This results from the macro `has(request.auth)`. - */ + @Override public abstract boolean testOnly(); /** Builder for CelSelect. */ @@ -483,25 +464,18 @@ public static Builder newBuilder() { } } - /** - * A call expression, including calls to predefined functions and operators. - * - *

For example, `value == 10`, `size(map_value)`. - */ + /** A call expression. See {@link Expression.Call} */ @AutoValue @Immutable - public abstract static class CelCall { + public abstract static class CelCall implements Expression.Call { - /** - * The target of a method call-style expression. - * - *

For example, `x` in `x.f()`. - */ + @Override public abstract Optional target(); - /** Required. The name of the function or method being called. */ + @Override public abstract String function(); + @Override public abstract ImmutableList args(); /** Builder for CelCall. */ @@ -587,24 +561,14 @@ public static Builder newBuilder() { } } - /** - * A list creation expression. - * - *

Lists may either be homogenous, e.g. `[1, 2, 3]`, or heterogeneous, e.g. `dyn([1, 'hello', - * 2.0])` - */ + /** A list creation expression. See {@link Expression.CreateList} */ @AutoValue @Immutable - public abstract static class CelCreateList { - /** The elements part of the list */ + public abstract static class CelCreateList implements Expression.CreateList { + @Override public abstract ImmutableList elements(); - /** - * The indices within the elements list which are marked as optional elements. - * - *

When an optional-typed value is present, the value it contains is included in the list. If - * the optional-typed value is absent, the list element is omitted from the CreateList result. - */ + @Override public abstract ImmutableList optionalIndices(); /** Builder for CelCreateList. */ @@ -689,19 +653,15 @@ public static Builder newBuilder() { } } - /** - * A message creation expression. - * - *

Messages are constructed with a type name and composed of field ids: `types.MyType{field_id: - * 'value'}`. - */ + /** A message creation expression. See {@link Expression.CreateStruct} */ @AutoValue @Immutable - public abstract static class CelCreateStruct { - /** The type name of the message to be created, empty when creating map literals. */ + public abstract static class CelCreateStruct + implements Expression.CreateStruct { + @Override public abstract String messageName(); - /** The entries in the creation expression. */ + @Override public abstract ImmutableList entries(); /** Builder for CelCreateStruct. */ @@ -777,26 +737,18 @@ public static Builder newBuilder() { /** Represents an entry of the struct */ @AutoValue @Immutable - public abstract static class Entry { - /** - * Required. An id assigned to this node by the parser which is unique in a given expression - * tree. This is used to associate type information and other attributes to the node. - */ + public abstract static class Entry implements Expression.CreateStruct.Entry { + + @Override public abstract long id(); - /** Entry key kind. */ + @Override public abstract String fieldKey(); - /** - * Required. The value assigned to the key. - * - *

If the optional_entry field is true, the expression must resolve to an optional-typed - * value. If the optional value is present, the key will be set; however, if the optional - * value is absent, the key will be unset. - */ + @Override public abstract CelExpr value(); - /** Whether the key-value pair is optional. */ + @Override public abstract boolean optionalEntry(); /** Builder for CelCreateStruct.Entry. */ @@ -829,15 +781,12 @@ public static Builder newBuilder() { } } - /** - * A map creation expression. - * - *

Maps are constructed as `{'key_name': 'value'}`. - */ + /** A map creation expression. See {@link Expression.CreateMap} */ @AutoValue @Immutable - public abstract static class CelCreateMap { + public abstract static class CelCreateMap implements Expression.CreateMap { /** The entries in the creation expression. */ + @Override public abstract ImmutableList entries(); /** Builder for CelCreateMap. */ @@ -908,29 +857,21 @@ public static Builder newBuilder() { return new AutoValue_CelExpr_CelCreateMap.Builder(); } - /** Represents an entry of the map */ + /** Represents an entry of the map. */ @AutoValue @Immutable - public abstract static class Entry { - /** - * Required. An id assigned to this node by the parser which is unique in a given expression - * tree. This is used to associate type information and other attributes to the node. - */ + public abstract static class Entry implements Expression.CreateMap.Entry { + + @Override public abstract long id(); - /** Required. The key. */ + @Override public abstract CelExpr key(); - /** - * Required. The value assigned to the key. - * - *

If the optional_entry field is true, the expression must resolve to an optional-typed - * value. If the optional value is present, the key will be set; however, if the optional - * value is absent, the key will be unset. - */ + @Override public abstract CelExpr value(); - /** Whether the key-value pair is optional. */ + @Override public abstract boolean optionalEntry(); /** Builder for CelCreateMap.Entry. */ @@ -962,65 +903,29 @@ public static CelCreateMap.Entry.Builder newBuilder() { } } - /** - * A comprehension expression applied to a list or map. - * - *

Comprehensions are not part of the core syntax, but enabled with macros. A macro matches a - * specific call signature within a parsed AST and replaces the call with an alternate AST block. - * Macro expansion happens at parse time. - * - *

The following macros are supported within CEL: - * - *

Aggregate type macros may be applied to all elements in a list or all keys in a map: - * - *

`all`, `exists`, `exists_one` - test a predicate expression against the inputs and return - * `true` if the predicate is satisfied for all, any, or only one value `list.all(x, x < 10)`. - * `filter` - test a predicate expression against the inputs and return the subset of elements - * which satisfy the predicate: `payments.filter(p, p > 1000)`. `map` - apply an expression to all - * elements in the input and return the output aggregate type: `[1, 2, 3].map(i, i * i)`. - * - *

The `has(m.x)` macro tests whether the property `x` is present in struct `m`. The semantics - * of this macro depend on the type of `m`. For proto2 messages `has(m.x)` is defined as 'defined, - * but not set`. For proto3, the macro tests whether the property is set to its default. For map - * and struct types, the macro tests whether the property `x` is defined on `m`. - * - *

Comprehension evaluation can be best visualized as the following pseudocode: - */ + /** A comprehension expression applied to a list or map. See {@link Expression.Comprehension} */ @AutoValue @Immutable - public abstract static class CelComprehension { - /** The name of the iteration variable. */ + public abstract static class CelComprehension implements Expression.Comprehension { + @Override public abstract String iterVar(); - /** The range over which var iterates. */ + @Override public abstract CelExpr iterRange(); - /** The name of the variable used for accumulation of the result. */ + @Override public abstract String accuVar(); - /** The initial value of the accumulator. */ + @Override public abstract CelExpr accuInit(); - /** - * An expression which can contain iter_var and accu_var. - * - *

Returns false when the result has been computed and may be used as a hint to short-circuit - * the remainder of the comprehension. - */ + @Override public abstract CelExpr loopCondition(); - /** - * An expression which can contain iter_var and accu_var. - * - *

Computes the next value of accu_var. - */ + @Override public abstract CelExpr loopStep(); - /** - * An expression which can contain accu_var. - * - *

Computes the result. - */ + @Override public abstract CelExpr result(); /** Builder for Comprehension. */ diff --git a/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java b/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java index 7b84826f1..0a44f4234 100644 --- a/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java +++ b/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java @@ -28,18 +28,21 @@ /** * An abstract representation of a common expression that allows mutation in any of its properties. - * The expressions are semantically the same as that of the immutable {@link CelExpr}. + * The expressions are semantically the same as that of the immutable {@link CelExpr}. Refer to + * {@link Expression} for details. * *

This allows for an efficient optimization of an AST without having to traverse and rebuild the * entire tree. * *

This class is not thread-safe by design. */ -public final class CelMutableExpr { +@SuppressWarnings("unchecked") // Class ensures only the super type is used +public final class CelMutableExpr implements Expression { private long id; private ExprKind.Kind exprKind; private Object exprValue; + @Override public long id() { return id; } @@ -48,6 +51,7 @@ public void setId(long id) { this.id = id; } + @Override public ExprKind.Kind getKind() { return exprKind; } @@ -57,41 +61,49 @@ public CelNotSet notSet() { return (CelNotSet) exprValue; } + @Override public CelConstant constant() { checkExprKind(Kind.CONSTANT); return (CelConstant) exprValue; } + @Override public CelMutableIdent ident() { checkExprKind(Kind.IDENT); return (CelMutableIdent) exprValue; } + @Override public CelMutableSelect select() { checkExprKind(Kind.SELECT); return (CelMutableSelect) exprValue; } + @Override public CelMutableCall call() { checkExprKind(Kind.CALL); return (CelMutableCall) exprValue; } + @Override public CelMutableCreateList createList() { checkExprKind(Kind.CREATE_LIST); return (CelMutableCreateList) exprValue; } + @Override public CelMutableCreateStruct createStruct() { checkExprKind(Kind.CREATE_STRUCT); return (CelMutableCreateStruct) exprValue; } + @Override public CelMutableCreateMap createMap() { checkExprKind(Kind.CREATE_MAP); return (CelMutableCreateMap) exprValue; } + @Override public CelMutableComprehension comprehension() { checkExprKind(Kind.COMPREHENSION); return (CelMutableComprehension) exprValue; @@ -138,9 +150,10 @@ public void setComprehension(CelMutableComprehension comprehension) { } /** A mutable identifier expression. */ - public static final class CelMutableIdent { + public static final class CelMutableIdent implements Ident { private String name = ""; + @Override public String name() { return name; } @@ -181,11 +194,12 @@ private CelMutableIdent(String name) { } /** A mutable field selection expression. e.g. `request.auth`. */ - public static final class CelMutableSelect { + public static final class CelMutableSelect implements Expression.Select { private CelMutableExpr operand; private String field = ""; private boolean testOnly; + @Override public CelMutableExpr operand() { return operand; } @@ -194,6 +208,7 @@ public void setOperand(CelMutableExpr operand) { this.operand = checkNotNull(operand); } + @Override public String field() { return field; } @@ -202,6 +217,7 @@ public void setField(String field) { this.field = checkNotNull(field); } + @Override public boolean testOnly() { return testOnly; } @@ -255,12 +271,13 @@ private CelMutableSelect(CelMutableExpr operand, String field, boolean testOnly) } } - /** A mutable call expression, including calls to predefined functions and operators. */ - public static final class CelMutableCall { + /** A mutable call expression. See {@link Expression.Call} */ + public static final class CelMutableCall implements Expression.Call { private Optional target; private String function; private List args; + @Override public Optional target() { return target; } @@ -269,6 +286,7 @@ public void setTarget(CelMutableExpr target) { this.target = Optional.of(target); } + @Override public String function() { return function; } @@ -277,6 +295,7 @@ public void setFunction(String function) { this.function = checkNotNull(function); } + @Override public List args() { return args; } @@ -366,16 +385,12 @@ private CelMutableCall(CelMutableExpr target, String function, ListLists may either be homogenous, e.g. `[1, 2, 3]`, or heterogeneous, e.g. `dyn([1, 'hello', - * 2.0])` - */ - public static final class CelMutableCreateList { + /** A mutable list creation expression. See {@link Expression.CreateList} */ + public static final class CelMutableCreateList implements Expression.CreateList { private final List elements; private final List optionalIndices; + @Override public List elements() { return elements; } @@ -385,6 +400,7 @@ public void setElement(int index, CelMutableExpr element) { elements.set(index, checkNotNull(element)); } + @Override public List optionalIndices() { return optionalIndices; } @@ -438,16 +454,13 @@ private CelMutableCreateList( } } - /** - * A mutable list creation expression. - * - *

Lists may either be homogenous, e.g. `[1, 2, 3]`, or heterogeneous, e.g. `dyn([1, 'hello', - * 2.0])` - */ - public static final class CelMutableCreateStruct { + /** A mutable list creation expression. See {@link Expression.CreateStruct} */ + public static final class CelMutableCreateStruct + implements Expression.CreateStruct { private String messageName = ""; private List entries; + @Override public String messageName() { return messageName; } @@ -456,6 +469,7 @@ public void setMessageName(String messageName) { this.messageName = checkNotNull(messageName); } + @Override public List entries() { return entries; } @@ -469,13 +483,14 @@ public void setEntry(int index, CelMutableCreateStruct.Entry entry) { entries.set(index, checkNotNull(entry)); } - /** Represents a mutable entry of the struct */ - public static final class Entry { + /** Represents a mutable entry of the struct. */ + public static final class Entry implements Expression.CreateStruct.Entry { private long id; private String fieldKey = ""; private CelMutableExpr value; private boolean optionalEntry; + @Override public long id() { return id; } @@ -484,6 +499,7 @@ public void setId(long id) { this.id = id; } + @Override public String fieldKey() { return fieldKey; } @@ -492,6 +508,7 @@ public void setFieldKey(String fieldKey) { this.fieldKey = checkNotNull(fieldKey); } + @Override public CelMutableExpr value() { return value; } @@ -500,6 +517,7 @@ public void setValue(CelMutableExpr value) { this.value = checkNotNull(value); } + @Override public boolean optionalEntry() { return optionalEntry; } @@ -600,14 +618,12 @@ private CelMutableCreateStruct(String messageName, ListMaps are constructed as `{'key_name': 'value'}`. - */ - public static final class CelMutableCreateMap { + /** A mutable map creation expression. See {@link Expression.CreateMap} */ + public static final class CelMutableCreateMap + implements Expression.CreateMap { private List entries; + @Override public List entries() { return entries; } @@ -622,12 +638,13 @@ public void setEntry(int index, CelMutableCreateMap.Entry entry) { } /** Represents an entry of the map */ - public static final class Entry { + public static final class Entry implements Expression.CreateMap.Entry { private long id; private CelMutableExpr key; private CelMutableExpr value; private boolean optionalEntry; + @Override public long id() { return id; } @@ -636,6 +653,7 @@ public void setId(long id) { this.id = id; } + @Override public CelMutableExpr key() { return key; } @@ -644,6 +662,7 @@ public void setKey(CelMutableExpr key) { this.key = checkNotNull(key); } + @Override public CelMutableExpr value() { return value; } @@ -652,6 +671,7 @@ public void setValue(CelMutableExpr value) { this.value = checkNotNull(value); } + @Override public boolean optionalEntry() { return optionalEntry; } @@ -752,8 +772,12 @@ private CelMutableCreateMap(List entries) { } } - /** A mutable comprehension expression applied to a list or map. */ - public static final class CelMutableComprehension { + /** + * A mutable comprehension expression applied to a list or map. See {@link + * Expression.Comprehension} + */ + public static final class CelMutableComprehension + implements Expression.Comprehension { private String iterVar; @@ -769,6 +793,7 @@ public static final class CelMutableComprehension { private CelMutableExpr result; + @Override public String iterVar() { return iterVar; } @@ -777,6 +802,7 @@ public void setIterVar(String iterVar) { this.iterVar = checkNotNull(iterVar); } + @Override public CelMutableExpr iterRange() { return iterRange; } @@ -785,6 +811,7 @@ public void setIterRange(CelMutableExpr iterRange) { this.iterRange = checkNotNull(iterRange); } + @Override public String accuVar() { return accuVar; } @@ -793,6 +820,7 @@ public void setAccuVar(String accuVar) { this.accuVar = checkNotNull(accuVar); } + @Override public CelMutableExpr accuInit() { return accuInit; } @@ -801,6 +829,7 @@ public void setAccuInit(CelMutableExpr accuInit) { this.accuInit = checkNotNull(accuInit); } + @Override public CelMutableExpr loopCondition() { return loopCondition; } @@ -809,6 +838,7 @@ public void setLoopCondition(CelMutableExpr loopCondition) { this.loopCondition = checkNotNull(loopCondition); } + @Override public CelMutableExpr loopStep() { return loopStep; } @@ -817,6 +847,7 @@ public void setLoopStep(CelMutableExpr loopStep) { this.loopStep = checkNotNull(loopStep); } + @Override public CelMutableExpr result() { return result; } diff --git a/common/src/main/java/dev/cel/common/ast/Expression.java b/common/src/main/java/dev/cel/common/ast/Expression.java new file mode 100644 index 000000000..3c2f7a4ed --- /dev/null +++ b/common/src/main/java/dev/cel/common/ast/Expression.java @@ -0,0 +1,280 @@ +// Copyright 2024 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.common.ast; + +import dev.cel.common.annotations.Internal; +import java.util.List; +import java.util.Optional; + +/** + * An abstract representation of a common expression. + * + *

Expressions are abstractly represented as a collection of identifiers, select statements, + * function calls, literals, and comprehensions. All operators with the exception of the '.' + * operator are modelled as function calls. This makes it easy to represent new operators into the + * existing AST. + * + *

All references within expressions must resolve to a [Decl][] provided at type-check for an + * expression to be valid. A reference may either be a bare identifier `name` or a qualified + * identifier `google.api.name`. References may either refer to a value or a function declaration. + * + *

For example, the expression `google.api.name.startsWith('expr')` references the declaration + * `google.api.name` within a [Expr.Select][] expression, and the function declaration `startsWith`. + */ +@Internal +public interface Expression { + + /** + * Required. An id assigned to this node by the parser which is unique in a given expression tree. + * This is used to associate type information and other attributes to a node in the parse tree. + */ + long id(); + + /** Represents the enumeration value for the underlying expression kind. */ + CelExpr.ExprKind.Kind getKind(); + + /** Gets the underlying constant expression. */ + CelConstant constant(); + + /** Gets the underlying identifier expression. */ + Ident ident(); + + /** Gets the underlying call expression. */ + Call call(); + + /** Gets the underlying identifier expression. */ + CreateList createList(); + + /** Gets the underlying select expression. */ + Select select(); + + /** Gets the underlying createStruct expression. */ + CreateStruct> createStruct(); + + /** Gets the underlying createMap expression. */ + CreateMap> createMap(); + + /** Gets the underlying comprehension expression. */ + Comprehension comprehension(); + + /** An identifier expression. e.g. `request`. */ + interface Ident { + + /** + * Required. Holds a single, unqualified identifier, possibly preceded by a '.'. + * + *

Qualified names are represented by the [Expr.Select][] expression. + */ + String name(); + } + + /** A call expression, including calls to predefined functions and operators. */ + interface Call { + /** + * The target of a method call-style expression. + * + *

For example, `x` in `x.f()`. + */ + Optional target(); + + /** Required. The name of the function or method being called. */ + String function(); + + /** + * Arguments to the call. + * + *

For example, `foo` in `f(foo)` or `x.f(foo)`. + */ + List args(); + } + + /** + * A list creation expression. + * + *

Lists may either be homogenous, e.g. `[1, 2, 3]`, or heterogeneous, e.g. `dyn([1, 'hello', + * 2.0])` + */ + interface CreateList { + + /** The elements part of the list */ + List elements(); + + /** + * The indices within the elements list which are marked as optional elements. + * + *

When an optional-typed value is present, the value it contains is included in the list. If + * the optional-typed value is absent, the list element is omitted from the CreateList result. + */ + List optionalIndices(); + } + + /** A field selection expression. e.g. `request.auth`. */ + interface Select { + /** + * Required. The target of the selection expression. + * + *

For example, in the select expression `request.auth`, the `request` portion of the + * expression is the `operand`. + */ + E operand(); + + /** + * Required. The name of the field to select. + * + *

For example, in the select expression `request.auth`, the `auth` portion of the expression + * would be the `field`. + */ + String field(); + + /** + * Whether the select is to be interpreted as a field presence test. + * + *

This results from the macro `has(request.auth)`. + */ + boolean testOnly(); + } + + /** + * A message creation expression. + * + *

Messages are constructed with a type name and composed of field ids: `types.MyType{field_id: + * 'value'}`. + */ + interface CreateStruct> { + + /** The type name of the message to be created, empty when creating map literals. */ + String messageName(); + + /** The entries in the creation expression. */ + List entries(); + + /** Represents an entry of the struct */ + interface Entry { + /** + * Required. An id assigned to this node by the parser which is unique in a given expression + * tree. This is used to associate type information and other attributes to the node. + */ + long id(); + + /** Entry key kind. */ + String fieldKey(); + + /** + * Required. The value assigned to the key. + * + *

If the optional_entry field is true, the expression must resolve to an optional-typed + * value. If the optional value is present, the key will be set; however, if the optional + * value is absent, the key will be unset. + */ + T value(); + + /** Whether the key-value pair is optional. */ + boolean optionalEntry(); + } + } + + /** + * A map creation expression. + * + *

Maps are constructed as `{'key_name': 'value'}`. + */ + interface CreateMap> { + + List entries(); + + /** Represents an entry of the map. */ + interface Entry { + /** + * Required. An id assigned to this node by the parser which is unique in a given expression + * tree. This is used to associate type information and other attributes to the node. + */ + long id(); + + /** Required. The key. */ + T key(); + + /** + * Required. The value assigned to the key. + * + *

If the optional_entry field is true, the expression must resolve to an optional-typed + * value. If the optional value is present, the key will be set; however, if the optional + * value is absent, the key will be unset. + */ + T value(); + + boolean optionalEntry(); + } + } + + /** + * A comprehension expression applied to a list or map. + * + *

Comprehensions are not part of the core syntax, but enabled with macros. A macro matches a + * specific call signature within a parsed AST and replaces the call with an alternate AST block. + * Macro expansion happens at parse time. + * + *

The following macros are supported within CEL: + * + *

Aggregate type macros may be applied to all elements in a list or all keys in a map: + * + *

`all`, `exists`, `exists_one` - test a predicate expression against the inputs and return + * `true` if the predicate is satisfied for all, any, or only one value `list.all(x, x < 10)`. + * `filter` - test a predicate expression against the inputs and return the subset of elements + * which satisfy the predicate: `payments.filter(p, p > 1000)`. `map` - apply an expression to all + * elements in the input and return the output aggregate type: `[1, 2, 3].map(i, i * i)`. + * + *

The `has(m.x)` macro tests whether the property `x` is present in struct `m`. The semantics + * of this macro depend on the type of `m`. For proto2 messages `has(m.x)` is defined as 'defined, + * but not set`. For proto3, the macro tests whether the property is set to its default. For map + * and struct types, the macro tests whether the property `x` is defined on `m`. + * + *

Comprehension evaluation can be best visualized as the following pseudocode: + */ + interface Comprehension { + /** The name of the iteration variable. */ + String iterVar(); + + /** The range over which var iterates. */ + E iterRange(); + + /** The name of the variable used for accumulation of the result. */ + String accuVar(); + + /** The initial value of the accumulator. */ + E accuInit(); + + /** + * An expression which can contain iter_var and accu_var. + * + *

Returns false when the result has been computed and may be used as a hint to short-circuit + * the remainder of the comprehension. + */ + E loopCondition(); + + /** + * An expression which can contain iter_var and accu_var. + * + *

Computes the next value of accu_var. + */ + E loopStep(); + + /** + * An expression which can contain accu_var. + * + *

Computes the result. + */ + E result(); + } +} From 6764cc37c5fc4d2787f39f7a49c1933e9cfef54c Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Tue, 16 Apr 2024 11:35:06 -0700 Subject: [PATCH 085/486] Create a base navigable class that accepts a bound generic type of an expression. PiperOrigin-RevId: 625400984 --- .../dev/cel/common/navigation/BUILD.bazel | 2 + .../common/navigation/BaseNavigableExpr.java | 131 ++++++++++++++++++ .../common/navigation/CelNavigableExpr.java | 129 +++++------------ .../navigation/CelNavigableExprVisitor.java | 81 +++++------ .../navigation/ExprHeightCalculator.java | 56 ++++---- .../cel/common/navigation/TraversalOrder.java | 37 +++++ .../CelNavigableExprVisitorTest.java | 3 +- .../java/dev/cel/optimizer/AstMutator.java | 2 +- .../optimizers/SubexpressionOptimizer.java | 2 +- 9 files changed, 269 insertions(+), 174 deletions(-) create mode 100644 common/src/main/java/dev/cel/common/navigation/BaseNavigableExpr.java create mode 100644 common/src/main/java/dev/cel/common/navigation/TraversalOrder.java diff --git a/common/src/main/java/dev/cel/common/navigation/BUILD.bazel b/common/src/main/java/dev/cel/common/navigation/BUILD.bazel index 5a3281e75..8d01f82d5 100644 --- a/common/src/main/java/dev/cel/common/navigation/BUILD.bazel +++ b/common/src/main/java/dev/cel/common/navigation/BUILD.bazel @@ -10,10 +10,12 @@ package( java_library( name = "navigation", srcs = [ + "BaseNavigableExpr.java", "CelNavigableAst.java", "CelNavigableExpr.java", "CelNavigableExprVisitor.java", "ExprHeightCalculator.java", + "TraversalOrder.java", ], tags = [ ], diff --git a/common/src/main/java/dev/cel/common/navigation/BaseNavigableExpr.java b/common/src/main/java/dev/cel/common/navigation/BaseNavigableExpr.java new file mode 100644 index 000000000..af6653b7c --- /dev/null +++ b/common/src/main/java/dev/cel/common/navigation/BaseNavigableExpr.java @@ -0,0 +1,131 @@ +// Copyright 2024 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.common.navigation; + +import com.google.errorprone.annotations.CanIgnoreReturnValue; +import com.google.errorprone.annotations.CheckReturnValue; +import dev.cel.common.ast.CelExpr; +import dev.cel.common.ast.CelExpr.ExprKind; +import dev.cel.common.ast.Expression; +import java.util.Optional; +import java.util.stream.Stream; + +/** + * BaseNavigableExpr represents the base navigable expression value with methods to inspect the + * parent and child expressions. + */ +@SuppressWarnings("unchecked") // Generic types are properly bound to Expression +abstract class BaseNavigableExpr { + + public abstract E expr(); + + public long id() { + return expr().id(); + } + + public abstract > Optional parent(); + + /** Represents the count of transitive parents. Depth of an AST's root is 0. */ + public abstract int depth(); + + /** + * Represents the maximum count of children from any of its branches. Height of a leaf node is 0. + * For example, the height of the call node 'func' in expression `(1 + 2 + 3).func(4 + 5)` is 3. + */ + public abstract int height(); + + /** + * Returns a stream of {@link BaseNavigableExpr} collected from the current node down to the last + * leaf-level member using post-order traversal. + */ + public > Stream allNodes() { + return allNodes(TraversalOrder.POST_ORDER); + } + + /** + * Returns a stream of {@link BaseNavigableExpr} collected from the current node down to the last + * leaf-level member using the specified traversal order. + */ + public > Stream allNodes(TraversalOrder traversalOrder) { + return CelNavigableExprVisitor.collect((T) this, traversalOrder); + } + + /** + * Returns a stream of {@link BaseNavigableExpr} collected down to the last leaf-level member + * using post-order traversal. + */ + public > Stream descendants() { + return descendants(TraversalOrder.POST_ORDER); + } + + /** + * Returns a stream of {@link BaseNavigableExpr} collected down to the last leaf-level member + * using the specified traversal order. + */ + public > Stream descendants(TraversalOrder traversalOrder) { + return CelNavigableExprVisitor.collect((T) this, traversalOrder) + .filter(node -> node.depth() > this.depth()); + } + + /** + * Returns a stream of {@link BaseNavigableExpr} collected from its immediate children using + * post-order traversal. + */ + public > Stream children() { + return children(TraversalOrder.POST_ORDER); + } + + /** + * Returns a stream of {@link BaseNavigableExpr} collected from its immediate children using the + * specified traversal order. + */ + public > Stream children(TraversalOrder traversalOrder) { + return CelNavigableExprVisitor.collect((T) this, this.depth() + 1, traversalOrder) + .filter(node -> node.depth() > this.depth()); + } + + /** Returns the underlying kind of the {@link CelExpr}. */ + public ExprKind.Kind getKind() { + return expr().getKind(); + } + + public abstract > Builder builderFromInstance(); + + interface Builder> { + + E expr(); + + int depth(); + + default ExprKind.Kind getKind() { + return expr().getKind(); + } + + @CanIgnoreReturnValue + Builder setExpr(E value); + + @CanIgnoreReturnValue + Builder setParent(T value); + + @CanIgnoreReturnValue + Builder setDepth(int value); + + @CanIgnoreReturnValue + Builder setHeight(int value); + + @CheckReturnValue + T build(); + } +} diff --git a/common/src/main/java/dev/cel/common/navigation/CelNavigableExpr.java b/common/src/main/java/dev/cel/common/navigation/CelNavigableExpr.java index d0cd2ba74..e994c15a0 100644 --- a/common/src/main/java/dev/cel/common/navigation/CelNavigableExpr.java +++ b/common/src/main/java/dev/cel/common/navigation/CelNavigableExpr.java @@ -16,118 +16,60 @@ import com.google.auto.value.AutoValue; import dev.cel.common.ast.CelExpr; -import dev.cel.common.ast.CelExpr.CelComprehension; -import dev.cel.common.ast.CelExpr.ExprKind; import java.util.Optional; import java.util.stream.Stream; /** - * CelNavigableExpr represents the base navigable expression value with methods to inspect the - * parent and child expressions. + * CelNavigableExpr decorates {@link CelExpr} with capabilities to inspect the parent and its + * descendants with ease. */ @AutoValue -public abstract class CelNavigableExpr { - - /** - * Specifies the traversal order of AST navigation. - * - *

For call expressions, the target is visited before its arguments. - * - *

For comprehensions, the visiting order is as follows: - * - *

    - *
  1. {@link CelComprehension#iterRange} - *
  2. {@link CelComprehension#accuInit} - *
  3. {@link CelComprehension#loopCondition} - *
  4. {@link CelComprehension#loopStep} - *
  5. {@link CelComprehension#result} - *
- */ - public enum TraversalOrder { - PRE_ORDER, - POST_ORDER - } - - public abstract CelExpr expr(); - - public long id() { - return expr().id(); - } - - public abstract Optional parent(); - - /** Represents the count of transitive parents. Depth of an AST's root is 0. */ - public abstract int depth(); - - /** - * Represents the maximum count of children from any of its branches. Height of a leaf node is 0. - * For example, the height of the call node 'func' in expression `(1 + 2 + 3).func(4 + 5)` is 3. - */ - public abstract int height(); - +// unchecked: Generic types are properly bound to BaseNavigableExpr +// redundant override: Overriding is required to specify the return type to a concrete type. +@SuppressWarnings({"unchecked", "RedundantOverride"}) +public abstract class CelNavigableExpr extends BaseNavigableExpr { /** Constructs a new instance of {@link CelNavigableExpr} from {@link CelExpr}. */ public static CelNavigableExpr fromExpr(CelExpr expr) { - ExprHeightCalculator exprHeightCalculator = new ExprHeightCalculator(expr); - - return CelNavigableExpr.builder() - .setExpr(expr) - .setHeight(exprHeightCalculator.getHeight(expr.id())) - .build(); + ExprHeightCalculator exprHeightCalculator = new ExprHeightCalculator<>(expr); + return builder().setExpr(expr).setHeight(exprHeightCalculator.getHeight(expr.id())).build(); } - /** - * Returns a stream of {@link CelNavigableExpr} collected from the current node down to the last - * leaf-level member using post-order traversal. - */ + @Override public Stream allNodes() { - return allNodes(TraversalOrder.POST_ORDER); + return super.allNodes(); } - /** - * Returns a stream of {@link CelNavigableExpr} collected from the current node down to the last - * leaf-level member using the specified traversal order. - */ + @Override public Stream allNodes(TraversalOrder traversalOrder) { - return CelNavigableExprVisitor.collect(this, traversalOrder); + return super.allNodes(traversalOrder); } - /** - * Returns a stream of {@link CelNavigableExpr} collected down to the last leaf-level member using - * post-order traversal. - */ + @Override + public abstract Optional parent(); + + @Override public Stream descendants() { - return descendants(TraversalOrder.POST_ORDER); + return super.descendants(); } - /** - * Returns a stream of {@link CelNavigableExpr} collected down to the last leaf-level member using - * the specified traversal order. - */ + @Override public Stream descendants(TraversalOrder traversalOrder) { - return CelNavigableExprVisitor.collect(this, traversalOrder) - .filter(node -> node.depth() > this.depth()); + return super.descendants(traversalOrder); } - /** - * Returns a stream of {@link CelNavigableExpr} collected from its immediate children using - * post-order traversal. - */ + @Override public Stream children() { - return children(TraversalOrder.POST_ORDER); + return super.children(); } - /** - * Returns a stream of {@link CelNavigableExpr} collected from its immediate children using the - * specified traversal order. - */ + @Override public Stream children(TraversalOrder traversalOrder) { - return CelNavigableExprVisitor.collect(this, this.depth() + 1, traversalOrder) - .filter(node -> node.depth() > this.depth()); + return super.children(traversalOrder); } - /** Returns the underlying kind of the {@link CelExpr}. */ - public ExprKind.Kind getKind() { - return expr().exprKind().getKind(); + @Override + public Builder builderFromInstance() { + return builder(); } /** Create a new builder to construct a {@link CelNavigableExpr} instance. */ @@ -137,25 +79,20 @@ public static Builder builder() { /** Builder to configure {@link CelNavigableExpr}. */ @AutoValue.Builder - public abstract static class Builder { + public abstract static class Builder + implements BaseNavigableExpr.Builder { - public abstract CelExpr expr(); - - public abstract int depth(); - - public ExprKind.Kind getKind() { - return expr().exprKind().getKind(); - } + @Override + public abstract Builder setParent(CelNavigableExpr value); + @Override public abstract Builder setExpr(CelExpr value); - abstract Builder setParent(CelNavigableExpr value); - + @Override public abstract Builder setDepth(int value); + @Override public abstract Builder setHeight(int value); - - public abstract CelNavigableExpr build(); } public abstract Builder toBuilder(); diff --git a/common/src/main/java/dev/cel/common/navigation/CelNavigableExprVisitor.java b/common/src/main/java/dev/cel/common/navigation/CelNavigableExprVisitor.java index afafd89c2..eecf789d5 100644 --- a/common/src/main/java/dev/cel/common/navigation/CelNavigableExprVisitor.java +++ b/common/src/main/java/dev/cel/common/navigation/CelNavigableExprVisitor.java @@ -14,30 +14,23 @@ package dev.cel.common.navigation; -import com.google.common.collect.ImmutableList; -import dev.cel.common.ast.CelExpr; -import dev.cel.common.ast.CelExpr.CelCall; -import dev.cel.common.ast.CelExpr.CelComprehension; -import dev.cel.common.ast.CelExpr.CelCreateList; -import dev.cel.common.ast.CelExpr.CelCreateMap; -import dev.cel.common.ast.CelExpr.CelCreateStruct; -import dev.cel.common.ast.CelExpr.CelSelect; -import dev.cel.common.navigation.CelNavigableExpr.TraversalOrder; +import dev.cel.common.ast.Expression; +import java.util.List; import java.util.stream.Stream; /** Visitor implementation to navigate an AST. */ -final class CelNavigableExprVisitor { +final class CelNavigableExprVisitor> { private static final int MAX_DESCENDANTS_RECURSION_DEPTH = 500; - private final Stream.Builder streamBuilder; - private final ExprHeightCalculator exprHeightCalculator; + private final Stream.Builder streamBuilder; + private final ExprHeightCalculator exprPropertyCalculator; private final TraversalOrder traversalOrder; private final int maxDepth; private CelNavigableExprVisitor( - int maxDepth, ExprHeightCalculator exprHeightCalculator, TraversalOrder traversalOrder) { + int maxDepth, ExprHeightCalculator exprPropertyCalculator, TraversalOrder traversalOrder) { this.maxDepth = maxDepth; - this.exprHeightCalculator = exprHeightCalculator; + this.exprPropertyCalculator = exprPropertyCalculator; this.traversalOrder = traversalOrder; this.streamBuilder = Stream.builder(); } @@ -60,8 +53,8 @@ private CelNavigableExprVisitor( * maxDepth of 2: a, b, d, e, c * */ - static Stream collect( - CelNavigableExpr navigableExpr, TraversalOrder traversalOrder) { + static > Stream collect( + T navigableExpr, TraversalOrder traversalOrder) { return collect(navigableExpr, MAX_DESCENDANTS_RECURSION_DEPTH, traversalOrder); } @@ -83,18 +76,18 @@ static Stream collect( * maxDepth of 2: a, b, d, e, c * */ - static Stream collect( - CelNavigableExpr navigableExpr, int maxDepth, TraversalOrder traversalOrder) { - ExprHeightCalculator exprHeightCalculator = new ExprHeightCalculator(navigableExpr.expr()); - CelNavigableExprVisitor visitor = - new CelNavigableExprVisitor(maxDepth, exprHeightCalculator, traversalOrder); + static > Stream collect( + T navigableExpr, int maxDepth, TraversalOrder traversalOrder) { + ExprHeightCalculator exprHeightCalculator = new ExprHeightCalculator<>(navigableExpr.expr()); + CelNavigableExprVisitor visitor = + new CelNavigableExprVisitor<>(maxDepth, exprHeightCalculator, traversalOrder); visitor.visit(navigableExpr); return visitor.streamBuilder.build(); } - private void visit(CelNavigableExpr navigableExpr) { + private void visit(T navigableExpr) { if (navigableExpr.depth() > MAX_DESCENDANTS_RECURSION_DEPTH - 1) { throw new IllegalStateException("Max recursion depth reached."); } @@ -132,7 +125,7 @@ private void visit(CelNavigableExpr navigableExpr) { } } - private void visit(CelNavigableExpr navigableExpr, CelCall call) { + private void visit(T navigableExpr, Expression.Call call) { if (call.target().isPresent()) { visit(newNavigableChild(navigableExpr, call.target().get())); } @@ -140,16 +133,16 @@ private void visit(CelNavigableExpr navigableExpr, CelCall call) { visitExprList(call.args(), navigableExpr); } - private void visit(CelNavigableExpr navigableExpr, CelCreateList createList) { + private void visit(T navigableExpr, Expression.CreateList createList) { visitExprList(createList.elements(), navigableExpr); } - private void visit(CelNavigableExpr navigableExpr, CelSelect selectExpr) { - CelNavigableExpr operand = newNavigableChild(navigableExpr, selectExpr.operand()); + private void visit(T navigableExpr, Expression.Select selectExpr) { + T operand = newNavigableChild(navigableExpr, selectExpr.operand()); visit(operand); } - private void visit(CelNavigableExpr navigableExpr, CelComprehension comprehension) { + private void visit(T navigableExpr, Expression.Comprehension comprehension) { visit(newNavigableChild(navigableExpr, comprehension.iterRange())); visit(newNavigableChild(navigableExpr, comprehension.accuInit())); visit(newNavigableChild(navigableExpr, comprehension.loopCondition())); @@ -157,36 +150,36 @@ private void visit(CelNavigableExpr navigableExpr, CelComprehension comprehensio visit(newNavigableChild(navigableExpr, comprehension.result())); } - private void visitStruct(CelNavigableExpr navigableExpr, CelCreateStruct struct) { - for (CelCreateStruct.Entry entry : struct.entries()) { + private void visitStruct( + T navigableExpr, Expression.CreateStruct> struct) { + for (Expression.CreateStruct.Entry entry : struct.entries()) { visit(newNavigableChild(navigableExpr, entry.value())); } } - private void visitMap(CelNavigableExpr navigableExpr, CelCreateMap map) { - for (CelCreateMap.Entry entry : map.entries()) { - CelNavigableExpr key = newNavigableChild(navigableExpr, entry.key()); + private void visitMap(T navigableExpr, Expression.CreateMap> map) { + for (Expression.CreateMap.Entry entry : map.entries()) { + T key = newNavigableChild(navigableExpr, entry.key()); visit(key); - CelNavigableExpr value = newNavigableChild(navigableExpr, entry.value()); + T value = newNavigableChild(navigableExpr, entry.value()); visit(value); } } - private void visitExprList(ImmutableList createListExpr, CelNavigableExpr parent) { - for (CelExpr expr : createListExpr) { + private void visitExprList(List createListExpr, T parent) { + for (E expr : createListExpr) { visit(newNavigableChild(parent, expr)); } } - private CelNavigableExpr newNavigableChild(CelNavigableExpr parent, CelExpr expr) { - CelNavigableExpr.Builder navigableExpr = - CelNavigableExpr.builder() - .setExpr(expr) - .setDepth(parent.depth() + 1) - .setHeight(exprHeightCalculator.getHeight(expr.id())) - .setParent(parent); - - return navigableExpr.build(); + private T newNavigableChild(T parent, E expr) { + return parent + .builderFromInstance() + .setExpr(expr) + .setDepth(parent.depth() + 1) + .setHeight(exprPropertyCalculator.getHeight(expr.id())) + .setParent(parent) + .build(); } } diff --git a/common/src/main/java/dev/cel/common/navigation/ExprHeightCalculator.java b/common/src/main/java/dev/cel/common/navigation/ExprHeightCalculator.java index f6555a09b..c2cb81101 100644 --- a/common/src/main/java/dev/cel/common/navigation/ExprHeightCalculator.java +++ b/common/src/main/java/dev/cel/common/navigation/ExprHeightCalculator.java @@ -16,25 +16,21 @@ import static java.lang.Math.max; -import com.google.common.collect.ImmutableList; -import dev.cel.common.ast.CelExpr; -import dev.cel.common.ast.CelExpr.CelCall; -import dev.cel.common.ast.CelExpr.CelComprehension; -import dev.cel.common.ast.CelExpr.CelCreateList; -import dev.cel.common.ast.CelExpr.CelCreateMap; -import dev.cel.common.ast.CelExpr.CelCreateStruct; -import dev.cel.common.ast.CelExpr.CelSelect; +import dev.cel.common.ast.Expression; +import dev.cel.common.ast.Expression.CreateMap; +import dev.cel.common.ast.Expression.CreateStruct; import java.util.HashMap; +import java.util.List; /** Package-private class to assist computing the height of expression nodes. */ -final class ExprHeightCalculator { +final class ExprHeightCalculator { // Store hashmap instead of immutable map for performance, such that this helper class can be // instantiated faster. private final HashMap idToHeight; - ExprHeightCalculator(CelExpr celExpr) { + ExprHeightCalculator(E expr) { this.idToHeight = new HashMap<>(); - visit(celExpr); + visit(expr); } int getHeight(Long exprId) { @@ -45,26 +41,26 @@ int getHeight(Long exprId) { return idToHeight.get(exprId); } - private int visit(CelExpr celExpr) { + private int visit(E expr) { int height = 1; - switch (celExpr.exprKind().getKind()) { + switch (expr.getKind()) { case CALL: - height += visit(celExpr.call()); + height += visit(expr.call()); break; case CREATE_LIST: - height += visit(celExpr.createList()); + height += visit(expr.createList()); break; case SELECT: - height += visit(celExpr.select()); + height += visit(expr.select()); break; case CREATE_STRUCT: - height += visitStruct(celExpr.createStruct()); + height += visitStruct(expr.createStruct()); break; case CREATE_MAP: - height += visitMap(celExpr.createMap()); + height += visitMap(expr.createMap()); break; case COMPREHENSION: - height += visit(celExpr.comprehension()); + height += visit(expr.comprehension()); break; default: // This is a leaf node @@ -72,11 +68,11 @@ private int visit(CelExpr celExpr) { break; } - idToHeight.put(celExpr.id(), height); + idToHeight.put(expr.id(), height); return height; } - private int visit(CelCall call) { + private int visit(Expression.Call call) { int targetHeight = 0; if (call.target().isPresent()) { targetHeight = visit(call.target().get()); @@ -86,15 +82,15 @@ private int visit(CelCall call) { return max(targetHeight, argumentHeight); } - private int visit(CelCreateList createList) { + private int visit(Expression.CreateList createList) { return visitExprList(createList.elements()); } - private int visit(CelSelect selectExpr) { + private int visit(Expression.Select selectExpr) { return visit(selectExpr.operand()); } - private int visit(CelComprehension comprehension) { + private int visit(Expression.Comprehension comprehension) { int maxHeight = 0; maxHeight = max(visit(comprehension.iterRange()), maxHeight); maxHeight = max(visit(comprehension.accuInit()), maxHeight); @@ -105,26 +101,26 @@ private int visit(CelComprehension comprehension) { return maxHeight; } - private int visitStruct(CelCreateStruct struct) { + private int visitStruct(Expression.CreateStruct> struct) { int maxHeight = 0; - for (CelCreateStruct.Entry entry : struct.entries()) { + for (CreateStruct.Entry entry : struct.entries()) { maxHeight = max(visit(entry.value()), maxHeight); } return maxHeight; } - private int visitMap(CelCreateMap map) { + private int visitMap(Expression.CreateMap> map) { int maxHeight = 0; - for (CelCreateMap.Entry entry : map.entries()) { + for (CreateMap.Entry entry : map.entries()) { maxHeight = max(visit(entry.key()), maxHeight); maxHeight = max(visit(entry.value()), maxHeight); } return maxHeight; } - private int visitExprList(ImmutableList createListExpr) { + private int visitExprList(List createListExpr) { int maxHeight = 0; - for (CelExpr expr : createListExpr) { + for (E expr : createListExpr) { maxHeight = max(visit(expr), maxHeight); } return maxHeight; diff --git a/common/src/main/java/dev/cel/common/navigation/TraversalOrder.java b/common/src/main/java/dev/cel/common/navigation/TraversalOrder.java new file mode 100644 index 000000000..80aafbf74 --- /dev/null +++ b/common/src/main/java/dev/cel/common/navigation/TraversalOrder.java @@ -0,0 +1,37 @@ +// Copyright 2024 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.common.navigation; + +import dev.cel.common.ast.CelExpr.CelComprehension; + +/** + * Specifies the traversal order of AST navigation. + * + *

For call expressions, the target is visited before its arguments. + * + *

For comprehensions, the visiting order is as follows: + * + *

    + *
  1. {@link CelComprehension#iterRange} + *
  2. {@link CelComprehension#accuInit} + *
  3. {@link CelComprehension#loopCondition} + *
  4. {@link CelComprehension#loopStep} + *
  5. {@link CelComprehension#result} + *
+ */ +public enum TraversalOrder { + PRE_ORDER, + POST_ORDER +} diff --git a/common/src/test/java/dev/cel/common/navigation/CelNavigableExprVisitorTest.java b/common/src/test/java/dev/cel/common/navigation/CelNavigableExprVisitorTest.java index 710267e55..d7c04375e 100644 --- a/common/src/test/java/dev/cel/common/navigation/CelNavigableExprVisitorTest.java +++ b/common/src/test/java/dev/cel/common/navigation/CelNavigableExprVisitorTest.java @@ -31,7 +31,6 @@ import dev.cel.common.ast.CelExpr; import dev.cel.common.ast.CelExpr.CelCall; import dev.cel.common.ast.CelExpr.ExprKind.Kind; -import dev.cel.common.navigation.CelNavigableExpr.TraversalOrder; import dev.cel.common.types.ListType; import dev.cel.common.types.SimpleType; import dev.cel.common.types.StructTypeReference; @@ -336,7 +335,7 @@ public void add_childrenOfMiddleBranch_success() throws Exception { // Assert that the children of add call in the middle branch are const(1) and ident("a") assertThat(children).hasSize(2); assertThat(children.get(0).expr()).isEqualTo(CelExpr.ofConstantExpr(1, CelConstant.ofValue(1))); - assertThat(children.get(1)).isEqualTo(ident); + assertThat(children.get(1).expr()).isEqualTo(ident.expr()); } @Test diff --git a/optimizer/src/main/java/dev/cel/optimizer/AstMutator.java b/optimizer/src/main/java/dev/cel/optimizer/AstMutator.java index 60161350d..94a4f4724 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/AstMutator.java +++ b/optimizer/src/main/java/dev/cel/optimizer/AstMutator.java @@ -40,7 +40,7 @@ import dev.cel.common.ast.CelExprIdGeneratorFactory.StableIdGenerator; import dev.cel.common.navigation.CelNavigableAst; import dev.cel.common.navigation.CelNavigableExpr; -import dev.cel.common.navigation.CelNavigableExpr.TraversalOrder; +import dev.cel.common.navigation.TraversalOrder; import dev.cel.common.types.CelType; import java.util.Collection; import java.util.HashMap; diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java index 57b9c7a6f..76816810f 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java @@ -45,7 +45,7 @@ import dev.cel.common.ast.CelExpr.ExprKind.Kind; import dev.cel.common.navigation.CelNavigableAst; import dev.cel.common.navigation.CelNavigableExpr; -import dev.cel.common.navigation.CelNavigableExpr.TraversalOrder; +import dev.cel.common.navigation.TraversalOrder; import dev.cel.common.types.CelType; import dev.cel.common.types.ListType; import dev.cel.common.types.SimpleType; From 305b375975bd26b5ed3a307770d4435f8440e2a0 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Tue, 16 Apr 2024 11:59:47 -0700 Subject: [PATCH 086/486] Compute Max IDs per subtree in NavigableExpr PiperOrigin-RevId: 625408805 --- .../dev/cel/common/navigation/BUILD.bazel | 2 +- .../common/navigation/BaseNavigableExpr.java | 9 + .../common/navigation/CelNavigableExpr.java | 17 +- .../navigation/CelNavigableExprVisitor.java | 15 +- .../navigation/ExprHeightCalculator.java | 128 --------- .../navigation/ExprPropertyCalculator.java | 156 +++++++++++ .../CelNavigableExprVisitorTest.java | 262 ++++++++++++++++++ 7 files changed, 453 insertions(+), 136 deletions(-) delete mode 100644 common/src/main/java/dev/cel/common/navigation/ExprHeightCalculator.java create mode 100644 common/src/main/java/dev/cel/common/navigation/ExprPropertyCalculator.java diff --git a/common/src/main/java/dev/cel/common/navigation/BUILD.bazel b/common/src/main/java/dev/cel/common/navigation/BUILD.bazel index 8d01f82d5..55ae48f72 100644 --- a/common/src/main/java/dev/cel/common/navigation/BUILD.bazel +++ b/common/src/main/java/dev/cel/common/navigation/BUILD.bazel @@ -14,7 +14,7 @@ java_library( "CelNavigableAst.java", "CelNavigableExpr.java", "CelNavigableExprVisitor.java", - "ExprHeightCalculator.java", + "ExprPropertyCalculator.java", "TraversalOrder.java", ], tags = [ diff --git a/common/src/main/java/dev/cel/common/navigation/BaseNavigableExpr.java b/common/src/main/java/dev/cel/common/navigation/BaseNavigableExpr.java index af6653b7c..1699b4a96 100644 --- a/common/src/main/java/dev/cel/common/navigation/BaseNavigableExpr.java +++ b/common/src/main/java/dev/cel/common/navigation/BaseNavigableExpr.java @@ -40,6 +40,12 @@ public long id() { /** Represents the count of transitive parents. Depth of an AST's root is 0. */ public abstract int depth(); + /** + * Represents the maximum ID of the tree. Note that if the underlying expression tree held by this + * navigable expression is mutated, its max ID becomes stale and must be recomputed. + */ + public abstract long maxId(); + /** * Represents the maximum count of children from any of its branches. Height of a leaf node is 0. * For example, the height of the call node 'func' in expression `(1 + 2 + 3).func(4 + 5)` is 3. @@ -125,6 +131,9 @@ default ExprKind.Kind getKind() { @CanIgnoreReturnValue Builder setHeight(int value); + @CanIgnoreReturnValue + Builder setMaxId(long value); + @CheckReturnValue T build(); } diff --git a/common/src/main/java/dev/cel/common/navigation/CelNavigableExpr.java b/common/src/main/java/dev/cel/common/navigation/CelNavigableExpr.java index e994c15a0..69453b900 100644 --- a/common/src/main/java/dev/cel/common/navigation/CelNavigableExpr.java +++ b/common/src/main/java/dev/cel/common/navigation/CelNavigableExpr.java @@ -16,6 +16,7 @@ import com.google.auto.value.AutoValue; import dev.cel.common.ast.CelExpr; +import dev.cel.common.navigation.ExprPropertyCalculator.ExprProperty; import java.util.Optional; import java.util.stream.Stream; @@ -28,10 +29,17 @@ // redundant override: Overriding is required to specify the return type to a concrete type. @SuppressWarnings({"unchecked", "RedundantOverride"}) public abstract class CelNavigableExpr extends BaseNavigableExpr { + /** Constructs a new instance of {@link CelNavigableExpr} from {@link CelExpr}. */ public static CelNavigableExpr fromExpr(CelExpr expr) { - ExprHeightCalculator exprHeightCalculator = new ExprHeightCalculator<>(expr); - return builder().setExpr(expr).setHeight(exprHeightCalculator.getHeight(expr.id())).build(); + ExprPropertyCalculator exprHeightCalculator = new ExprPropertyCalculator<>(expr); + ExprProperty exprProperty = exprHeightCalculator.getProperty(expr.id()); + + return builder() + .setExpr(expr) + .setHeight(exprProperty.height()) + .setMaxId(exprProperty.maxId()) + .build(); } @Override @@ -74,7 +82,7 @@ public Builder builderFromInstance() { /** Create a new builder to construct a {@link CelNavigableExpr} instance. */ public static Builder builder() { - return new AutoValue_CelNavigableExpr.Builder().setDepth(0).setHeight(0); + return new AutoValue_CelNavigableExpr.Builder().setDepth(0).setHeight(0).setMaxId(0); } /** Builder to configure {@link CelNavigableExpr}. */ @@ -91,6 +99,9 @@ public abstract static class Builder @Override public abstract Builder setDepth(int value); + @Override + public abstract Builder setMaxId(long value); + @Override public abstract Builder setHeight(int value); } diff --git a/common/src/main/java/dev/cel/common/navigation/CelNavigableExprVisitor.java b/common/src/main/java/dev/cel/common/navigation/CelNavigableExprVisitor.java index eecf789d5..73cfecd0b 100644 --- a/common/src/main/java/dev/cel/common/navigation/CelNavigableExprVisitor.java +++ b/common/src/main/java/dev/cel/common/navigation/CelNavigableExprVisitor.java @@ -15,6 +15,7 @@ package dev.cel.common.navigation; import dev.cel.common.ast.Expression; +import dev.cel.common.navigation.ExprPropertyCalculator.ExprProperty; import java.util.List; import java.util.stream.Stream; @@ -23,12 +24,14 @@ final class CelNavigableExprVisitor streamBuilder; - private final ExprHeightCalculator exprPropertyCalculator; + private final ExprPropertyCalculator exprPropertyCalculator; private final TraversalOrder traversalOrder; private final int maxDepth; private CelNavigableExprVisitor( - int maxDepth, ExprHeightCalculator exprPropertyCalculator, TraversalOrder traversalOrder) { + int maxDepth, + ExprPropertyCalculator exprPropertyCalculator, + TraversalOrder traversalOrder) { this.maxDepth = maxDepth; this.exprPropertyCalculator = exprPropertyCalculator; this.traversalOrder = traversalOrder; @@ -78,7 +81,8 @@ static > Stream collect( */ static > Stream collect( T navigableExpr, int maxDepth, TraversalOrder traversalOrder) { - ExprHeightCalculator exprHeightCalculator = new ExprHeightCalculator<>(navigableExpr.expr()); + ExprPropertyCalculator exprHeightCalculator = + new ExprPropertyCalculator<>(navigableExpr.expr()); CelNavigableExprVisitor visitor = new CelNavigableExprVisitor<>(maxDepth, exprHeightCalculator, traversalOrder); @@ -174,11 +178,14 @@ private void visitExprList(List createListExpr, T parent) { } private T newNavigableChild(T parent, E expr) { + ExprProperty exprProperty = exprPropertyCalculator.getProperty(expr.id()); + return parent .builderFromInstance() .setExpr(expr) .setDepth(parent.depth() + 1) - .setHeight(exprPropertyCalculator.getHeight(expr.id())) + .setHeight(exprProperty.height()) + .setMaxId(exprProperty.maxId()) .setParent(parent) .build(); } diff --git a/common/src/main/java/dev/cel/common/navigation/ExprHeightCalculator.java b/common/src/main/java/dev/cel/common/navigation/ExprHeightCalculator.java deleted file mode 100644 index c2cb81101..000000000 --- a/common/src/main/java/dev/cel/common/navigation/ExprHeightCalculator.java +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright 2024 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.common.navigation; - -import static java.lang.Math.max; - -import dev.cel.common.ast.Expression; -import dev.cel.common.ast.Expression.CreateMap; -import dev.cel.common.ast.Expression.CreateStruct; -import java.util.HashMap; -import java.util.List; - -/** Package-private class to assist computing the height of expression nodes. */ -final class ExprHeightCalculator { - // Store hashmap instead of immutable map for performance, such that this helper class can be - // instantiated faster. - private final HashMap idToHeight; - - ExprHeightCalculator(E expr) { - this.idToHeight = new HashMap<>(); - visit(expr); - } - - int getHeight(Long exprId) { - if (!idToHeight.containsKey(exprId)) { - throw new IllegalStateException("Height not found for expression id: " + exprId); - } - - return idToHeight.get(exprId); - } - - private int visit(E expr) { - int height = 1; - switch (expr.getKind()) { - case CALL: - height += visit(expr.call()); - break; - case CREATE_LIST: - height += visit(expr.createList()); - break; - case SELECT: - height += visit(expr.select()); - break; - case CREATE_STRUCT: - height += visitStruct(expr.createStruct()); - break; - case CREATE_MAP: - height += visitMap(expr.createMap()); - break; - case COMPREHENSION: - height += visit(expr.comprehension()); - break; - default: - // This is a leaf node - height = 0; - break; - } - - idToHeight.put(expr.id(), height); - return height; - } - - private int visit(Expression.Call call) { - int targetHeight = 0; - if (call.target().isPresent()) { - targetHeight = visit(call.target().get()); - } - - int argumentHeight = visitExprList(call.args()); - return max(targetHeight, argumentHeight); - } - - private int visit(Expression.CreateList createList) { - return visitExprList(createList.elements()); - } - - private int visit(Expression.Select selectExpr) { - return visit(selectExpr.operand()); - } - - private int visit(Expression.Comprehension comprehension) { - int maxHeight = 0; - maxHeight = max(visit(comprehension.iterRange()), maxHeight); - maxHeight = max(visit(comprehension.accuInit()), maxHeight); - maxHeight = max(visit(comprehension.loopCondition()), maxHeight); - maxHeight = max(visit(comprehension.loopStep()), maxHeight); - maxHeight = max(visit(comprehension.result()), maxHeight); - - return maxHeight; - } - - private int visitStruct(Expression.CreateStruct> struct) { - int maxHeight = 0; - for (CreateStruct.Entry entry : struct.entries()) { - maxHeight = max(visit(entry.value()), maxHeight); - } - return maxHeight; - } - - private int visitMap(Expression.CreateMap> map) { - int maxHeight = 0; - for (CreateMap.Entry entry : map.entries()) { - maxHeight = max(visit(entry.key()), maxHeight); - maxHeight = max(visit(entry.value()), maxHeight); - } - return maxHeight; - } - - private int visitExprList(List createListExpr) { - int maxHeight = 0; - for (E expr : createListExpr) { - maxHeight = max(visit(expr), maxHeight); - } - return maxHeight; - } -} diff --git a/common/src/main/java/dev/cel/common/navigation/ExprPropertyCalculator.java b/common/src/main/java/dev/cel/common/navigation/ExprPropertyCalculator.java new file mode 100644 index 000000000..63097a1e3 --- /dev/null +++ b/common/src/main/java/dev/cel/common/navigation/ExprPropertyCalculator.java @@ -0,0 +1,156 @@ +// Copyright 2024 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.common.navigation; + +import static java.lang.Math.max; + +import com.google.auto.value.AutoValue; +import dev.cel.common.ast.Expression; +import dev.cel.common.ast.Expression.CreateMap; +import dev.cel.common.ast.Expression.CreateStruct; +import java.util.HashMap; +import java.util.List; + +/** Package-private class to assist computing the height and the max ID of expression nodes. */ +final class ExprPropertyCalculator { + // Store hashmap instead of immutable map for performance, such that this helper class can be + // instantiated faster. + private final HashMap idToProperty; + + ExprPropertyCalculator(E celExpr) { + this.idToProperty = new HashMap<>(); + visit(celExpr); + } + + /** + * Retrieves the property containing the expression's maximum ID and the height of the subtree. + * + * @throws IllegalArgumentException If the provided expression ID does not exist. + */ + ExprProperty getProperty(Long exprId) { + if (!idToProperty.containsKey(exprId)) { + throw new IllegalArgumentException("Property not found for expression id: " + exprId); + } + + return idToProperty.get(exprId); + } + + private ExprProperty visit(E expr) { + int baseHeight = 1; + ExprProperty visitedProperty; + switch (expr.getKind()) { + case CALL: + visitedProperty = visit(expr.call()); + break; + case CREATE_LIST: + visitedProperty = visit(expr.createList()); + break; + case SELECT: + visitedProperty = visit(expr.select()); + break; + case CREATE_STRUCT: + visitedProperty = visitStruct(expr.createStruct()); + break; + case CREATE_MAP: + visitedProperty = visitMap(expr.createMap()); + break; + case COMPREHENSION: + visitedProperty = visit(expr.comprehension()); + break; + default: + // This is a leaf node + baseHeight = 0; + visitedProperty = ExprProperty.create(baseHeight, expr.id()); + break; + } + + ExprProperty exprProperty = + ExprProperty.create( + baseHeight + visitedProperty.height(), max(visitedProperty.maxId(), expr.id())); + idToProperty.put(expr.id(), exprProperty); + + return exprProperty; + } + + private ExprProperty visit(Expression.Call call) { + ExprProperty visitedTarget = ExprProperty.create(0, 0); + if (call.target().isPresent()) { + visitedTarget = visit(call.target().get()); + } + + ExprProperty visitedArgument = visitExprList(call.args()); + return ExprProperty.merge(visitedArgument, visitedTarget); + } + + private ExprProperty visit(Expression.CreateList createList) { + return visitExprList(createList.elements()); + } + + private ExprProperty visit(Expression.Select selectExpr) { + return visit(selectExpr.operand()); + } + + private ExprProperty visit(Expression.Comprehension comprehension) { + ExprProperty visitedProperty = visit(comprehension.iterRange()); + visitedProperty = ExprProperty.merge(visitedProperty, visit(comprehension.accuInit())); + visitedProperty = ExprProperty.merge(visitedProperty, visit(comprehension.loopCondition())); + visitedProperty = ExprProperty.merge(visitedProperty, visit(comprehension.loopStep())); + visitedProperty = ExprProperty.merge(visitedProperty, visit(comprehension.result())); + + return visitedProperty; + } + + private ExprProperty visitStruct(Expression.CreateStruct> struct) { + ExprProperty visitedProperty = ExprProperty.create(0, 0); + for (CreateStruct.Entry entry : struct.entries()) { + visitedProperty = ExprProperty.merge(visitedProperty, visit(entry.value())); + } + return visitedProperty; + } + + private ExprProperty visitMap(Expression.CreateMap> map) { + ExprProperty visitedProperty = ExprProperty.create(0, 0); + for (CreateMap.Entry entry : map.entries()) { + visitedProperty = ExprProperty.merge(visitedProperty, visit(entry.key())); + visitedProperty = ExprProperty.merge(visitedProperty, visit(entry.value())); + } + return visitedProperty; + } + + private ExprProperty visitExprList(List createListExpr) { + ExprProperty visitedProperty = ExprProperty.create(0, 0); + for (E expr : createListExpr) { + visitedProperty = ExprProperty.merge(visitedProperty, visit(expr)); + } + return visitedProperty; + } + + /** Value class to store the height and the max ID at a specific expression ID. */ + @AutoValue + abstract static class ExprProperty { + abstract Integer height(); + + abstract Long maxId(); + + /** Merges the two {@link ExprProperty}, taking their maximum values from the properties. */ + private static ExprProperty merge(ExprProperty e1, ExprProperty e2) { + return create(max(e1.height(), e2.height()), max(e1.maxId(), e2.maxId())); + } + + private static ExprProperty create(int height, long maxId) { + return new AutoValue_ExprPropertyCalculator_ExprProperty(height, maxId); + } + } +} diff --git a/common/src/test/java/dev/cel/common/navigation/CelNavigableExprVisitorTest.java b/common/src/test/java/dev/cel/common/navigation/CelNavigableExprVisitorTest.java index d7c04375e..4af7a7e83 100644 --- a/common/src/test/java/dev/cel/common/navigation/CelNavigableExprVisitorTest.java +++ b/common/src/test/java/dev/cel/common/navigation/CelNavigableExprVisitorTest.java @@ -127,6 +127,26 @@ public void add_preOrder_heightSet() throws Exception { assertThat(allNodeHeights).containsExactly(2, 1, 0, 0, 0).inOrder(); // +, +, 1, a, 2 } + @Test + public void add_preOrder_maxIdsSet() throws Exception { + CelCompiler compiler = + CelCompilerFactory.standardCelCompilerBuilder().addVar("a", SimpleType.INT).build(); + // Tree shape (brackets are IDs): + // + [4] + // + [2] 2 [5] + // 1 [1] a [3] + CelAbstractSyntaxTree ast = compiler.compile("1 + a + 2").getAst(); + CelNavigableAst navigableAst = CelNavigableAst.fromAst(ast); + + ImmutableList allNodeMaxIds = + navigableAst + .getRoot() + .allNodes(TraversalOrder.PRE_ORDER) + .map(CelNavigableExpr::maxId) + .collect(toImmutableList()); + assertThat(allNodeMaxIds).containsExactly(5L, 3L, 1L, 3L, 5L).inOrder(); // +, +, 1, a, 2 + } + @Test public void add_postOrder_heightSet() throws Exception { CelCompiler compiler = @@ -147,6 +167,26 @@ public void add_postOrder_heightSet() throws Exception { assertThat(allNodeHeights).containsExactly(0, 0, 1, 0, 2).inOrder(); // 1, a, +, 2, + } + @Test + public void add_postOrder_maxIdsSet() throws Exception { + CelCompiler compiler = + CelCompilerFactory.standardCelCompilerBuilder().addVar("a", SimpleType.INT).build(); + // Tree shape (brackets are IDs): + // + [4] + // + [2] 2 [5] + // 1 [1] a [3] + CelAbstractSyntaxTree ast = compiler.compile("1 + a + 2").getAst(); + CelNavigableAst navigableAst = CelNavigableAst.fromAst(ast); + + ImmutableList allNodeMaxIds = + navigableAst + .getRoot() + .allNodes(TraversalOrder.POST_ORDER) + .map(CelNavigableExpr::maxId) + .collect(toImmutableList()); + assertThat(allNodeMaxIds).containsExactly(1L, 3L, 3L, 5L, 5L).inOrder(); // 1, a, +, 2, + + } + @Test public void add_fromLeaf_heightSetForParents() throws Exception { CelCompiler compiler = @@ -176,6 +216,35 @@ public void add_fromLeaf_heightSetForParents() throws Exception { assertThat(heights.build()).containsExactly(3, 2, 1, 0); } + @Test + public void add_fromLeaf_maxIdsSetForParents() throws Exception { + CelCompiler compiler = + CelCompilerFactory.standardCelCompilerBuilder().addVar("a", SimpleType.INT).build(); + // Tree shape: + // + + // + 3 + // + 2 + // a 1 + CelAbstractSyntaxTree ast = compiler.compile("1 + a + 2 + 3").getAst(); + CelNavigableAst navigableAst = CelNavigableAst.fromAst(ast); + + ImmutableList.Builder heights = ImmutableList.builder(); + CelNavigableExpr navigableExpr = + navigableAst + .getRoot() + .allNodes() + .filter(node -> node.expr().identOrDefault().name().equals("a")) + .findAny() + .get(); + heights.add(navigableExpr.maxId()); + while (navigableExpr.parent().isPresent()) { + navigableExpr = navigableExpr.parent().get(); + heights.add(navigableExpr.maxId()); + } + + assertThat(heights.build()).containsExactly(3L, 3L, 5L, 7L).inOrder(); + } + @Test public void add_children_heightSet(@TestParameter TraversalOrder traversalOrder) throws Exception { @@ -198,6 +267,30 @@ public void add_children_heightSet(@TestParameter TraversalOrder traversalOrder) assertThat(allNodeHeights).containsExactly(2, 0).inOrder(); // + (2), 2 (0) regardless of order } + @Test + public void add_children_maxIdsSet(@TestParameter TraversalOrder traversalOrder) + throws Exception { + CelCompiler compiler = + CelCompilerFactory.standardCelCompilerBuilder().addVar("a", SimpleType.INT).build(); + // Tree shape: + // + + // + 3 + // + 2 + // a 1 + CelAbstractSyntaxTree ast = compiler.compile("1 + a + 2 + 3").getAst(); + CelNavigableAst navigableAst = CelNavigableAst.fromAst(ast); + + ImmutableList allNodeHeights = + navigableAst + .getRoot() + .children(traversalOrder) + .map(CelNavigableExpr::maxId) + .collect(toImmutableList()); + assertThat(allNodeHeights) + .containsExactly(5L, 7L) + .inOrder(); // + (5), 3 (7) regardless of order + } + @Test public void add_filterConstants_allNodesReturned() throws Exception { CelCompiler compiler = @@ -581,6 +674,27 @@ public void messageConstruction_postOrder_heightSet() throws Exception { assertThat(allNodes).containsExactly(0, 1).inOrder(); } + @Test + public void messageConstruction_maxIdsSet(@TestParameter TraversalOrder traversalOrder) + throws Exception { + CelCompiler compiler = + CelCompilerFactory.standardCelCompilerBuilder() + .addMessageTypes(TestAllTypes.getDescriptor()) + .setContainer("dev.cel.testing.testdata.proto3") + .build(); + CelAbstractSyntaxTree ast = compiler.compile("TestAllTypes{single_int64: 1}").getAst(); + CelNavigableAst navigableAst = CelNavigableAst.fromAst(ast); + + ImmutableList allNodes = + navigableAst + .getRoot() + .allNodes(traversalOrder) + .map(CelNavigableExpr::maxId) + .collect(toImmutableList()); + + assertThat(allNodes).containsExactly(3L, 3L).inOrder(); + } + @Test public void mapConstruction_allNodesReturned() throws Exception { CelCompiler compiler = CelCompilerFactory.standardCelCompilerBuilder().build(); @@ -659,6 +773,38 @@ public void mapConstruction_postOrder_heightSet() throws Exception { assertThat(allNodes).containsExactly(0, 0, 1).inOrder(); } + @Test + public void mapConstruction_preOrder_maxIdsSet() throws Exception { + CelCompiler compiler = CelCompilerFactory.standardCelCompilerBuilder().build(); + CelAbstractSyntaxTree ast = compiler.compile("{'key': 2}").getAst(); + CelNavigableAst navigableAst = CelNavigableAst.fromAst(ast); + + ImmutableList allNodes = + navigableAst + .getRoot() + .allNodes(TraversalOrder.PRE_ORDER) + .map(CelNavigableExpr::maxId) + .collect(toImmutableList()); + + assertThat(allNodes).containsExactly(4L, 3L, 4L).inOrder(); + } + + @Test + public void mapConstruction_postOrder_maxIdsSet() throws Exception { + CelCompiler compiler = CelCompilerFactory.standardCelCompilerBuilder().build(); + CelAbstractSyntaxTree ast = compiler.compile("{'key': 2}").getAst(); + CelNavigableAst navigableAst = CelNavigableAst.fromAst(ast); + + ImmutableList allNodes = + navigableAst + .getRoot() + .allNodes(TraversalOrder.POST_ORDER) + .map(CelNavigableExpr::maxId) + .collect(toImmutableList()); + + assertThat(allNodes).containsExactly(3L, 4L, 4L).inOrder(); + } + @Test public void emptyMapConstruction_allNodesReturned() throws Exception { CelCompiler compiler = CelCompilerFactory.standardCelCompilerBuilder().build(); @@ -834,6 +980,44 @@ public void comprehension_postOrder_heightSet() throws Exception { assertThat(allNodes).containsExactly(0, 1, 0, 0, 1, 2, 0, 0, 1, 0, 3).inOrder(); } + @Test + public void comprehension_preOrder_maxIdsSet() throws Exception { + CelCompiler compiler = + CelCompilerFactory.standardCelCompilerBuilder() + .setStandardMacros(CelStandardMacro.EXISTS) + .build(); + CelAbstractSyntaxTree ast = compiler.compile("[true].exists(i, i)").getAst(); + CelNavigableAst navigableAst = CelNavigableAst.fromAst(ast); + + ImmutableList allNodes = + navigableAst + .getRoot() + .allNodes(TraversalOrder.PRE_ORDER) + .map(CelNavigableExpr::maxId) + .collect(toImmutableList()); + + assertThat(allNodes).containsExactly(13L, 2L, 2L, 6L, 9L, 8L, 7L, 11L, 10L, 5L, 12L).inOrder(); + } + + @Test + public void comprehension_postOrder_maxIdsSet() throws Exception { + CelCompiler compiler = + CelCompilerFactory.standardCelCompilerBuilder() + .setStandardMacros(CelStandardMacro.EXISTS) + .build(); + CelAbstractSyntaxTree ast = compiler.compile("[true].exists(i, i)").getAst(); + CelNavigableAst navigableAst = CelNavigableAst.fromAst(ast); + + ImmutableList allNodes = + navigableAst + .getRoot() + .allNodes(TraversalOrder.POST_ORDER) + .map(CelNavigableExpr::maxId) + .collect(toImmutableList()); + + assertThat(allNodes).containsExactly(2L, 2L, 6L, 7L, 8L, 9L, 10L, 5L, 11L, 12L, 13L).inOrder(); + } + @Test public void comprehension_allNodes_parentsPopulated() throws Exception { CelCompiler compiler = @@ -1072,6 +1256,66 @@ public void callExpr_postOrder_heightSet() throws Exception { assertThat(allNodes).containsExactly(0, 0, 1, 0, 2, 0, 3, 0, 0, 1, 0, 2, 0, 4).inOrder(); } + @Test + public void callExpr_preOrder_maxIdsSet() throws Exception { + CelCompiler compiler = + CelCompilerFactory.standardCelCompilerBuilder() + .addFunctionDeclarations( + newFunctionDeclaration( + "test", + newMemberOverload( + "test_overload", + SimpleType.STRING, + SimpleType.STRING, + SimpleType.INT, + SimpleType.UINT))) + .build(); + CelAbstractSyntaxTree ast = + compiler.compile("('a' + 'b' + 'c' + 'd').test((1 + 2 + 3), 6u)").getAst(); + CelNavigableAst navigableAst = CelNavigableAst.fromAst(ast); + + ImmutableList allNodes = + navigableAst + .getRoot() + .allNodes(TraversalOrder.PRE_ORDER) + .map(CelNavigableExpr::maxId) + .collect(toImmutableList()); + + assertThat(allNodes) + .containsExactly(14L, 7L, 5L, 3L, 1L, 3L, 5L, 7L, 13L, 11L, 9L, 11L, 13L, 14L) + .inOrder(); + } + + @Test + public void callExpr_postOrder_maxIdsSet() throws Exception { + CelCompiler compiler = + CelCompilerFactory.standardCelCompilerBuilder() + .addFunctionDeclarations( + newFunctionDeclaration( + "test", + newMemberOverload( + "test_overload", + SimpleType.STRING, + SimpleType.STRING, + SimpleType.INT, + SimpleType.UINT))) + .build(); + CelAbstractSyntaxTree ast = + compiler.compile("('a' + 'b' + 'c' + 'd').test((1 + 2 + 3), 6u)").getAst(); + CelNavigableAst navigableAst = CelNavigableAst.fromAst(ast); + + ImmutableList allNodes = + navigableAst + .getRoot() + .allNodes(TraversalOrder.POST_ORDER) + .map(CelNavigableExpr::maxId) + .collect(toImmutableList()); + + assertThat(allNodes) + .containsExactly(1L, 3L, 3L, 5L, 5L, 7L, 7L, 9L, 11L, 11L, 13L, 13L, 14L, 14L) + .inOrder(); + } + @Test public void createList_children_heightSet(@TestParameter TraversalOrder traversalOrder) throws Exception { @@ -1090,6 +1334,24 @@ public void createList_children_heightSet(@TestParameter TraversalOrder traversa assertThat(allNodeHeights).containsExactly(0, 0, 1, 2).inOrder(); } + @Test + public void createList_children_maxIdsSet(@TestParameter TraversalOrder traversalOrder) + throws Exception { + CelCompiler compiler = + CelCompilerFactory.standardCelCompilerBuilder().addVar("a", SimpleType.INT).build(); + CelAbstractSyntaxTree ast = compiler.compile("[1, a, (2 + 2), (3 + 4 + 5)]").getAst(); + + CelNavigableAst navigableAst = CelNavigableAst.fromAst(ast); + + ImmutableList allNodeHeights = + navigableAst + .getRoot() + .children(traversalOrder) + .map(CelNavigableExpr::maxId) + .collect(toImmutableList()); + assertThat(allNodeHeights).containsExactly(2L, 3L, 6L, 11L).inOrder(); + } + @Test public void maxRecursionLimitReached_throws() throws Exception { StringBuilder sb = new StringBuilder(); From db796fead7f594fe3565dd0d9efec6e38a4b1847 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Tue, 16 Apr 2024 13:25:55 -0700 Subject: [PATCH 087/486] Add CelMutableAst PiperOrigin-RevId: 625433867 --- .../main/java/dev/cel/common/ast/BUILD.bazel | 3 + .../dev/cel/common/ast/CelMutableAst.java | 109 ++++++++++++++++++ .../test/java/dev/cel/common/ast/BUILD.bazel | 1 + .../dev/cel/common/ast/CelMutableAstTest.java | 91 +++++++++++++++ 4 files changed, 204 insertions(+) create mode 100644 common/src/main/java/dev/cel/common/ast/CelMutableAst.java create mode 100644 common/src/test/java/dev/cel/common/ast/CelMutableAstTest.java diff --git a/common/src/main/java/dev/cel/common/ast/BUILD.bazel b/common/src/main/java/dev/cel/common/ast/BUILD.bazel index ac4df5487..9ed6c80fc 100644 --- a/common/src/main/java/dev/cel/common/ast/BUILD.bazel +++ b/common/src/main/java/dev/cel/common/ast/BUILD.bazel @@ -34,6 +34,7 @@ EXPR_FACTORY_SOURCES = [ # keep sorted MUTABLE_AST_SOURCES = [ + "CelMutableAst.java", "CelMutableExpr.java", "CelMutableExprConverter.java", ] @@ -124,6 +125,8 @@ java_library( ], deps = [ ":ast", + "//common", + "//common/types:type_providers", "@maven//:com_google_guava_guava", ], ) diff --git a/common/src/main/java/dev/cel/common/ast/CelMutableAst.java b/common/src/main/java/dev/cel/common/ast/CelMutableAst.java new file mode 100644 index 000000000..f529e2e8d --- /dev/null +++ b/common/src/main/java/dev/cel/common/ast/CelMutableAst.java @@ -0,0 +1,109 @@ +// Copyright 2024 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.common.ast; + +import dev.cel.common.CelAbstractSyntaxTree; +import dev.cel.common.CelSource; +import dev.cel.common.types.CelType; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +/** + * An abstract representation of CEL Abstract Syntax tree that allows mutation in any of its + * properties. This class is semantically the same as that of the immutable {@link + * CelAbstractSyntaxTree}. + * + *

This should only be used within optimizers to augment an AST. + */ +public final class CelMutableAst { + private final CelMutableExpr mutatedExpr; + private final CelSource.Builder source; + private final Map references; + private final Map types; + + /** Returns the underlying {@link CelMutableExpr} representation of the abstract syntax tree. */ + public CelMutableExpr expr() { + return mutatedExpr; + } + + /** + * Returns the {@link CelSource} that was used during construction of the abstract syntax tree. + */ + public CelSource.Builder source() { + return source; + } + + /** + * Returns the resolved reference to a declaration at expression ID for a type-checked AST. + * + * @return Optional of {@link CelReference} or {@link Optional#empty} if the reference does not + * exist at the ID. + */ + public Optional getReference(long exprId) { + return Optional.ofNullable(references.get(exprId)); + } + + /** + * Returns the type of the expression node for a type-checked AST. + * + * @return Optional of {@link CelType} or {@link Optional#empty} if the type does not exist at the + * ID. + */ + public Optional getType(long exprId) { + return Optional.ofNullable(types.get(exprId)); + } + + /** Converts this mutable AST into a parsed {@link CelAbstractSyntaxTree}. */ + public CelAbstractSyntaxTree toParsedAst() { + return CelAbstractSyntaxTree.newParsedAst( + CelMutableExprConverter.fromMutableExpr(mutatedExpr), source.build()); + } + + /** + * Constructs an instance of {@link CelMutableAst} with the incoming {@link + * CelAbstractSyntaxTree}. + */ + public static CelMutableAst fromCelAst(CelAbstractSyntaxTree ast) { + return new CelMutableAst( + CelMutableExprConverter.fromCelExpr(ast.getExpr()), + ast.getSource().toBuilder(), + ast.getReferenceMap(), + ast.getTypeMap()); + } + + /** + * Constructs an instance of {@link CelMutableAst} with the mutable expression and its source + * builder. + */ + public static CelMutableAst of(CelMutableExpr mutableExpr, CelSource.Builder sourceBuilder) { + return new CelMutableAst(mutableExpr, sourceBuilder); + } + + private CelMutableAst(CelMutableExpr mutatedExpr, CelSource.Builder source) { + this(mutatedExpr, source, new HashMap<>(), new HashMap<>()); + } + + private CelMutableAst( + CelMutableExpr mutatedExpr, + CelSource.Builder source, + Map references, + Map types) { + this.mutatedExpr = mutatedExpr; + this.source = source; + this.references = new HashMap<>(references); + this.types = new HashMap<>(types); + } +} diff --git a/common/src/test/java/dev/cel/common/ast/BUILD.bazel b/common/src/test/java/dev/cel/common/ast/BUILD.bazel index 4c74f4964..103f4804a 100644 --- a/common/src/test/java/dev/cel/common/ast/BUILD.bazel +++ b/common/src/test/java/dev/cel/common/ast/BUILD.bazel @@ -13,6 +13,7 @@ java_library( "//:java_truth", "//common", "//common:compiler_common", + "//common:options", "//common/ast", "//common/ast:cel_expr_visitor", "//common/ast:expr_converter", diff --git a/common/src/test/java/dev/cel/common/ast/CelMutableAstTest.java b/common/src/test/java/dev/cel/common/ast/CelMutableAstTest.java new file mode 100644 index 000000000..1b249484d --- /dev/null +++ b/common/src/test/java/dev/cel/common/ast/CelMutableAstTest.java @@ -0,0 +1,91 @@ +// Copyright 2024 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.common.ast; + +import static com.google.common.truth.Truth.assertThat; + +import dev.cel.common.CelAbstractSyntaxTree; +import dev.cel.common.CelOptions; +import dev.cel.common.CelSource; +import dev.cel.common.types.SimpleType; +import dev.cel.compiler.CelCompiler; +import dev.cel.compiler.CelCompilerFactory; +import dev.cel.parser.CelStandardMacro; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public final class CelMutableAstTest { + + @Test + public void constructMutableAst() { + CelMutableExpr mutableExpr = CelMutableExpr.ofConstant(1L, CelConstant.ofValue("hello world")); + CelSource.Builder sourceBuilder = CelSource.newBuilder(); + + CelMutableAst celMutableAst = CelMutableAst.of(mutableExpr, sourceBuilder); + + assertThat(celMutableAst.expr()).isEqualTo(mutableExpr); + assertThat(celMutableAst.source()).isSameInstanceAs(sourceBuilder); + } + + @Test + public void fromCelAst_mutableAst_containsMutableExpr() throws Exception { + CelCompiler celCompiler = CelCompilerFactory.standardCelCompilerBuilder().build(); + CelAbstractSyntaxTree ast = celCompiler.compile("'hello world'").getAst(); + + CelMutableAst celMutableAst = CelMutableAst.fromCelAst(ast); + + assertThat(celMutableAst.expr()) + .isEqualTo(CelMutableExpr.ofConstant(1L, CelConstant.ofValue("hello world"))); + } + + @Test + public void getType_success() throws Exception { + CelCompiler celCompiler = CelCompilerFactory.standardCelCompilerBuilder().build(); + CelAbstractSyntaxTree ast = celCompiler.compile("'hello world'").getAst(); + CelMutableAst celMutableAst = CelMutableAst.fromCelAst(ast); + + assertThat(celMutableAst.getType(1L)).hasValue(SimpleType.STRING); + } + + @Test + public void getReference_success() throws Exception { + CelCompiler celCompiler = CelCompilerFactory.standardCelCompilerBuilder().build(); + CelAbstractSyntaxTree ast = celCompiler.compile("size('test')").getAst(); + CelMutableAst celMutableAst = CelMutableAst.fromCelAst(ast); + + assertThat(celMutableAst.getReference(1L)) + .hasValue(CelReference.newBuilder().addOverloadIds("size_string").build()); + } + + @Test + public void parsedAst_roundTrip() throws Exception { + CelCompiler celCompiler = + CelCompilerFactory.standardCelCompilerBuilder() + .setOptions(CelOptions.current().populateMacroCalls(true).build()) + .setStandardMacros(CelStandardMacro.STANDARD_MACROS) + .build(); + CelAbstractSyntaxTree ast = celCompiler.parse("[1].exists(x, x > 0)").getAst(); + CelMutableAst celMutableAst = CelMutableAst.fromCelAst(ast); + + CelAbstractSyntaxTree roundTrippedAst = celMutableAst.toParsedAst(); + + assertThat(ast.getExpr()).isEqualTo(roundTrippedAst.getExpr()); + assertThat(roundTrippedAst.getSource().getMacroCalls()).hasSize(1); + assertThat(roundTrippedAst.getSource().getMacroCalls()) + .containsExactlyEntriesIn(ast.getSource().getMacroCalls()); + } +} From 473e43942df8d3d3a57b47fd599325cde0fc31f3 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Tue, 16 Apr 2024 16:14:39 -0700 Subject: [PATCH 088/486] Change MutableExprVisitor to visit using CelMutableExpr PiperOrigin-RevId: 625485309 --- .../main/java/dev/cel/optimizer/BUILD.bazel | 1 + .../dev/cel/optimizer/MutableExprVisitor.java | 142 ++++++++++-------- 2 files changed, 82 insertions(+), 61 deletions(-) diff --git a/optimizer/src/main/java/dev/cel/optimizer/BUILD.bazel b/optimizer/src/main/java/dev/cel/optimizer/BUILD.bazel index 7e2022ab1..07de0dd06 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/BUILD.bazel +++ b/optimizer/src/main/java/dev/cel/optimizer/BUILD.bazel @@ -90,6 +90,7 @@ java_library( "//common/annotations", "//common/ast", "//common/ast:expr_factory", + "//common/ast:mutable_ast", "//common/navigation", "//common/types:type_providers", "@maven//:com_google_errorprone_error_prone_annotations", diff --git a/optimizer/src/main/java/dev/cel/optimizer/MutableExprVisitor.java b/optimizer/src/main/java/dev/cel/optimizer/MutableExprVisitor.java index 36cb86069..ea751313a 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/MutableExprVisitor.java +++ b/optimizer/src/main/java/dev/cel/optimizer/MutableExprVisitor.java @@ -15,146 +15,166 @@ package dev.cel.optimizer; import com.google.common.base.Preconditions; -import com.google.common.collect.ImmutableList; +import com.google.errorprone.annotations.CanIgnoreReturnValue; import dev.cel.common.annotations.Internal; import dev.cel.common.ast.CelExpr; -import dev.cel.common.ast.CelExpr.CelCall; -import dev.cel.common.ast.CelExpr.CelComprehension; -import dev.cel.common.ast.CelExpr.CelCreateList; -import dev.cel.common.ast.CelExpr.CelCreateMap; -import dev.cel.common.ast.CelExpr.CelCreateStruct; -import dev.cel.common.ast.CelExpr.CelSelect; import dev.cel.common.ast.CelExprIdGeneratorFactory.ExprIdGenerator; +import dev.cel.common.ast.CelMutableExpr; +import dev.cel.common.ast.CelMutableExpr.CelMutableCall; +import dev.cel.common.ast.CelMutableExpr.CelMutableComprehension; +import dev.cel.common.ast.CelMutableExpr.CelMutableCreateList; +import dev.cel.common.ast.CelMutableExpr.CelMutableCreateMap; +import dev.cel.common.ast.CelMutableExpr.CelMutableCreateStruct; +import dev.cel.common.ast.CelMutableExpr.CelMutableSelect; +import dev.cel.common.ast.CelMutableExprConverter; +import java.util.List; /** - * MutableExprVisitor performs mutation of {@link CelExpr} based on its configured parameters. + * MutableExprVisitor performs mutation of {@link CelMutableExpr} based on its configured + * parameters. * *

This class is NOT thread-safe. Callers should spawn a new instance of this class each time the * expression is being mutated. - * - *

Note that CelExpr is immutable by design. Therefore, the logic here doesn't actually mutate - * the existing expression tree. Instead, a brand new CelExpr is produced with the subtree swapped - * at the desired expression ID to replace. */ @Internal final class MutableExprVisitor { - private final CelExpr.Builder newExpr; + private final CelMutableExpr newExpr; private final ExprIdGenerator celExprIdGenerator; private final long iterationLimit; private int iterationCount; private long exprIdToReplace; + /** TODO: Temporarily kept to retain method signature. Remove in the upcoming CLs. */ static MutableExprVisitor newInstance( ExprIdGenerator idGenerator, CelExpr.Builder newExpr, long exprIdToReplace, long iterationLimit) { + return newInstance( + idGenerator, + CelMutableExprConverter.fromCelExpr(newExpr.build()), + exprIdToReplace, + iterationLimit); + } + + static MutableExprVisitor newInstance( + ExprIdGenerator idGenerator, + CelMutableExpr newExpr, + long exprIdToReplace, + long iterationLimit) { // iterationLimit * 2, because the expr can be walked twice due to the immutable nature of // CelExpr. return new MutableExprVisitor(idGenerator, newExpr, exprIdToReplace, iterationLimit * 2); } + /** TODO: Temporarily kept to retain method signature. Remove in the upcoming CLs. */ CelExpr.Builder visit(CelExpr.Builder root) { + CelMutableExpr mutatedRoot = visit(CelMutableExprConverter.fromCelExpr(root.build())); + return CelMutableExprConverter.fromMutableExpr(mutatedRoot).toBuilder(); + } + + CelMutableExpr visit(CelMutableExpr root) { if (++iterationCount > iterationLimit) { throw new IllegalStateException("Max iteration count reached."); } if (root.id() == exprIdToReplace) { exprIdToReplace = Integer.MIN_VALUE; // Marks that the subtree has been replaced. - return visit(this.newExpr.setId(root.id())); + this.newExpr.setId(root.id()); + return visit(this.newExpr); } root.setId(celExprIdGenerator.generate(root.id())); - switch (root.exprKind().getKind()) { + switch (root.getKind()) { case SELECT: - return visit(root, root.select().toBuilder()); + return visit(root, root.select()); case CALL: - return visit(root, root.call().toBuilder()); + return visit(root, root.call()); case CREATE_LIST: - return visit(root, root.createList().toBuilder()); + return visit(root, root.createList()); case CREATE_STRUCT: - return visit(root, root.createStruct().toBuilder()); + return visit(root, root.createStruct()); case CREATE_MAP: - return visit(root, root.createMap().toBuilder()); + return visit(root, root.createMap()); case COMPREHENSION: - return visit(root, root.comprehension().toBuilder()); + return visit(root, root.comprehension()); case CONSTANT: // Fall-through is intended case IDENT: case NOT_SET: // Note: comprehension arguments can contain a not set root. return root; } - throw new IllegalArgumentException("unexpected root kind: " + root.exprKind().getKind()); + throw new IllegalArgumentException("unexpected root kind: " + root.getKind()); } - private CelExpr.Builder visit(CelExpr.Builder expr, CelSelect.Builder select) { - select.setOperand(visit(select.operand().toBuilder()).build()); - return expr.setSelect(select.build()); + @CanIgnoreReturnValue + private CelMutableExpr visit(CelMutableExpr expr, CelMutableSelect select) { + select.setOperand(visit(select.operand())); + return expr; } - private CelExpr.Builder visit(CelExpr.Builder expr, CelCall.Builder call) { + @CanIgnoreReturnValue + private CelMutableExpr visit(CelMutableExpr expr, CelMutableCall call) { if (call.target().isPresent()) { - call.setTarget(visit(call.target().get().toBuilder()).build()); + call.setTarget(visit(call.target().get())); } - ImmutableList argsBuilders = call.getArgsBuilders(); + List argsBuilders = call.args(); for (int i = 0; i < argsBuilders.size(); i++) { - CelExpr.Builder arg = argsBuilders.get(i); - call.setArg(i, visit(arg).build()); + CelMutableExpr arg = argsBuilders.get(i); + call.setArg(i, visit(arg)); } - return expr.setCall(call.build()); + return expr; } - private CelExpr.Builder visit(CelExpr.Builder expr, CelCreateStruct.Builder createStruct) { - ImmutableList entries = createStruct.getEntriesBuilders(); - for (int i = 0; i < entries.size(); i++) { - CelCreateStruct.Entry.Builder entry = entries.get(i); + @CanIgnoreReturnValue + private CelMutableExpr visit(CelMutableExpr expr, CelMutableCreateStruct createStruct) { + List entries = createStruct.entries(); + for (CelMutableCreateStruct.Entry entry : entries) { entry.setId(celExprIdGenerator.generate(entry.id())); - entry.setValue(visit(entry.value().toBuilder()).build()); - - createStruct.setEntry(i, entry.build()); + entry.setValue(visit(entry.value())); } - return expr.setCreateStruct(createStruct.build()); + return expr; } - private CelExpr.Builder visit(CelExpr.Builder expr, CelCreateMap.Builder createMap) { - ImmutableList entriesBuilders = createMap.getEntriesBuilders(); - for (int i = 0; i < entriesBuilders.size(); i++) { - CelCreateMap.Entry.Builder entry = entriesBuilders.get(i); + @CanIgnoreReturnValue + private CelMutableExpr visit(CelMutableExpr expr, CelMutableCreateMap createMap) { + List entriesBuilders = createMap.entries(); + for (CelMutableCreateMap.Entry entry : entriesBuilders) { entry.setId(celExprIdGenerator.generate(entry.id())); - entry.setKey(visit(entry.key().toBuilder()).build()); - entry.setValue(visit(entry.value().toBuilder()).build()); - - createMap.setEntry(i, entry.build()); + entry.setKey(visit(entry.key())); + entry.setValue(visit(entry.value())); } - return expr.setCreateMap(createMap.build()); + return expr; } - private CelExpr.Builder visit(CelExpr.Builder expr, CelCreateList.Builder createList) { - ImmutableList elementsBuilders = createList.getElementsBuilders(); + @CanIgnoreReturnValue + private CelMutableExpr visit(CelMutableExpr expr, CelMutableCreateList createList) { + List elementsBuilders = createList.elements(); for (int i = 0; i < elementsBuilders.size(); i++) { - CelExpr.Builder elem = elementsBuilders.get(i); - createList.setElement(i, visit(elem).build()); + CelMutableExpr elem = elementsBuilders.get(i); + createList.setElement(i, visit(elem)); } - return expr.setCreateList(createList.build()); + return expr; } - private CelExpr.Builder visit(CelExpr.Builder expr, CelComprehension.Builder comprehension) { - comprehension.setIterRange(visit(comprehension.iterRange().toBuilder()).build()); - comprehension.setAccuInit(visit(comprehension.accuInit().toBuilder()).build()); - comprehension.setLoopCondition(visit(comprehension.loopCondition().toBuilder()).build()); - comprehension.setLoopStep(visit(comprehension.loopStep().toBuilder()).build()); - comprehension.setResult(visit(comprehension.result().toBuilder()).build()); + @CanIgnoreReturnValue + private CelMutableExpr visit(CelMutableExpr expr, CelMutableComprehension comprehension) { + comprehension.setIterRange(visit(comprehension.iterRange())); + comprehension.setAccuInit(visit(comprehension.accuInit())); + comprehension.setLoopCondition(visit(comprehension.loopCondition())); + comprehension.setLoopStep(visit(comprehension.loopStep())); + comprehension.setResult(visit(comprehension.result())); - return expr.setComprehension(comprehension.build()); + return expr; } private MutableExprVisitor( ExprIdGenerator celExprIdGenerator, - CelExpr.Builder newExpr, + CelMutableExpr newExpr, long exprId, long iterationLimit) { Preconditions.checkState(iterationLimit > 0L); From 141dda85a90253a89447ac876a11f7e6c452265f Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Tue, 16 Apr 2024 16:26:36 -0700 Subject: [PATCH 089/486] Add Mutable versions of NavigableExpr and AST PiperOrigin-RevId: 625488362 --- common/navigation/BUILD.bazel | 10 ++ .../dev/cel/common/navigation/BUILD.bazel | 41 ++++- .../navigation/CelNavigableMutableAst.java | 47 ++++++ .../navigation/CelNavigableMutableExpr.java | 109 +++++++++++++ .../dev/cel/common/navigation/BUILD.bazel | 3 + .../CelNavigableMutableAstTest.java | 44 +++++ .../CelNavigableMutableExprTest.java | 150 ++++++++++++++++++ .../main/java/dev/cel/optimizer/BUILD.bazel | 1 + .../dev/cel/optimizer/optimizers/BUILD.bazel | 1 + 9 files changed, 403 insertions(+), 3 deletions(-) create mode 100644 common/src/main/java/dev/cel/common/navigation/CelNavigableMutableAst.java create mode 100644 common/src/main/java/dev/cel/common/navigation/CelNavigableMutableExpr.java create mode 100644 common/src/test/java/dev/cel/common/navigation/CelNavigableMutableAstTest.java create mode 100644 common/src/test/java/dev/cel/common/navigation/CelNavigableMutableExprTest.java diff --git a/common/navigation/BUILD.bazel b/common/navigation/BUILD.bazel index f4e757ad5..df3447513 100644 --- a/common/navigation/BUILD.bazel +++ b/common/navigation/BUILD.bazel @@ -3,7 +3,17 @@ package( default_visibility = ["//visibility:public"], ) +java_library( + name = "common", + exports = ["//common/src/main/java/dev/cel/common/navigation:common"], +) + java_library( name = "navigation", exports = ["//common/src/main/java/dev/cel/common/navigation"], ) + +java_library( + name = "mutable_navigation", + exports = ["//common/src/main/java/dev/cel/common/navigation:mutable_navigation"], +) diff --git a/common/src/main/java/dev/cel/common/navigation/BUILD.bazel b/common/src/main/java/dev/cel/common/navigation/BUILD.bazel index 55ae48f72..1c1cd181f 100644 --- a/common/src/main/java/dev/cel/common/navigation/BUILD.bazel +++ b/common/src/main/java/dev/cel/common/navigation/BUILD.bazel @@ -8,11 +8,9 @@ package( ) java_library( - name = "navigation", + name = "common", srcs = [ "BaseNavigableExpr.java", - "CelNavigableAst.java", - "CelNavigableExpr.java", "CelNavigableExprVisitor.java", "ExprPropertyCalculator.java", "TraversalOrder.java", @@ -20,10 +18,47 @@ java_library( tags = [ ], deps = [ + "//:auto_value", + "//common/ast", + "@maven//:com_google_errorprone_error_prone_annotations", + "@maven//:com_google_guava_guava", + "@maven//:org_jspecify_jspecify", + ], +) + +java_library( + name = "navigation", + srcs = [ + "CelNavigableAst.java", + "CelNavigableExpr.java", + ], + tags = [ + ], + deps = [ + ":common", "//:auto_value", "//common", "//common/ast", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", + "@maven//:org_jspecify_jspecify", + ], +) + +java_library( + name = "mutable_navigation", + srcs = [ + "CelNavigableMutableAst.java", + "CelNavigableMutableExpr.java", + ], + tags = [ + ], + deps = [ + ":common", + "//:auto_value", + "//common/ast:mutable_ast", + "@maven//:com_google_errorprone_error_prone_annotations", + "@maven//:com_google_guava_guava", + "@maven//:org_jspecify_jspecify", ], ) diff --git a/common/src/main/java/dev/cel/common/navigation/CelNavigableMutableAst.java b/common/src/main/java/dev/cel/common/navigation/CelNavigableMutableAst.java new file mode 100644 index 000000000..f28ada79f --- /dev/null +++ b/common/src/main/java/dev/cel/common/navigation/CelNavigableMutableAst.java @@ -0,0 +1,47 @@ +// Copyright 2024 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.common.navigation; + +import dev.cel.common.ast.CelMutableAst; + +/** + * Decorates a {@link CelMutableAst} with navigational properties. This allows us to visit a node's + * children, descendants or its parent with ease. + */ +public final class CelNavigableMutableAst { + + private final CelMutableAst ast; + private final CelNavigableMutableExpr root; + + private CelNavigableMutableAst(CelMutableAst mutableAst) { + this.ast = mutableAst; + this.root = CelNavigableMutableExpr.fromExpr(mutableAst.expr()); + } + + /** Constructs a new instance of {@link CelNavigableMutableAst} from {@link CelMutableAst}. */ + public static CelNavigableMutableAst fromAst(CelMutableAst ast) { + return new CelNavigableMutableAst(ast); + } + + /** Returns the root of the AST. */ + public CelNavigableMutableExpr getRoot() { + return root; + } + + /** Returns the underlying {@link CelMutableAst}. */ + public CelMutableAst getAst() { + return ast; + } +} diff --git a/common/src/main/java/dev/cel/common/navigation/CelNavigableMutableExpr.java b/common/src/main/java/dev/cel/common/navigation/CelNavigableMutableExpr.java new file mode 100644 index 000000000..b9af67675 --- /dev/null +++ b/common/src/main/java/dev/cel/common/navigation/CelNavigableMutableExpr.java @@ -0,0 +1,109 @@ +// Copyright 2024 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.common.navigation; + +import com.google.auto.value.AutoValue; +import dev.cel.common.ast.CelMutableExpr; +import dev.cel.common.navigation.ExprPropertyCalculator.ExprProperty; +import java.util.Optional; +import java.util.stream.Stream; + +/** + * CelNavigableMutableExpr decorates {@link CelMutableExpr} with capabilities to inspect the parent + * and its descendants with ease. + */ +@AutoValue +// unchecked: Generic types are properly bound to BaseNavigableExpr +// redundant override: Overriding is required to specify the return type to a concrete type. +@SuppressWarnings({"unchecked", "RedundantOverride"}) +public abstract class CelNavigableMutableExpr extends BaseNavigableExpr { + + /** Constructs a new instance of {@link CelNavigableMutableExpr} from {@link CelMutableExpr}. */ + public static CelNavigableMutableExpr fromExpr(CelMutableExpr expr) { + ExprPropertyCalculator exprHeightCalculator = + new ExprPropertyCalculator<>(expr); + ExprProperty exprProperty = exprHeightCalculator.getProperty(expr.id()); + + return builder() + .setExpr(expr) + .setHeight(exprProperty.height()) + .setMaxId(exprProperty.maxId()) + .build(); + } + + @Override + public Stream allNodes() { + return super.allNodes(); + } + + @Override + public Stream allNodes(TraversalOrder traversalOrder) { + return super.allNodes(traversalOrder); + } + + @Override + public abstract Optional parent(); + + @Override + public Stream descendants() { + return super.descendants(); + } + + @Override + public Stream descendants(TraversalOrder traversalOrder) { + return super.descendants(traversalOrder); + } + + @Override + public Stream children() { + return super.children(); + } + + @Override + public Stream children(TraversalOrder traversalOrder) { + return super.children(traversalOrder); + } + + @Override + public Builder builderFromInstance() { + return builder(); + } + + /** Create a new builder to construct a {@link CelNavigableExpr} instance. */ + public static CelNavigableMutableExpr.Builder builder() { + return new AutoValue_CelNavigableMutableExpr.Builder().setDepth(0).setHeight(0).setMaxId(0); + } + + /** Builder to configure {@link CelNavigableExpr}. */ + @AutoValue.Builder + public abstract static class Builder + implements BaseNavigableExpr.Builder { + + @Override + public abstract Builder setParent(CelNavigableMutableExpr value); + + @Override + public abstract Builder setExpr(CelMutableExpr value); + + @Override + public abstract Builder setDepth(int value); + + @Override + public abstract Builder setMaxId(long value); + + @Override + public abstract Builder setHeight(int value); + } +} diff --git a/common/src/test/java/dev/cel/common/navigation/BUILD.bazel b/common/src/test/java/dev/cel/common/navigation/BUILD.bazel index 490819e77..40e04a70d 100644 --- a/common/src/test/java/dev/cel/common/navigation/BUILD.bazel +++ b/common/src/test/java/dev/cel/common/navigation/BUILD.bazel @@ -12,7 +12,10 @@ java_library( "//common:compiler_common", "//common:options", "//common/ast", + "//common/ast:mutable_ast", "//common/navigation", + "//common/navigation:common", + "//common/navigation:mutable_navigation", "//common/resources/testdata/proto3:test_all_types_java_proto", "//common/types", "//compiler", diff --git a/common/src/test/java/dev/cel/common/navigation/CelNavigableMutableAstTest.java b/common/src/test/java/dev/cel/common/navigation/CelNavigableMutableAstTest.java new file mode 100644 index 000000000..3d7f8bfcd --- /dev/null +++ b/common/src/test/java/dev/cel/common/navigation/CelNavigableMutableAstTest.java @@ -0,0 +1,44 @@ +// Copyright 2024 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.common.navigation; + +import static com.google.common.truth.Truth.assertThat; + +import dev.cel.common.ast.CelConstant; +import dev.cel.common.ast.CelMutableAst; +import dev.cel.common.ast.CelMutableExpr; +import dev.cel.compiler.CelCompiler; +import dev.cel.compiler.CelCompilerFactory; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class CelNavigableMutableAstTest { + + @Test + public void construct_success() throws Exception { + CelCompiler celCompiler = CelCompilerFactory.standardCelCompilerBuilder().build(); + CelMutableAst ast = CelMutableAst.fromCelAst(celCompiler.compile("'Hello World'").getAst()); + + CelNavigableMutableAst navigableAst = CelNavigableMutableAst.fromAst(ast); + + assertThat(navigableAst.getAst()).isEqualTo(ast); + assertThat(navigableAst.getRoot().expr()) + .isEqualTo(CelMutableExpr.ofConstant(1, CelConstant.ofValue("Hello World"))); + assertThat(navigableAst.getRoot().parent()).isEmpty(); + assertThat(navigableAst.getRoot().depth()).isEqualTo(0); + } +} diff --git a/common/src/test/java/dev/cel/common/navigation/CelNavigableMutableExprTest.java b/common/src/test/java/dev/cel/common/navigation/CelNavigableMutableExprTest.java new file mode 100644 index 000000000..7d6a9e0f7 --- /dev/null +++ b/common/src/test/java/dev/cel/common/navigation/CelNavigableMutableExprTest.java @@ -0,0 +1,150 @@ +// Copyright 2024 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.common.navigation; + +import static com.google.common.collect.ImmutableList.toImmutableList; +import static com.google.common.truth.Truth.assertThat; + +import com.google.common.collect.ImmutableList; +import dev.cel.common.ast.CelConstant; +import dev.cel.common.ast.CelExpr.ExprKind.Kind; +import dev.cel.common.ast.CelMutableExpr; +import dev.cel.common.ast.CelMutableExpr.CelMutableCreateList; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class CelNavigableMutableExprTest { + + @Test + public void construct_withoutParent() { + CelMutableExpr constExpr = CelMutableExpr.ofConstant(1, CelConstant.ofValue("test")); + + CelNavigableMutableExpr navigableExpr = + CelNavigableMutableExpr.builder().setExpr(constExpr).setDepth(2).build(); + + assertThat(navigableExpr.expr()).isEqualTo(constExpr); + assertThat(navigableExpr.depth()).isEqualTo(2); + assertThat(navigableExpr.parent()).isEmpty(); + } + + @Test + public void construct_withParent() { + CelMutableExpr constExpr = CelMutableExpr.ofConstant(1, CelConstant.ofValue("test")); + CelMutableExpr identExpr = CelMutableExpr.ofIdent(2, "a"); + + CelNavigableMutableExpr parentExpr = + CelNavigableMutableExpr.builder().setExpr(identExpr).setDepth(1).build(); + CelNavigableMutableExpr navigableExpr = + CelNavigableMutableExpr.builder() + .setExpr(constExpr) + .setDepth(2) + .setParent(parentExpr) + .build(); + + assertThat(parentExpr.expr()).isEqualTo(identExpr); + assertThat(parentExpr.depth()).isEqualTo(1); + assertThat(parentExpr.parent()).isEmpty(); + assertThat(navigableExpr.expr()).isEqualTo(constExpr); + assertThat(navigableExpr.depth()).isEqualTo(2); + assertThat(navigableExpr.parent()).hasValue(parentExpr); + } + + @Test + public void builderFromInstance_sameAsStaticBuilder() { + CelNavigableMutableExpr.Builder staticBuilder = + CelNavigableMutableExpr.builder().setExpr(CelMutableExpr.ofNotSet()); + + CelNavigableMutableExpr.Builder builderFromInstance = + CelNavigableMutableExpr.fromExpr(CelMutableExpr.ofNotSet()) + .builderFromInstance() + .setExpr(CelMutableExpr.ofNotSet()); + + assertThat(staticBuilder.build()).isEqualTo(builderFromInstance.build()); + } + + @Test + public void allNodes_filteredConstants_returnsAllConstants() { + CelNavigableMutableExpr mutableExpr = + CelNavigableMutableExpr.fromExpr( + CelMutableExpr.ofCreateList( + CelMutableCreateList.create( + CelMutableExpr.ofConstant(CelConstant.ofValue("element1")), + CelMutableExpr.ofCreateList( + CelMutableCreateList.create( + CelMutableExpr.ofConstant(CelConstant.ofValue("element2"))))))); + + ImmutableList allNodes = + mutableExpr + .allNodes() + .filter(node -> node.getKind().equals(Kind.CONSTANT)) + .map(BaseNavigableExpr::expr) + .collect(toImmutableList()); + + assertThat(allNodes) + .containsExactly( + CelMutableExpr.ofConstant(CelConstant.ofValue("element1")), + CelMutableExpr.ofConstant(CelConstant.ofValue("element2"))) + .inOrder(); + } + + @Test + public void descendants_filteredConstants_returnsAllConstants() { + CelNavigableMutableExpr mutableExpr = + CelNavigableMutableExpr.fromExpr( + CelMutableExpr.ofCreateList( + CelMutableCreateList.create( + CelMutableExpr.ofConstant(CelConstant.ofValue("element1")), + CelMutableExpr.ofCreateList( + CelMutableCreateList.create( + CelMutableExpr.ofConstant(CelConstant.ofValue("element2"))))))); + + ImmutableList allNodes = + mutableExpr + .descendants() + .filter(node -> node.getKind().equals(Kind.CONSTANT)) + .map(BaseNavigableExpr::expr) + .collect(toImmutableList()); + + assertThat(allNodes) + .containsExactly( + CelMutableExpr.ofConstant(CelConstant.ofValue("element1")), + CelMutableExpr.ofConstant(CelConstant.ofValue("element2"))) + .inOrder(); + } + + @Test + public void children_filteredConstants_returnsSingleConstant() { + CelNavigableMutableExpr mutableExpr = + CelNavigableMutableExpr.fromExpr( + CelMutableExpr.ofCreateList( + CelMutableCreateList.create( + CelMutableExpr.ofConstant(CelConstant.ofValue("element1")), + CelMutableExpr.ofCreateList( + CelMutableCreateList.create( + CelMutableExpr.ofConstant(CelConstant.ofValue("element2"))))))); + + ImmutableList allNodes = + mutableExpr + .children() + .filter(node -> node.getKind().equals(Kind.CONSTANT)) + .map(BaseNavigableExpr::expr) + .collect(toImmutableList()); + + assertThat(allNodes) + .containsExactly(CelMutableExpr.ofConstant(CelConstant.ofValue("element1"))); + } +} diff --git a/optimizer/src/main/java/dev/cel/optimizer/BUILD.bazel b/optimizer/src/main/java/dev/cel/optimizer/BUILD.bazel index 07de0dd06..a6751d8af 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/BUILD.bazel +++ b/optimizer/src/main/java/dev/cel/optimizer/BUILD.bazel @@ -92,6 +92,7 @@ java_library( "//common/ast:expr_factory", "//common/ast:mutable_ast", "//common/navigation", + "//common/navigation:common", "//common/types:type_providers", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel b/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel index 38267774f..1dbd78f3b 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel @@ -46,6 +46,7 @@ java_library( "//common:compiler_common", "//common/ast", "//common/navigation", + "//common/navigation:common", "//common/types", "//common/types:type_providers", "//extensions:optional_library", From c7c2447868315a00b3455395ea8957e1cbec6cc5 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Thu, 18 Apr 2024 13:05:15 -0700 Subject: [PATCH 090/486] Dedupe enum types by enum descriptor's fully qualified name in ProtoMessageTypeProvider PiperOrigin-RevId: 626125941 --- .../test/java/dev/cel/bundle/CelImplTest.java | 31 +++++++++++++++++++ .../types/ProtoMessageTypeProvider.java | 7 +++-- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/bundle/src/test/java/dev/cel/bundle/CelImplTest.java b/bundle/src/test/java/dev/cel/bundle/CelImplTest.java index 625d2d1a7..3beeb3af9 100644 --- a/bundle/src/test/java/dev/cel/bundle/CelImplTest.java +++ b/bundle/src/test/java/dev/cel/bundle/CelImplTest.java @@ -41,12 +41,15 @@ import com.google.common.util.concurrent.MoreExecutors; import com.google.protobuf.Any; import com.google.protobuf.ByteString; +import com.google.protobuf.DescriptorProtos.FileDescriptorProto; import com.google.protobuf.DescriptorProtos.FileDescriptorSet; +import com.google.protobuf.Descriptors.FileDescriptor; import com.google.protobuf.Duration; import com.google.protobuf.FieldMask; import com.google.protobuf.Message; import com.google.protobuf.NullValue; import com.google.protobuf.Struct; +import com.google.protobuf.TextFormat; import com.google.protobuf.Timestamp; import com.google.protobuf.util.Timestamps; import com.google.rpc.context.AttributeContext; @@ -1021,6 +1024,34 @@ public void compile_enumTypeTransitiveResolutionFailure() { assertThat(e).hasMessageThat().contains("undeclared reference to 'NullValue'"); } + @Test + public void compile_multipleInstancesOfEnumDescriptor_dedupedByFullName() throws Exception { + String enumTextProto = + "name: \"standalone_global_enum.proto\"\n" + + "package: \"dev.cel.testing.testdata.proto3\"\n" + + "enum_type {\n" + + " name: \"StandaloneGlobalEnum\"\n" + + " value {\n" + + " name: \"SGOO\"\n" + + " number: 0\n" + + " }\n" + + "}\n" + + "syntax: \"proto3\"\n"; + FileDescriptorProto enumFileDescriptorProto = + TextFormat.parse(enumTextProto, FileDescriptorProto.class); + FileDescriptor enumFileDescriptor = + FileDescriptor.buildFrom(enumFileDescriptorProto, new FileDescriptor[] {}); + Cel cel = + standardCelBuilderWithMacros() + .setContainer("dev.cel.testing.testdata") + .addFileTypes(enumFileDescriptor) + .addFileTypes(StandaloneGlobalEnum.getDescriptor().getFile()) + .build(); + + assertThat(cel.compile("dev.cel.testing.testdata.proto3.StandaloneGlobalEnum.SGOO").getAst()) + .isNotNull(); + } + @Test public void program_customVarResolver() throws Exception { Cel cel = diff --git a/common/src/main/java/dev/cel/common/types/ProtoMessageTypeProvider.java b/common/src/main/java/dev/cel/common/types/ProtoMessageTypeProvider.java index f366a79bb..4b97178d0 100644 --- a/common/src/main/java/dev/cel/common/types/ProtoMessageTypeProvider.java +++ b/common/src/main/java/dev/cel/common/types/ProtoMessageTypeProvider.java @@ -142,8 +142,11 @@ private ImmutableMap createProtoMessageTypes( private ImmutableMap createEnumTypes( Collection enumDescriptors) { - ImmutableMap.Builder enumTypes = ImmutableMap.builder(); + HashMap enumTypes = new HashMap<>(); for (EnumDescriptor enumDescriptor : enumDescriptors) { + if (enumTypes.containsKey(enumDescriptor.getFullName())) { + continue; + } ImmutableMap values = enumDescriptor.getValues().stream() .collect( @@ -151,7 +154,7 @@ private ImmutableMap createEnumTypes( enumTypes.put( enumDescriptor.getFullName(), EnumType.create(enumDescriptor.getFullName(), values)); } - return enumTypes.buildOrThrow(); + return ImmutableMap.copyOf(enumTypes); } private static class FieldResolver { From 59565af72fc2f38d8d99c1d6e8d5ec152800b72d Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Thu, 18 Apr 2024 14:36:50 -0700 Subject: [PATCH 091/486] Change AST Mutator to accept mutable ASTs PiperOrigin-RevId: 626153876 --- .../main/java/dev/cel/common/CelSource.java | 4 + .../dev/cel/common/navigation/BUILD.bazel | 1 + .../navigation/CelNavigableMutableAst.java | 13 + .../java/dev/cel/optimizer/AstMutator.java | 843 ++++++++++-------- .../main/java/dev/cel/optimizer/BUILD.bazel | 1 + .../optimizers/SubexpressionOptimizer.java | 7 +- .../dev/cel/optimizer/AstMutatorTest.java | 478 +++++----- .../test/java/dev/cel/optimizer/BUILD.bazel | 2 + 8 files changed, 755 insertions(+), 594 deletions(-) diff --git a/common/src/main/java/dev/cel/common/CelSource.java b/common/src/main/java/dev/cel/common/CelSource.java index 6adaf8773..2422f7b20 100644 --- a/common/src/main/java/dev/cel/common/CelSource.java +++ b/common/src/main/java/dev/cel/common/CelSource.java @@ -279,6 +279,10 @@ public Builder clearMacroCall(long exprId) { return this; } + public ImmutableSet getExtensions() { + return extensions.build(); + } + /** * Adds one or more {@link Extension}s to the source information. Extensions implement set * semantics and deduped if same ones are provided. diff --git a/common/src/main/java/dev/cel/common/navigation/BUILD.bazel b/common/src/main/java/dev/cel/common/navigation/BUILD.bazel index 1c1cd181f..903ae3f0f 100644 --- a/common/src/main/java/dev/cel/common/navigation/BUILD.bazel +++ b/common/src/main/java/dev/cel/common/navigation/BUILD.bazel @@ -57,6 +57,7 @@ java_library( ":common", "//:auto_value", "//common/ast:mutable_ast", + "//common/types:type_providers", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", "@maven//:org_jspecify_jspecify", diff --git a/common/src/main/java/dev/cel/common/navigation/CelNavigableMutableAst.java b/common/src/main/java/dev/cel/common/navigation/CelNavigableMutableAst.java index f28ada79f..bda18dc03 100644 --- a/common/src/main/java/dev/cel/common/navigation/CelNavigableMutableAst.java +++ b/common/src/main/java/dev/cel/common/navigation/CelNavigableMutableAst.java @@ -15,6 +15,8 @@ package dev.cel.common.navigation; import dev.cel.common.ast.CelMutableAst; +import dev.cel.common.types.CelType; +import java.util.Optional; /** * Decorates a {@link CelMutableAst} with navigational properties. This allows us to visit a node's @@ -44,4 +46,15 @@ public CelNavigableMutableExpr getRoot() { public CelMutableAst getAst() { return ast; } + + /** + * Returns the type of the expression node for a type-checked AST. This simply proxies down the + * call to {@link CelMutableAst#getType(long)}. + * + * @return Optional of {@link CelType} or {@link Optional#empty} if the type does not exist at the + * ID. + */ + public Optional getType(long exprId) { + return ast.getType(exprId); + } } diff --git a/optimizer/src/main/java/dev/cel/optimizer/AstMutator.java b/optimizer/src/main/java/dev/cel/optimizer/AstMutator.java index 94a4f4724..2ce5fdddc 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/AstMutator.java +++ b/optimizer/src/main/java/dev/cel/optimizer/AstMutator.java @@ -14,37 +14,39 @@ package dev.cel.optimizer; -import static com.google.common.collect.ImmutableList.toImmutableList; import static com.google.common.collect.ImmutableMap.toImmutableMap; import static java.lang.Math.max; +import static java.util.stream.Collectors.toCollection; import com.google.auto.value.AutoValue; -import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; import com.google.common.collect.HashBasedTable; -import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Table; import com.google.errorprone.annotations.Immutable; import dev.cel.common.CelAbstractSyntaxTree; import dev.cel.common.CelSource; +import dev.cel.common.ast.CelConstant; import dev.cel.common.ast.CelExpr; -import dev.cel.common.ast.CelExpr.CelCall; -import dev.cel.common.ast.CelExpr.CelComprehension; -import dev.cel.common.ast.CelExpr.CelIdent; import dev.cel.common.ast.CelExpr.ExprKind.Kind; -import dev.cel.common.ast.CelExprFactory; import dev.cel.common.ast.CelExprIdGeneratorFactory; import dev.cel.common.ast.CelExprIdGeneratorFactory.ExprIdGenerator; -import dev.cel.common.ast.CelExprIdGeneratorFactory.MonotonicIdGenerator; import dev.cel.common.ast.CelExprIdGeneratorFactory.StableIdGenerator; -import dev.cel.common.navigation.CelNavigableAst; +import dev.cel.common.ast.CelMutableAst; +import dev.cel.common.ast.CelMutableExpr; +import dev.cel.common.ast.CelMutableExpr.CelMutableCall; +import dev.cel.common.ast.CelMutableExpr.CelMutableComprehension; +import dev.cel.common.ast.CelMutableExpr.CelMutableCreateList; +import dev.cel.common.ast.CelMutableExprConverter; import dev.cel.common.navigation.CelNavigableExpr; +import dev.cel.common.navigation.CelNavigableMutableAst; +import dev.cel.common.navigation.CelNavigableMutableExpr; import dev.cel.common.navigation.TraversalOrder; import dev.cel.common.types.CelType; -import java.util.Collection; +import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map.Entry; import java.util.NoSuchElementException; import java.util.Optional; @@ -53,12 +55,14 @@ /** AstMutator contains logic for mutating a {@link CelAbstractSyntaxTree}. */ @Immutable +@SuppressWarnings("InlineMeSuggester") // Deprecated methods are not used and will be removed. public final class AstMutator { private static final ExprIdGenerator NO_OP_ID_GENERATOR = id -> id; + private static final ExprIdGenerator UNSET_ID_GENERATOR = id -> 0; private final long iterationLimit; /** - * Returns a new instance of a AST Mutator with the iteration limit set. + * Returns a new instance of a AST mutator with the iteration limit set. * *

Mutation is performed by walking the existing AST until the expression node to replace is * found, then the new subtree is walked to complete the mutation. Visiting of each node @@ -76,86 +80,70 @@ private AstMutator(long iterationLimit) { this.iterationLimit = iterationLimit; } - /** Replaces all the expression IDs in the expression tree with 0. */ - public CelExpr clearExprIds(CelExpr celExpr) { - return renumberExprIds((unused) -> 0, celExpr.toBuilder()).build(); - } - /** - * Replaces a subtree in the given expression node. This operation is intended for AST - * optimization purposes. - * - *

This is a very dangerous operation. Callers should re-typecheck the mutated AST and - * additionally verify that the resulting AST is semantically valid. - * - *

All expression IDs will be renumbered in a stable manner to ensure there's no ID collision - * between the nodes. The renumbering occurs even if the subtree was not replaced. - * - *

If the ability to unparse an expression containing a macro call must be retained, use {@link - * #replaceSubtree(CelAbstractSyntaxTree, CelExpr, long) instead.} + * TODO: Temporarily kept to retain method signature. Remove in the upcoming CLs. * - * @param celExpr Original expression node to rewrite. - * @param newExpr New CelExpr to replace the subtree with. - * @param exprIdToReplace Expression id of the subtree that is getting replaced. + * @deprecated Use MutableExpr based APIs instead. */ - public CelExpr replaceSubtree(CelExpr celExpr, CelExpr newExpr, long exprIdToReplace) { - MonotonicIdGenerator monotonicIdGenerator = - CelExprIdGeneratorFactory.newMonotonicIdGenerator(0); - return mutateExpr( - unused -> monotonicIdGenerator.nextExprId(), - celExpr.toBuilder(), - newExpr.toBuilder(), - exprIdToReplace) - .build(); + @Deprecated + public CelExpr clearExprIds(CelExpr expr) { + return CelMutableExprConverter.fromMutableExpr( + clearExprIds(CelMutableExprConverter.fromCelExpr(expr))); + } + + /** Replaces all the expression IDs in the expression tree with 0. */ + public CelMutableExpr clearExprIds(CelMutableExpr expr) { + return renumberExprIds(UNSET_ID_GENERATOR, expr); } /** - * Replaces a subtree in the given AST. This operation is intended for AST optimization purposes. + * TODO: Temporarily kept to retain method signature. Remove in the upcoming CLs. * - *

This is a very dangerous operation. Callers should re-typecheck the mutated AST and - * additionally verify that the resulting AST is semantically valid. - * - *

All expression IDs will be renumbered in a stable manner to ensure there's no ID collision - * between the nodes. The renumbering occurs even if the subtree was not replaced. - * - *

This will scrub out the description, positions and line offsets from {@code CelSource}. If - * the source contains macro calls, its call IDs will be to be consistent with the renumbered IDs - * in the AST. - * - * @param ast Original ast to mutate. - * @param newExpr New CelExpr to replace the subtree with. - * @param exprIdToReplace Expression id of the subtree that is getting replaced. + * @deprecated Use MutableExpr based APIs instead. */ - public CelAbstractSyntaxTree replaceSubtree( - CelAbstractSyntaxTree ast, CelExpr newExpr, long exprIdToReplace) { - return replaceSubtreeWithNewAst( - ast, - CelAbstractSyntaxTree.newParsedAst( - newExpr, - // Copy the macro call information to the new AST such that macro call map can be - // normalized post-replacement. - CelSource.newBuilder().addAllMacroCalls(ast.getSource().getMacroCalls()).build()), - exprIdToReplace); + @Deprecated + public CelAbstractSyntaxTree wrapAstWithNewCelBlock( + String celBlockFunction, CelAbstractSyntaxTree ast, List subexpressions) { + return wrapAstWithNewCelBlock( + celBlockFunction, + CelMutableAst.fromCelAst(ast), + subexpressions.stream() + .map(CelMutableExprConverter::fromCelExpr) + .collect(toCollection(ArrayList::new))) + .toParsedAst(); } /** Wraps the given AST and its subexpressions with a new cel.@block call. */ - public CelAbstractSyntaxTree wrapAstWithNewCelBlock( - String celBlockFunction, CelAbstractSyntaxTree ast, Collection subexpressions) { + public CelMutableAst wrapAstWithNewCelBlock( + String celBlockFunction, CelMutableAst ast, List subexpressions) { long maxId = getMaxId(ast); - CelExpr blockExpr = - CelExpr.newBuilder() - .setId(++maxId) - .setCall( - CelCall.newBuilder() - .setFunction(celBlockFunction) - .addArgs( - CelExpr.ofCreateListExpr( - ++maxId, ImmutableList.copyOf(subexpressions), ImmutableList.of()), - ast.getExpr()) - .build()) - .build(); - - return CelAbstractSyntaxTree.newParsedAst(blockExpr, ast.getSource()); + CelMutableExpr blockExpr = + CelMutableExpr.ofCall( + ++maxId, + CelMutableCall.create( + celBlockFunction, + CelMutableExpr.ofCreateList(++maxId, CelMutableCreateList.create(subexpressions)), + ast.expr())); + + return CelMutableAst.of(blockExpr, ast.source()); + } + + /** + * TODO: Temporarily kept to retain method signature. Remove in the upcoming CLs. + * + * @deprecated Use MutableExpr based APIs instead. + */ + @Deprecated + public CelAbstractSyntaxTree replaceSubtreeWithNewBindMacro( + CelAbstractSyntaxTree ast, String varName, CelExpr varInit, CelExpr resultExpr, long id) { + return replaceSubtreeWithNewBindMacro( + CelMutableAst.fromCelAst(ast), + varName, + CelMutableExprConverter.fromCelExpr(varInit), + CelMutableExprConverter.fromCelExpr(resultExpr), + id, + true) + .toParsedAst(); } /** @@ -164,49 +152,62 @@ public CelAbstractSyntaxTree wrapAstWithNewCelBlock( * *

The bind call takes the format of: {@code cel.bind(varInit, varName, resultExpr)} * - * @param ast Original ast to mutate. + * @param ast Original AST to mutate. * @param varName New variable name for the bind macro call. * @param varInit Initialization expression to bind to the local variable. * @param resultExpr Result expression * @param exprIdToReplace Expression ID of the subtree that is getting replaced. + * @param populateMacroSource If true, populates the cel.bind macro source in the AST. */ - public CelAbstractSyntaxTree replaceSubtreeWithNewBindMacro( - CelAbstractSyntaxTree ast, + public CelMutableAst replaceSubtreeWithNewBindMacro( + CelMutableAst ast, String varName, - CelExpr varInit, - CelExpr resultExpr, - long exprIdToReplace) { + CelMutableExpr varInit, + CelMutableExpr resultExpr, + long exprIdToReplace, + boolean populateMacroSource) { + // Copy the incoming expressions to prevent modifying the root long maxId = max(getMaxId(varInit), getMaxId(ast)); StableIdGenerator stableIdGenerator = CelExprIdGeneratorFactory.newStableIdGenerator(maxId); - BindMacro bindMacro = newBindMacro(varName, varInit, resultExpr, stableIdGenerator); - // In situations where the existing AST already contains a macro call (ex: nested cel.binds), - // its macro source must be normalized to make it consistent with the newly generated bind - // macro. - CelSource celSource = - normalizeMacroSource( - ast.getSource(), - -1, // Do not replace any of the subexpr in the macro map. - bindMacro.bindMacro().toBuilder(), - stableIdGenerator::renumberId); - celSource = - celSource.toBuilder() - .addMacroCalls(bindMacro.bindExpr().id(), bindMacro.bindMacro()) - .build(); + CelMutableExpr newBindMacroExpr = + newBindMacroExpr( + varName, varInit, CelMutableExpr.newInstance(resultExpr), stableIdGenerator); + CelSource.Builder celSource = CelSource.newBuilder(); + if (populateMacroSource) { + CelMutableExpr newBindMacroSourceExpr = + newBindMacroSourceExpr(newBindMacroExpr, varName, stableIdGenerator); + // In situations where the existing AST already contains a macro call (ex: nested cel.binds), + // its macro source must be normalized to make it consistent with the newly generated bind + // macro. + celSource = + normalizeMacroSource( + ast.source(), + -1, // Do not replace any of the subexpr in the macro map. + newBindMacroSourceExpr, + stableIdGenerator::renumberId) + .addMacroCalls( + newBindMacroExpr.id(), + CelMutableExprConverter.fromMutableExpr(newBindMacroSourceExpr)); + } + + CelMutableAst newBindAst = CelMutableAst.of(newBindMacroExpr, celSource); - return replaceSubtreeWithNewAst( - ast, CelAbstractSyntaxTree.newParsedAst(bindMacro.bindExpr(), celSource), exprIdToReplace); + return replaceSubtree(ast, newBindAst, exprIdToReplace); } - /** Renumbers all the expr IDs in the given AST in a consecutive manner starting from 1. */ public CelAbstractSyntaxTree renumberIdsConsecutively(CelAbstractSyntaxTree ast) { + return renumberIdsConsecutively(CelMutableAst.fromCelAst(ast)).toParsedAst(); + } + + /** Renumbers all the expr IDs in the given AST in a consecutive manner starting from 1. */ + public CelMutableAst renumberIdsConsecutively(CelMutableAst mutableAst) { StableIdGenerator stableIdGenerator = CelExprIdGeneratorFactory.newStableIdGenerator(0); - CelExpr.Builder root = - renumberExprIds(stableIdGenerator::renumberId, ast.getExpr().toBuilder()); - CelSource newSource = + CelMutableExpr mutableExpr = renumberExprIds(stableIdGenerator::renumberId, mutableAst.expr()); + CelSource.Builder newSource = normalizeMacroSource( - ast.getSource(), Integer.MIN_VALUE, root, stableIdGenerator::renumberId); + mutableAst.source(), Integer.MIN_VALUE, mutableExpr, stableIdGenerator::renumberId); - return CelAbstractSyntaxTree.newParsedAst(root.build(), newSource); + return CelMutableAst.of(mutableExpr, newSource); } /** @@ -235,23 +236,24 @@ public CelAbstractSyntaxTree renumberIdsConsecutively(CelAbstractSyntaxTree ast) * && [true].exists(@c1:0, @c1:0))} * * - * @param ast AST to mutate + * @param ast AST containing type-checked references * @param newIterVarPrefix Prefix to use for new iteration variable identifier name. For example, * providing @c will produce @c0:0, @c0:1, @c1:0, @c2:0... as new names. * @param newResultPrefix Prefix to use for new comprehensin result identifier names. */ public MangledComprehensionAst mangleComprehensionIdentifierNames( CelAbstractSyntaxTree ast, String newIterVarPrefix, String newResultPrefix) { - CelNavigableAst newNavigableAst = CelNavigableAst.fromAst(ast); - Predicate comprehensionIdentifierPredicate = x -> true; + CelNavigableMutableAst navigableMutableAst = + CelNavigableMutableAst.fromAst(CelMutableAst.fromCelAst(ast)); + Predicate comprehensionIdentifierPredicate = x -> true; comprehensionIdentifierPredicate = comprehensionIdentifierPredicate .and(node -> node.getKind().equals(Kind.COMPREHENSION)) .and(node -> !node.expr().comprehension().iterVar().startsWith(newIterVarPrefix)) .and(node -> !node.expr().comprehension().accuVar().startsWith(newResultPrefix)); - LinkedHashMap comprehensionsToMangle = - newNavigableAst + LinkedHashMap comprehensionsToMangle = + navigableMutableAst .getRoot() // This is important - mangling needs to happen bottom-up to avoid stepping over // shadowed variables that are not part of the comprehension being mangled. @@ -260,11 +262,10 @@ public MangledComprehensionAst mangleComprehensionIdentifierNames( .filter( node -> { // Ensure the iter_var or the comprehension result is actually referenced in the - // loop_step. If it's not, we - // can skip mangling. + // loop_step. If it's not, we can skip mangling. String iterVar = node.expr().comprehension().iterVar(); String result = node.expr().comprehension().result().ident().name(); - return CelNavigableExpr.fromExpr(node.expr().comprehension().loopStep()) + return CelNavigableMutableExpr.fromExpr(node.expr().comprehension().loopStep()) .allNodes() .filter(subNode -> subNode.getKind().equals(Kind.IDENT)) .map(subNode -> subNode.expr().ident()) @@ -275,36 +276,46 @@ public MangledComprehensionAst mangleComprehensionIdentifierNames( Collectors.toMap( k -> k, v -> { - CelComprehension comprehension = v.expr().comprehension(); + CelMutableComprehension comprehension = v.expr().comprehension(); String iterVar = comprehension.iterVar(); - // Identifiers to mangle could be the iteration variable, comprehension result - // or both, but at least one has to exist. - // As an example, [1,2].map(i, 3) would produce an optional.empty because `i` - // is not actually used. + // Identifiers to mangle could be the iteration variable, comprehension + // result or both, but at least one has to exist. + // As an example, [1,2].map(i, 3) would result in optional.empty for iteration + // variable because `i` is not actually used. Optional iterVarId = - CelNavigableExpr.fromExpr(comprehension.loopStep()) + CelNavigableMutableExpr.fromExpr(comprehension.loopStep()) .allNodes() .filter( loopStepNode -> - loopStepNode.expr().identOrDefault().name().equals(iterVar)) - .map(CelNavigableExpr::id) + loopStepNode.getKind().equals(Kind.IDENT) + && loopStepNode.expr().ident().name().equals(iterVar)) + .map(CelNavigableMutableExpr::id) .findAny(); Optional iterVarType = iterVarId.map( id -> - ast.getType(id) + navigableMutableAst + .getType(id) .orElseThrow( () -> new NoSuchElementException( - "Checked type not present for iteration variable:" - + " " + "Checked type not present for iteration" + + " variable: " + iterVarId))); - Optional resultType = ast.getType(comprehension.result().id()); + CelType resultType = + navigableMutableAst + .getType(comprehension.result().id()) + .orElseThrow( + () -> + new IllegalStateException( + "Result type was not present for the comprehension ID: " + + comprehension.result().id())); return MangledComprehensionType.of(iterVarType, resultType); }, (x, y) -> { - throw new IllegalStateException("Unexpected CelNavigableExpr collision"); + throw new IllegalStateException( + "Unexpected CelNavigableMutableExpr collision"); }, LinkedHashMap::new)); int iterCount = 0; @@ -315,21 +326,15 @@ public MangledComprehensionAst mangleComprehensionIdentifierNames( // Intermediary table used for the purposes of generating a unique mangled variable name. Table comprehensionLevelToType = HashBasedTable.create(); - for (Entry comprehensionEntry : + CelMutableExpr mutatedComprehensionExpr = navigableMutableAst.getAst().expr(); + CelSource.Builder newSource = navigableMutableAst.getAst().source(); + for (Entry comprehensionEntry : comprehensionsToMangle.entrySet()) { iterCount++; - // Refetch the comprehension node as mutating the AST could have renumbered its IDs. - CelNavigableExpr comprehensionNode = - newNavigableAst - .getRoot() - .allNodes(TraversalOrder.POST_ORDER) - .filter(comprehensionIdentifierPredicate) - .findAny() - .orElseThrow( - () -> new NoSuchElementException("Failed to refetch mutated comprehension")); + CelNavigableMutableExpr comprehensionNode = comprehensionEntry.getKey(); MangledComprehensionType comprehensionEntryType = comprehensionEntry.getValue(); - CelExpr.Builder comprehensionExpr = comprehensionNode.expr().toBuilder(); + CelMutableExpr comprehensionExpr = comprehensionNode.expr(); int comprehensionNestingLevel = countComprehensionNestingLevel(comprehensionNode); MangledComprehensionName mangledComprehensionName; if (comprehensionLevelToType.contains(comprehensionNestingLevel, comprehensionEntryType)) { @@ -352,25 +357,21 @@ public MangledComprehensionAst mangleComprehensionIdentifierNames( String iterVar = comprehensionExpr.comprehension().iterVar(); String accuVar = comprehensionExpr.comprehension().accuVar(); - CelExpr.Builder mutatedComprehensionExpr = + mutatedComprehensionExpr = mangleIdentsInComprehensionExpr( - newNavigableAst.getAst().getExpr().toBuilder(), + mutatedComprehensionExpr, comprehensionExpr, iterVar, accuVar, mangledComprehensionName); // Repeat the mangling process for the macro source. - CelSource newSource = + newSource = mangleIdentsInMacroSource( - newNavigableAst.getAst(), + newSource, mutatedComprehensionExpr, iterVar, mangledComprehensionName, comprehensionExpr.id()); - - newNavigableAst = - CelNavigableAst.fromAst( - CelAbstractSyntaxTree.newParsedAst(mutatedComprehensionExpr.build(), newSource)); } if (iterCount >= iterationLimit) { @@ -381,100 +382,200 @@ public MangledComprehensionAst mangleComprehensionIdentifierNames( } return MangledComprehensionAst.of( - newNavigableAst.getAst(), ImmutableMap.copyOf(mangledIdentNamesToType)); + CelMutableAst.of(mutatedComprehensionExpr, newSource), + ImmutableMap.copyOf(mangledIdentNamesToType)); + } + + /** + * TODO: Temporarily kept to retain method signature. Remove in the upcoming CLs. + * + * @deprecated Use MutableExpr based APIs instead. + */ + @Deprecated + public CelExpr replaceSubtree(CelExpr celExpr, CelExpr newExpr, long id) { + return replaceSubtree( + CelMutableExprConverter.fromCelExpr(celExpr), + CelMutableExprConverter.fromCelExpr(newExpr), + id) + .toParsedAst() + .getExpr(); + } + + /** + * TODO: Temporarily kept to retain method signature. Remove in the upcoming CLs. + * + * @deprecated Use MutableExpr based APIs instead. + */ + @Deprecated + public CelAbstractSyntaxTree replaceSubtree( + CelAbstractSyntaxTree root, CelExpr newExpr, long id) { + return replaceSubtree( + CelMutableAst.fromCelAst(root), CelMutableExprConverter.fromCelExpr(newExpr), id) + .toParsedAst(); + } + + /** + * Replaces a subtree in the given expression node. This operation is intended for AST + * optimization purposes. + * + *

This is a very dangerous operation. Callers must re-typecheck the mutated AST and + * additionally verify that the resulting AST is semantically valid. + * + *

All expression IDs will be renumbered in a stable manner to ensure there's no ID collision + * between the nodes. The renumbering occurs even if the subtree was not replaced. + * + *

If the ability to unparse an expression containing a macro call must be retained, use {@link + * #replaceSubtree(CelMutableAst, CelMutableAst, long) instead.} + * + * @param root Original expression node to rewrite. + * @param newExpr New CelExpr to replace the subtree with. + * @param exprIdToReplace Expression id of the subtree that is getting replaced. + */ + public CelMutableAst replaceSubtree( + CelMutableExpr root, CelMutableExpr newExpr, long exprIdToReplace) { + return replaceSubtree(CelMutableAst.of(root, CelSource.newBuilder()), newExpr, exprIdToReplace); + } + + /** + * Replaces a subtree in the given AST. This operation is intended for AST optimization purposes. + * + *

This is a very dangerous operation. Callers must re-typecheck the mutated AST and + * additionally verify that the resulting AST is semantically valid. + * + *

All expression IDs will be renumbered in a stable manner to ensure there's no ID collision + * between the nodes. The renumbering occurs even if the subtree was not replaced. + * + *

This will scrub out the description, positions and line offsets from {@code CelSource}. If + * the source contains macro calls, its call IDs will be to be consistent with the renumbered IDs + * in the AST. + * + * @param ast Original ast to mutate. + * @param newExpr New CelExpr to replace the subtree with. + * @param exprIdToReplace Expression id of the subtree that is getting replaced. + */ + public CelMutableAst replaceSubtree( + CelMutableAst ast, CelMutableExpr newExpr, long exprIdToReplace) { + return replaceSubtree( + ast, + CelMutableAst.of( + newExpr, + // Copy the macro call information to the new AST such that macro call map can be + // normalized post-replacement. + CelSource.newBuilder().addAllMacroCalls(ast.source().getMacroCalls())), + exprIdToReplace); } /** - * Mutates the given AST by replacing a subtree at a given index. + * Replaces a subtree in the given AST. This operation is intended for AST optimization purposes. * - * @param ast Existing AST being mutated - * @param newAst New subtree to perform the replacement with. If the subtree has a macro map - * populated, its macro source is merged with the existing AST's after normalization. - * @param exprIdToReplace The expr ID in the existing AST to replace the subtree at. + *

This is a very dangerous operation. Callers must re-typecheck the mutated AST and + * additionally verify that the resulting AST is semantically valid. + * + *

All expression IDs will be renumbered in a stable manner to ensure there's no ID collision + * between the nodes. The renumbering occurs even if the subtree was not replaced. + * + *

This will scrub out the description, positions and line offsets from {@code CelSource}. If + * the source contains macro calls, its call IDs will be to be consistent with the renumbered IDs + * in the AST. + * + * @param ast Original ast to mutate. + * @param newAst New AST to replace the subtree with. + * @param exprIdToReplace Expression id of the subtree that is getting replaced. */ - @VisibleForTesting - CelAbstractSyntaxTree replaceSubtreeWithNewAst( - CelAbstractSyntaxTree ast, CelAbstractSyntaxTree newAst, long exprIdToReplace) { + public CelMutableAst replaceSubtree( + CelMutableAst ast, CelMutableAst newAst, long exprIdToReplace) { + return replaceSubtree( + CelNavigableMutableAst.fromAst(ast), + CelNavigableMutableAst.fromAst(newAst), + exprIdToReplace); + } + + /** + * Replaces a subtree in the given AST. This operation is intended for AST optimization purposes. + * + *

This is a very dangerous operation. Callers must re-typecheck the mutated AST and + * additionally verify that the resulting AST is semantically valid. + * + *

All expression IDs will be renumbered in a stable manner to ensure there's no ID collision + * between the nodes. The renumbering occurs even if the subtree was not replaced. + * + *

This will scrub out the description, positions and line offsets from {@code CelSource}. If + * the source contains macro calls, its call IDs will be to be consistent with the renumbered IDs + * in the AST. + * + * @param navAst Original navigable ast to mutate. + * @param navNewAst New navigable AST to replace the subtree with. + * @param exprIdToReplace Expression id of the subtree that is getting replaced. + */ + public CelMutableAst replaceSubtree( + CelNavigableMutableAst navAst, CelNavigableMutableAst navNewAst, long exprIdToReplace) { // Stabilize the incoming AST by renumbering all of its expression IDs. - long maxId = max(getMaxId(ast), getMaxId(newAst)); + long maxId = max(getMaxId(navAst), getMaxId(navNewAst)); + CelMutableAst ast = navAst.getAst(); + CelMutableAst newAst = navNewAst.getAst(); newAst = stabilizeAst(newAst, maxId); + long stablizedNewExprRootId = newAst.expr().id(); // Mutate the AST root with the new subtree. All the existing expr IDs are renumbered in the // process, but its original IDs are memoized so that we can normalize the expr IDs // in the macro source map. StableIdGenerator stableIdGenerator = CelExprIdGeneratorFactory.newStableIdGenerator(getMaxId(newAst)); - CelExpr.Builder mutatedRoot = - mutateExpr( - stableIdGenerator::renumberId, - ast.getExpr().toBuilder(), - newAst.getExpr().toBuilder(), - exprIdToReplace); - - CelSource newAstSource = ast.getSource(); - if (!newAst.getSource().getMacroCalls().isEmpty()) { - // The root is mutated, but the expr IDs in the macro map needs to be normalized. - // In situations where an AST with a new macro map is being inserted (ex: new bind call), - // the new subtree's expr ID is not memoized in the stable ID generator because the ID never - // existed in the main AST. - // In this case, we forcibly memoize the new subtree ID with a newly generated ID so - // that the macro map IDs can be normalized properly. + + CelMutableExpr mutatedRoot = + mutateExpr(stableIdGenerator::renumberId, ast.expr(), newAst.expr(), exprIdToReplace); + CelSource.Builder newAstSource = CelSource.newBuilder(); + if (!ast.source().getMacroCalls().isEmpty()) { + newAstSource = combine(newAstSource, ast.source()); + } + + if (!newAst.source().getMacroCalls().isEmpty()) { stableIdGenerator.memoize( - newAst.getExpr().id(), stableIdGenerator.renumberId(exprIdToReplace)); - newAstSource = combine(newAstSource, newAst.getSource()); + stablizedNewExprRootId, stableIdGenerator.renumberId(exprIdToReplace)); + newAstSource = combine(newAstSource, newAst.source()); } newAstSource = normalizeMacroSource( newAstSource, exprIdToReplace, mutatedRoot, stableIdGenerator::renumberId); - - return CelAbstractSyntaxTree.newParsedAst(mutatedRoot.build(), newAstSource); + return CelMutableAst.of(mutatedRoot, newAstSource); } - private CelExpr.Builder mangleIdentsInComprehensionExpr( - CelExpr.Builder root, - CelExpr.Builder comprehensionExpr, + private CelMutableExpr mangleIdentsInComprehensionExpr( + CelMutableExpr root, + CelMutableExpr comprehensionExpr, String originalIterVar, String originalAccuVar, MangledComprehensionName mangledComprehensionName) { - CelExpr.Builder modifiedLoopStep = - replaceIdentName( - comprehensionExpr.comprehension().loopStep().toBuilder(), - originalIterVar, - mangledComprehensionName.iterVarName()); - comprehensionExpr.setComprehension( - comprehensionExpr.comprehension().toBuilder() - .setLoopStep(modifiedLoopStep.build()) - .build()); - comprehensionExpr = - replaceIdentName(comprehensionExpr, originalAccuVar, mangledComprehensionName.resultName()); - - CelComprehension.Builder newComprehension = - comprehensionExpr.comprehension().toBuilder() - .setIterVar(mangledComprehensionName.iterVarName()); + CelMutableComprehension comprehension = comprehensionExpr.comprehension(); + replaceIdentName( + comprehension.loopStep(), originalIterVar, mangledComprehensionName.iterVarName()); + replaceIdentName(comprehensionExpr, originalAccuVar, mangledComprehensionName.resultName()); + + comprehension.setIterVar(mangledComprehensionName.iterVarName()); // Most standard macros set accu_var as __result__, but not all (ex: cel.bind). - if (newComprehension.accuVar().equals(originalAccuVar)) { - newComprehension.setAccuVar(mangledComprehensionName.resultName()); + if (comprehension.accuVar().equals(originalAccuVar)) { + comprehension.setAccuVar(mangledComprehensionName.resultName()); } - return mutateExpr( - NO_OP_ID_GENERATOR, - root, - comprehensionExpr.setComprehension(newComprehension.build()), - comprehensionExpr.id()); + return mutateExpr(NO_OP_ID_GENERATOR, root, comprehensionExpr, comprehensionExpr.id()); } - private CelExpr.Builder replaceIdentName( - CelExpr.Builder comprehensionExpr, String originalIdentName, String newIdentName) { + private void replaceIdentName( + CelMutableExpr comprehensionExpr, String originalIdentName, String newIdentName) { int iterCount; for (iterCount = 0; iterCount < iterationLimit; iterCount++) { - Optional identToMangle = - CelNavigableExpr.fromExpr(comprehensionExpr.build()) + CelMutableExpr identToMangle = + CelNavigableMutableExpr.fromExpr(comprehensionExpr) .descendants() - .map(CelNavigableExpr::expr) - .filter(node -> node.identOrDefault().name().equals(originalIdentName)) - .findAny(); - if (!identToMangle.isPresent()) { + .map(CelNavigableMutableExpr::expr) + .filter( + node -> + node.getKind().equals(Kind.IDENT) + && node.ident().name().equals(originalIdentName)) + .findAny() + .orElse(null); + if (identToMangle == null) { break; } @@ -482,31 +583,29 @@ private CelExpr.Builder replaceIdentName( mutateExpr( NO_OP_ID_GENERATOR, comprehensionExpr, - CelExpr.newBuilder().setIdent(CelIdent.newBuilder().setName(newIdentName).build()), - identToMangle.get().id()); + CelMutableExpr.ofIdent(newIdentName), + identToMangle.id()); } if (iterCount >= iterationLimit) { throw new IllegalStateException("Max iteration count reached."); } - - return comprehensionExpr; } - private CelSource mangleIdentsInMacroSource( - CelAbstractSyntaxTree ast, - CelExpr.Builder mutatedComprehensionExpr, + private CelSource.Builder mangleIdentsInMacroSource( + CelSource.Builder sourceBuilder, + CelMutableExpr mutatedComprehensionExpr, String originalIterVar, MangledComprehensionName mangledComprehensionName, long originalComprehensionId) { - if (!ast.getSource().getMacroCalls().containsKey(originalComprehensionId)) { - return ast.getSource(); + if (!sourceBuilder.getMacroCalls().containsKey(originalComprehensionId)) { + return sourceBuilder; } // First, normalize the macro source. // ex: [x].exists(x, [x].exists(x, x == 1)) -> [x].exists(x, [@c1].exists(x, @c0 == 1)). CelSource.Builder newSource = - normalizeMacroSource(ast.getSource(), -1, mutatedComprehensionExpr, (id) -> id).toBuilder(); + normalizeMacroSource(sourceBuilder, -1, mutatedComprehensionExpr, (id) -> id); // Note that in the above example, the iteration variable is not replaced after normalization. // This is because populating a macro call map upon parse generates a new unique identifier @@ -515,62 +614,69 @@ private CelSource mangleIdentsInMacroSource( // variable actually exists in the main AST thus, this step isn't needed. // ex: [1].map(x, [2].filter(y, x == y). Here, the variable declaration `x` exists in the AST // but not `y`. - CelExpr.Builder macroExpr = newSource.getMacroCalls().get(originalComprehensionId).toBuilder(); + CelMutableExpr macroExpr = + CelMutableExprConverter.fromCelExpr(newSource.getMacroCalls().get(originalComprehensionId)); // By convention, the iteration variable is always the first argument of the // macro call expression. - CelExpr identToMangle = macroExpr.call().args().get(0); - if (identToMangle.identOrDefault().name().equals(originalIterVar)) { + CelMutableExpr identToMangle = macroExpr.call().args().get(0); + if (identToMangle.ident().name().equals(originalIterVar)) { + // if (identToMangle.identOrDefault().name().equals(originalIterVar)) { macroExpr = mutateExpr( NO_OP_ID_GENERATOR, macroExpr, - CelExpr.newBuilder() - .setIdent( - CelIdent.newBuilder() - .setName(mangledComprehensionName.iterVarName()) - .build()), + CelMutableExpr.ofIdent(mangledComprehensionName.iterVarName()), identToMangle.id()); } - newSource.addMacroCalls(originalComprehensionId, macroExpr.build()); - return newSource.build(); + newSource.addMacroCalls( + originalComprehensionId, CelMutableExprConverter.fromMutableExpr(macroExpr)); + + return newSource; } - private BindMacro newBindMacro( - String varName, CelExpr varInit, CelExpr resultExpr, StableIdGenerator stableIdGenerator) { + private CelMutableExpr newBindMacroExpr( + String varName, + CelMutableExpr varInit, + CelMutableExpr resultExpr, + StableIdGenerator stableIdGenerator) { // Renumber incoming expression IDs in the init and result expression to avoid collision with // the main AST. Existing IDs are memoized for a macro source sanitization pass at the end // (e.g: inserting a bind macro to an existing macro expr) - varInit = renumberExprIds(stableIdGenerator::nextExprId, varInit.toBuilder()).build(); - resultExpr = renumberExprIds(stableIdGenerator::nextExprId, resultExpr.toBuilder()).build(); - CelExprFactory exprFactory = - CelExprFactory.newInstance((unused) -> stableIdGenerator.nextExprId()); - CelExpr bindMacroExpr = - exprFactory.fold( + varInit = renumberExprIds(stableIdGenerator::nextExprId, varInit); + resultExpr = renumberExprIds(stableIdGenerator::nextExprId, resultExpr); + + long iterRangeId = stableIdGenerator.nextExprId(); + long loopConditionId = stableIdGenerator.nextExprId(); + long loopStepId = stableIdGenerator.nextExprId(); + long comprehensionId = stableIdGenerator.nextExprId(); + + return CelMutableExpr.ofComprehension( + comprehensionId, + CelMutableComprehension.create( "#unused", - exprFactory.newList(), + CelMutableExpr.ofCreateList(iterRangeId, CelMutableCreateList.create()), varName, varInit, - exprFactory.newBoolLiteral(false), - exprFactory.newIdentifier(varName), - resultExpr); - - CelExpr bindMacroCallExpr = - exprFactory - .newReceiverCall( - "bind", - CelExpr.ofIdentExpr(stableIdGenerator.nextExprId(), "cel"), - CelExpr.ofIdentExpr(stableIdGenerator.nextExprId(), varName), - bindMacroExpr.comprehension().accuInit(), - bindMacroExpr.comprehension().result()) - .toBuilder() - .setId(0) - .build(); - - return BindMacro.of(bindMacroExpr, bindMacroCallExpr); - } - - private static CelSource combine(CelSource celSource1, CelSource celSource2) { + CelMutableExpr.ofConstant(loopConditionId, CelConstant.ofValue(false)), + CelMutableExpr.ofIdent(loopStepId, varName), + resultExpr)); + } + + private CelMutableExpr newBindMacroSourceExpr( + CelMutableExpr bindMacroExpr, String varName, StableIdGenerator stableIdGenerator) { + return CelMutableExpr.ofCall( + 0, // Required sentinel value for macro call + CelMutableCall.create( + CelMutableExpr.ofIdent(stableIdGenerator.nextExprId(), "cel"), + "bind", + CelMutableExpr.ofIdent(stableIdGenerator.nextExprId(), varName), + bindMacroExpr.comprehension().accuInit(), + bindMacroExpr.comprehension().result())); + } + + private static CelSource.Builder combine( + CelSource.Builder celSource1, CelSource.Builder celSource2) { ImmutableMap.Builder macroMap = ImmutableMap.builder(); macroMap.putAll(celSource1.getMacroCalls()); macroMap.putAll(celSource2.getMacroCalls()); @@ -578,8 +684,7 @@ private static CelSource combine(CelSource celSource1, CelSource celSource2) { return CelSource.newBuilder() .addAllExtensions(celSource1.getExtensions()) .addAllExtensions(celSource2.getExtensions()) - .addAllMacroCalls(macroMap.buildOrThrow()) - .build(); + .addAllMacroCalls(macroMap.buildOrThrow()); } /** @@ -587,52 +692,51 @@ private static CelSource combine(CelSource celSource1, CelSource celSource2) { * (monotonically increased) from the starting seed ID. If the AST contains any macro calls, its * IDs are also normalized. */ - private CelAbstractSyntaxTree stabilizeAst(CelAbstractSyntaxTree ast, long seedExprId) { + private CelMutableAst stabilizeAst(CelMutableAst mutableAst, long seedExprId) { + CelMutableExpr mutableExpr = mutableAst.expr(); + CelSource.Builder source = mutableAst.source(); StableIdGenerator stableIdGenerator = CelExprIdGeneratorFactory.newStableIdGenerator(seedExprId); - CelExpr.Builder newExprBuilder = - renumberExprIds(stableIdGenerator::nextExprId, ast.getExpr().toBuilder()); - - if (ast.getSource().getMacroCalls().isEmpty()) { - return CelAbstractSyntaxTree.newParsedAst(newExprBuilder.build(), ast.getSource()); - } + CelMutableExpr mutatedExpr = renumberExprIds(stableIdGenerator::nextExprId, mutableExpr); CelSource.Builder sourceBuilder = - CelSource.newBuilder().addAllExtensions(ast.getSource().getExtensions()); + CelSource.newBuilder().addAllExtensions(source.getExtensions()); // Update the macro call IDs and their call IDs - for (Entry macroCall : ast.getSource().getMacroCalls().entrySet()) { + for (Entry macroCall : source.getMacroCalls().entrySet()) { long macroId = macroCall.getKey(); long newCallId = stableIdGenerator.renumberId(macroId); + CelMutableExpr existingMacroCallExpr = + CelMutableExprConverter.fromCelExpr(macroCall.getValue()); - CelExpr.Builder newCall = - renumberExprIds(stableIdGenerator::renumberId, macroCall.getValue().toBuilder()); + CelMutableExpr newCall = + renumberExprIds(stableIdGenerator::renumberId, existingMacroCallExpr); - sourceBuilder.addMacroCalls(newCallId, newCall.build()); + sourceBuilder.addMacroCalls(newCallId, CelMutableExprConverter.fromMutableExpr(newCall)); } - return CelAbstractSyntaxTree.newParsedAst(newExprBuilder.build(), sourceBuilder.build()); + return CelMutableAst.of(mutatedExpr, sourceBuilder); } - private CelSource normalizeMacroSource( - CelSource celSource, + private CelSource.Builder normalizeMacroSource( + CelSource.Builder celSource, long exprIdToReplace, - CelExpr.Builder mutatedRoot, + CelMutableExpr mutatedRoot, ExprIdGenerator idGenerator) { // Remove the macro metadata that no longer exists in the AST due to being replaced. - celSource = celSource.toBuilder().clearMacroCall(exprIdToReplace).build(); + celSource.clearMacroCall(exprIdToReplace); CelSource.Builder sourceBuilder = CelSource.newBuilder().addAllExtensions(celSource.getExtensions()); if (celSource.getMacroCalls().isEmpty()) { - return sourceBuilder.build(); + return sourceBuilder; } - ImmutableMap allExprs = - CelNavigableExpr.fromExpr(mutatedRoot.build()) + ImmutableMap allExprs = + CelNavigableMutableExpr.fromExpr(mutatedRoot) .allNodes() - .map(CelNavigableExpr::expr) + .map(CelNavigableMutableExpr::expr) .collect( toImmutableMap( - CelExpr::id, + CelMutableExpr::id, expr -> expr, (expr1, expr2) -> { // Comprehensions can reuse same expression (result). We just need to ensure @@ -653,23 +757,26 @@ private CelSource normalizeMacroSource( continue; } - CelExpr.Builder newMacroCallExpr = - renumberExprIds(idGenerator, existingMacroCall.getValue().toBuilder()); + CelMutableExpr existingMacroCallExpr = + CelMutableExprConverter.fromCelExpr(existingMacroCall.getValue()); + CelMutableExpr newMacroCallExpr = renumberExprIds(idGenerator, existingMacroCallExpr); - CelNavigableExpr callNav = CelNavigableExpr.fromExpr(newMacroCallExpr.build()); - ImmutableList callDescendants = - callNav.descendants().map(CelNavigableExpr::expr).collect(toImmutableList()); + CelNavigableMutableExpr callNav = CelNavigableMutableExpr.fromExpr(newMacroCallExpr); + ArrayList callDescendants = + callNav + .descendants() + .map(CelNavigableMutableExpr::expr) + .collect(toCollection(ArrayList::new)); - for (CelExpr callChild : callDescendants) { + for (CelMutableExpr callChild : callDescendants) { if (!allExprs.containsKey(callChild.id())) { continue; } - CelExpr mutatedExpr = allExprs.get(callChild.id()); + CelMutableExpr mutatedExpr = allExprs.get(callChild.id()); if (!callChild.equals(mutatedExpr)) { newMacroCallExpr = - mutateExpr( - NO_OP_ID_GENERATOR, newMacroCallExpr, mutatedExpr.toBuilder(), callChild.id()); + mutateExpr(NO_OP_ID_GENERATOR, newMacroCallExpr, mutatedExpr, callChild.id()); } } @@ -677,55 +784,55 @@ private CelSource normalizeMacroSource( long replacedId = idGenerator.generate(exprIdToReplace); boolean isListExprBeingReplaced = allExprs.containsKey(replacedId) - && allExprs.get(replacedId).exprKind().getKind().equals(Kind.CREATE_LIST); + && allExprs.get(replacedId).getKind().equals(Kind.CREATE_LIST); if (isListExprBeingReplaced) { unwrapListArgumentsInMacroCallExpr( allExprs.get(callId).comprehension(), newMacroCallExpr); } } - sourceBuilder.addMacroCalls(callId, newMacroCallExpr.build()); + sourceBuilder.addMacroCalls( + callId, CelMutableExprConverter.fromMutableExpr(newMacroCallExpr)); } // Replace comprehension nodes with a NOT_SET reference to reduce AST size. for (Entry macroCall : sourceBuilder.getMacroCalls().entrySet()) { - CelExpr macroCallExpr = macroCall.getValue(); - CelNavigableExpr.fromExpr(macroCallExpr) + CelMutableExpr macroCallExpr = CelMutableExprConverter.fromCelExpr(macroCall.getValue()); + CelNavigableMutableExpr.fromExpr(macroCallExpr) .allNodes() .filter(node -> node.getKind().equals(Kind.COMPREHENSION)) - .map(CelNavigableExpr::expr) + .map(CelNavigableMutableExpr::expr) .forEach( node -> { - CelExpr.Builder mutatedNode = + CelMutableExpr mutatedNode = mutateExpr( - (id) -> id, - macroCallExpr.toBuilder(), - CelExpr.ofNotSet(node.id()).toBuilder(), + NO_OP_ID_GENERATOR, + macroCallExpr, + CelMutableExpr.ofNotSet(node.id()), node.id()); - macroCall.setValue(mutatedNode.build()); + macroCall.setValue(CelMutableExprConverter.fromMutableExpr(mutatedNode)); }); // Prune any NOT_SET (comprehension) nodes that no longer exist in the main AST // This can occur from pulling out a nested comprehension into a separate cel.block index - CelNavigableExpr.fromExpr(macroCallExpr) + CelNavigableMutableExpr.fromExpr(macroCallExpr) .allNodes() .filter(node -> node.getKind().equals(Kind.NOT_SET)) - .map(CelNavigableExpr::id) + .map(CelNavigableMutableExpr::id) .filter(id -> !allExprs.containsKey(id)) .forEach( id -> { - ImmutableList newCallArgs = + ArrayList newCallArgs = macroCallExpr.call().args().stream() .filter(node -> node.id() != id) - .collect(toImmutableList()); - CelCall.Builder call = - macroCallExpr.call().toBuilder().clearArgs().addArgs(newCallArgs); - - macroCall.setValue(macroCallExpr.toBuilder().setCall(call.build()).build()); + .collect(toCollection(ArrayList::new)); + CelMutableCall call = macroCallExpr.call(); + call.setArgs(newCallArgs); + macroCall.setValue(CelMutableExprConverter.fromMutableExpr(macroCallExpr)); }); } - return sourceBuilder.build(); + return sourceBuilder; } /** @@ -741,69 +848,83 @@ private CelSource normalizeMacroSource( * arguments unwrapped. */ private static void unwrapListArgumentsInMacroCallExpr( - CelComprehension comprehension, CelExpr.Builder newMacroCallExpr) { - CelExpr accuInit = comprehension.accuInit(); - if (!accuInit.exprKind().getKind().equals(Kind.CREATE_LIST) + CelMutableComprehension comprehension, CelMutableExpr newMacroCallExpr) { + CelMutableExpr accuInit = comprehension.accuInit(); + if (!accuInit.getKind().equals(Kind.CREATE_LIST) || !accuInit.createList().elements().isEmpty()) { // Does not contain an extraneous list. return; } - CelExpr loopStepExpr = comprehension.loopStep(); - ImmutableList args = loopStepExpr.call().args(); - if (args.size() != 2) { + CelMutableExpr loopStepExpr = comprehension.loopStep(); + List loopStepArgs = loopStepExpr.call().args(); + if (loopStepArgs.size() != 2) { throw new IllegalArgumentException( String.format( "Expected exactly 2 arguments but got %d instead on expr id: %d", - args.size(), loopStepExpr.id())); + loopStepArgs.size(), loopStepExpr.id())); } - CelCall newMacroCall = newMacroCallExpr.call(); - newMacroCallExpr.setCall( - newMacroCallExpr.call().toBuilder() - .clearArgs() - .addArgs( - newMacroCall.args().get(0)) // iter_var is first argument of the call by convention - .addArgs(args.get(1).createList().elements()) - .build()); + CelMutableCall existingMacroCall = newMacroCallExpr.call(); + CelMutableCall newMacroCall = + existingMacroCall.target().isPresent() + ? CelMutableCall.create(existingMacroCall.target().get(), existingMacroCall.function()) + : CelMutableCall.create(existingMacroCall.function()); + newMacroCall.addArgs( + existingMacroCall.args().get(0)); // iter_var is first argument of the call by convention + newMacroCall.addArgs(loopStepArgs.get(1).createList().elements()); + + newMacroCallExpr.setCall(newMacroCall); } - private CelExpr.Builder mutateExpr( + private CelMutableExpr mutateExpr( ExprIdGenerator idGenerator, - CelExpr.Builder root, - CelExpr.Builder newExpr, + CelMutableExpr root, + CelMutableExpr newExpr, long exprIdToReplace) { - MutableExprVisitor astMutator = + MutableExprVisitor mutableAst = MutableExprVisitor.newInstance(idGenerator, newExpr, exprIdToReplace, iterationLimit); - return astMutator.visit(root); + return mutableAst.visit(root); } - private CelExpr.Builder renumberExprIds(ExprIdGenerator idGenerator, CelExpr.Builder root) { - MutableExprVisitor astMutator = + private CelMutableExpr renumberExprIds(ExprIdGenerator idGenerator, CelMutableExpr root) { + MutableExprVisitor mutableAst = MutableExprVisitor.newInstance(idGenerator, root, Integer.MIN_VALUE, iterationLimit); - return astMutator.visit(root); + return mutableAst.visit(root); } - private static long getMaxId(CelAbstractSyntaxTree ast) { - long maxId = getMaxId(ast.getExpr()); - for (Entry macroCall : ast.getSource().getMacroCalls().entrySet()) { + private static long getMaxId(CelExpr newExpr) { + return CelNavigableExpr.fromExpr(newExpr) + .allNodes() + .mapToLong(CelNavigableExpr::id) + .max() + .orElseThrow(NoSuchElementException::new); + } + + private static long getMaxId(CelMutableAst mutableAst) { + return getMaxId(CelNavigableMutableAst.fromAst(mutableAst)); + } + + private static long getMaxId(CelNavigableMutableAst navAst) { + long maxId = navAst.getRoot().maxId(); + for (Entry macroCall : navAst.getAst().source().getMacroCalls().entrySet()) { maxId = max(maxId, getMaxId(macroCall.getValue())); } return maxId; } - private static long getMaxId(CelExpr newExpr) { - return CelNavigableExpr.fromExpr(newExpr) + private static long getMaxId(CelMutableExpr mutableExpr) { + return CelNavigableMutableExpr.fromExpr(mutableExpr) .allNodes() - .mapToLong(CelNavigableExpr::id) + .mapToLong(CelNavigableMutableExpr::id) .max() .orElseThrow(NoSuchElementException::new); } - private static int countComprehensionNestingLevel(CelNavigableExpr comprehensionExpr) { + private static int countComprehensionNestingLevel(CelNavigableMutableExpr comprehensionExpr) { int nestedLevel = 0; - Optional maybeParent = comprehensionExpr.parent(); + Optional maybeParent = comprehensionExpr.parent(); while (maybeParent.isPresent()) { if (maybeParent.get().getKind().equals(Kind.COMPREHENSION)) { nestedLevel++; @@ -822,14 +943,24 @@ private static int countComprehensionNestingLevel(CelNavigableExpr comprehension public abstract static class MangledComprehensionAst { /** AST after the iteration variables have been mangled. */ - public abstract CelAbstractSyntaxTree ast(); + public abstract CelMutableAst mutableAst(); /** Map containing the mangled identifier names to their types. */ public abstract ImmutableMap mangledComprehensionMap(); + /** + * TODO: Temporarily kept to retain method signature. Remove in the upcoming CLs. + * + * @deprecated Use MutableExpr based APIs instead. + */ + @Deprecated + public CelAbstractSyntaxTree ast() { + return mutableAst().toParsedAst(); + } + private static MangledComprehensionAst of( - CelAbstractSyntaxTree ast, + CelMutableAst ast, ImmutableMap mangledComprehensionMap) { return new AutoValue_AstMutator_MangledComprehensionAst(ast, mangledComprehensionMap); } @@ -846,11 +977,9 @@ public abstract static class MangledComprehensionType { public abstract Optional iterVarType(); /** Type of comprehension result */ - public abstract Optional resultType(); + public abstract CelType resultType(); - private static MangledComprehensionType of( - Optional iterVarType, Optional resultType) { - Preconditions.checkArgument(iterVarType.isPresent() || resultType.isPresent()); + private static MangledComprehensionType of(Optional iterVarType, CelType resultType) { return new AutoValue_AstMutator_MangledComprehensionType(iterVarType, resultType); } } @@ -872,24 +1001,4 @@ private static MangledComprehensionName of(String iterVarName, String resultName return new AutoValue_AstMutator_MangledComprehensionName(iterVarName, resultName); } } - - /** - * Intermediate value class to store the generated CelExpr for the bind macro and the macro call - * information. - */ - @AutoValue - abstract static class BindMacro { - /** Comprehension expr for the generated cel.bind macro. */ - abstract CelExpr bindExpr(); - - /** - * Call expr representation that will be stored in the macro call map of the AST. This is - * typically used for the purposes of supporting unparse. - */ - abstract CelExpr bindMacro(); - - private static BindMacro of(CelExpr bindExpr, CelExpr bindMacro) { - return new AutoValue_AstMutator_BindMacro(bindExpr, bindMacro); - } - } } diff --git a/optimizer/src/main/java/dev/cel/optimizer/BUILD.bazel b/optimizer/src/main/java/dev/cel/optimizer/BUILD.bazel index a6751d8af..d7833098f 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/BUILD.bazel +++ b/optimizer/src/main/java/dev/cel/optimizer/BUILD.bazel @@ -93,6 +93,7 @@ java_library( "//common/ast:mutable_ast", "//common/navigation", "//common/navigation:common", + "//common/navigation:mutable_navigation", "//common/types:type_providers", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java index 76816810f..7397d78dd 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java @@ -222,12 +222,7 @@ private OptimizationResult optimizeUsingCelBlock(CelNavigableAst navigableAst, C iterVarType -> newVarDecls.add( CelVarDecl.newVarDeclaration(name.iterVarName(), iterVarType))); - type.resultType() - .ifPresent( - comprehensionResultType -> - newVarDecls.add( - CelVarDecl.newVarDeclaration( - name.resultName(), comprehensionResultType))); + newVarDecls.add(CelVarDecl.newVarDeclaration(name.resultName(), type.resultType())); }); // Type-check all sub-expressions then create new block index identifiers. diff --git a/optimizer/src/test/java/dev/cel/optimizer/AstMutatorTest.java b/optimizer/src/test/java/dev/cel/optimizer/AstMutatorTest.java index 6eb0e04b2..5f254dc07 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/AstMutatorTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/AstMutatorTest.java @@ -18,7 +18,6 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertThrows; -import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.testing.junit.testparameterinjector.TestParameterInjector; import com.google.testing.junit.testparameterinjector.TestParameters; @@ -33,12 +32,16 @@ import dev.cel.common.CelSource.Extension.Version; import dev.cel.common.ast.CelConstant; import dev.cel.common.ast.CelExpr; -import dev.cel.common.ast.CelExpr.CelCall; -import dev.cel.common.ast.CelExpr.CelIdent; -import dev.cel.common.ast.CelExpr.CelSelect; import dev.cel.common.ast.CelExpr.ExprKind.Kind; +import dev.cel.common.ast.CelMutableAst; +import dev.cel.common.ast.CelMutableExpr; +import dev.cel.common.ast.CelMutableExpr.CelMutableCall; +import dev.cel.common.ast.CelMutableExpr.CelMutableCreateList; +import dev.cel.common.ast.CelMutableExpr.CelMutableSelect; +import dev.cel.common.ast.CelMutableExprConverter; import dev.cel.common.navigation.CelNavigableAst; import dev.cel.common.navigation.CelNavigableExpr; +import dev.cel.common.navigation.CelNavigableMutableExpr; import dev.cel.common.types.SimpleType; import dev.cel.common.types.StructTypeReference; import dev.cel.extensions.CelExtensions; @@ -67,39 +70,44 @@ public class AstMutatorTest { .build(); private static final CelUnparser CEL_UNPARSER = CelUnparserFactory.newUnparser(); - private static final AstMutator MUTABLE_AST = AstMutator.newInstance(1000); + private static final AstMutator AST_MUTATOR = AstMutator.newInstance(1000); @Test - public void constExpr() throws Exception { + public void replaceSubtree_replaceConst() throws Exception { CelAbstractSyntaxTree ast = CEL.compile("10").getAst(); + CelMutableAst mutableAst = CelMutableAst.fromCelAst(ast); + CelMutableExpr newBooleanConst = CelMutableExpr.ofConstant(1, CelConstant.ofValue(true)); - CelAbstractSyntaxTree mutatedAst = - MUTABLE_AST.replaceSubtree( - ast, CelExpr.newBuilder().setConstant(CelConstant.ofValue(true)).build(), 1); + CelMutableAst result = + AST_MUTATOR.replaceSubtree(mutableAst, newBooleanConst, mutableAst.expr().id()); - assertThat(mutatedAst.getExpr()) + assertThat(result.toParsedAst().getExpr()) .isEqualTo(CelExpr.ofConstantExpr(3, CelConstant.ofValue(true))); } @Test public void astMutator_returnsParsedAst() throws Exception { CelAbstractSyntaxTree ast = CEL.compile("10").getAst(); + CelMutableAst mutableAst = CelMutableAst.fromCelAst(ast); + CelMutableExpr newBooleanConst = CelMutableExpr.ofConstant(1, CelConstant.ofValue(true)); - CelAbstractSyntaxTree mutatedAst = - MUTABLE_AST.replaceSubtree( - ast, CelExpr.newBuilder().setConstant(CelConstant.ofValue(true)).build(), 1); + CelMutableAst result = + AST_MUTATOR.replaceSubtree(mutableAst, newBooleanConst, mutableAst.expr().id()); assertThat(ast.isChecked()).isTrue(); - assertThat(mutatedAst.isChecked()).isFalse(); + assertThat(result.toParsedAst().isChecked()).isFalse(); } @Test public void astMutator_nonMacro_sourceCleared() throws Exception { CelAbstractSyntaxTree ast = CEL.compile("10").getAst(); + CelMutableAst mutableAst = CelMutableAst.fromCelAst(ast); + CelMutableExpr newBooleanConst = CelMutableExpr.ofConstant(1, CelConstant.ofValue(true)); CelAbstractSyntaxTree mutatedAst = - MUTABLE_AST.replaceSubtree( - ast, CelExpr.newBuilder().setConstant(CelConstant.ofValue(true)).build(), 1); + AST_MUTATOR + .replaceSubtree(mutableAst, newBooleanConst, mutableAst.expr().id()) + .toParsedAst(); assertThat(mutatedAst.getSource().getDescription()).isEmpty(); assertThat(mutatedAst.getSource().getLineOffsets()).isEmpty(); @@ -111,10 +119,11 @@ public void astMutator_nonMacro_sourceCleared() throws Exception { @Test public void astMutator_macro_sourceMacroCallsPopulated() throws Exception { CelAbstractSyntaxTree ast = CEL.compile("has(TestAllTypes{}.single_int32)").getAst(); + CelMutableAst mutableAst = CelMutableAst.fromCelAst(ast); + CelMutableExpr newBooleanConst = CelMutableExpr.ofConstant(1, CelConstant.ofValue(true)); CelAbstractSyntaxTree mutatedAst = - MUTABLE_AST.replaceSubtree( - ast, CelExpr.newBuilder().setConstant(CelConstant.ofValue(true)).build(), 1); + AST_MUTATOR.replaceSubtree(mutableAst, newBooleanConst, 1).toParsedAst(); // no_op assertThat(mutatedAst.getSource().getDescription()).isEmpty(); assertThat(mutatedAst.getSource().getLineOffsets()).isEmpty(); @@ -131,10 +140,12 @@ public void replaceSubtree_astContainsTaggedExtension_retained() throws Exceptio ast = CelAbstractSyntaxTree.newCheckedAst( ast.getExpr(), celSource, ast.getReferenceMap(), ast.getTypeMap()); + CelMutableAst mutableAst = CelMutableAst.fromCelAst(ast); CelAbstractSyntaxTree mutatedAst = - MUTABLE_AST.replaceSubtree( - ast, CelExpr.newBuilder().setConstant(CelConstant.ofValue(true)).build(), 1); + AST_MUTATOR + .replaceSubtree(mutableAst, CelMutableExpr.ofConstant(CelConstant.ofValue(true)), 1) + .toParsedAst(); assertThat(mutatedAst.getSource().getExtensions()).containsExactly(extension); } @@ -150,6 +161,7 @@ public void replaceSubtreeWithNewAst_astsContainTaggedExtension_retained() throw ast.getSource().toBuilder().addAllExtensions(extension).build(), ast.getReferenceMap(), ast.getTypeMap()); + CelMutableAst mutableAst = CelMutableAst.fromCelAst(ast); // Setup second AST with another test extension CelAbstractSyntaxTree astToReplaceWith = CEL.compile("cel.bind(a, true, a)").getAst(); Extension extension2 = Extension.create("test2", Version.of(2, 2)); @@ -159,10 +171,11 @@ public void replaceSubtreeWithNewAst_astsContainTaggedExtension_retained() throw astToReplaceWith.getSource().toBuilder().addAllExtensions(extension2).build(), astToReplaceWith.getReferenceMap(), astToReplaceWith.getTypeMap()); + CelMutableAst mutableAst2 = CelMutableAst.fromCelAst(astToReplaceWith); // Mutate the original AST with the new AST at the root CelAbstractSyntaxTree mutatedAst = - MUTABLE_AST.replaceSubtreeWithNewAst(ast, astToReplaceWith, ast.getExpr().id()); + AST_MUTATOR.replaceSubtree(mutableAst, mutableAst2, mutableAst.expr().id()).toParsedAst(); // Expect that both the extensions are merged assertThat(mutatedAst.getSource().getExtensions()).containsExactly(extension, extension2); @@ -179,6 +192,7 @@ public void replaceSubtreeWithNewAst_astsContainSameExtensions_deduped() throws ast.getSource().toBuilder().addAllExtensions(extension).build(), ast.getReferenceMap(), ast.getTypeMap()); + CelMutableAst mutableAst = CelMutableAst.fromCelAst(ast); // Setup second AST with the same test extension as above CelAbstractSyntaxTree astToReplaceWith = CEL.compile("cel.bind(a, true, a)").getAst(); Extension extension2 = Extension.create("test", Version.of(1, 1)); @@ -188,10 +202,11 @@ public void replaceSubtreeWithNewAst_astsContainSameExtensions_deduped() throws astToReplaceWith.getSource().toBuilder().addAllExtensions(extension2).build(), astToReplaceWith.getReferenceMap(), astToReplaceWith.getTypeMap()); + CelMutableAst mutableAst2 = CelMutableAst.fromCelAst(astToReplaceWith); // Mutate the original AST with the new AST at the root CelAbstractSyntaxTree mutatedAst = - MUTABLE_AST.replaceSubtreeWithNewAst(ast, astToReplaceWith, ast.getExpr().id()); + AST_MUTATOR.replaceSubtree(mutableAst, mutableAst2, mutableAst.expr().id()).toParsedAst(); // Expect that the extension is deduped assertThat(mutatedAst.getSource().getExtensions()).containsExactly(extension); @@ -207,10 +222,11 @@ public void replaceSubtree_rootReplacedWithMacro_macroCallPopulated( String source, int expectedMacroCallSize) throws Exception { CelAbstractSyntaxTree ast = CEL.compile("1").getAst(); CelAbstractSyntaxTree ast2 = CEL.compile(source).getAst(); + CelMutableAst mutableAst = CelMutableAst.fromCelAst(ast); + CelMutableAst mutableAst2 = CelMutableAst.fromCelAst(ast2); CelAbstractSyntaxTree mutatedAst = - MUTABLE_AST.replaceSubtreeWithNewAst( - ast, ast2, CelNavigableAst.fromAst(ast).getRoot().id()); + AST_MUTATOR.replaceSubtree(mutableAst, mutableAst2, mutableAst.expr().id()).toParsedAst(); assertThat(mutatedAst.getSource().getMacroCalls()).hasSize(expectedMacroCallSize); assertThat(CEL_UNPARSER.unparse(mutatedAst)).isEqualTo(source); @@ -218,30 +234,50 @@ public void replaceSubtree_rootReplacedWithMacro_macroCallPopulated( } @Test - public void replaceSubtree_branchReplacedWithMacro_macroCallPopulated() throws Exception { + public void replaceSubtree_leftBranchReplacedWithMacro_macroCallPopulated() throws Exception { CelAbstractSyntaxTree ast = CEL.compile("true && false").getAst(); CelAbstractSyntaxTree ast2 = CEL.compile("[1].exists(x, x > 0)").getAst(); + CelMutableAst mutableAst = CelMutableAst.fromCelAst(ast); + CelMutableAst mutableAst2 = CelMutableAst.fromCelAst(ast2); CelAbstractSyntaxTree mutatedAst = - MUTABLE_AST.replaceSubtreeWithNewAst(ast, ast2, 3); // Replace false with the macro expr - CelAbstractSyntaxTree mutatedAst2 = - MUTABLE_AST.replaceSubtreeWithNewAst(ast, ast2, 1); // Replace true with the macro expr + AST_MUTATOR + .replaceSubtree(mutableAst, mutableAst2, 3) + .toParsedAst(); // Replace false with the macro expr assertThat(mutatedAst.getSource().getMacroCalls()).hasSize(1); assertThat(CEL_UNPARSER.unparse(mutatedAst)).isEqualTo("true && [1].exists(x, x > 0)"); assertThat(CEL.createProgram(CEL.check(mutatedAst).getAst()).eval()).isEqualTo(true); - assertThat(mutatedAst2.getSource().getMacroCalls()).hasSize(1); - assertThat(CEL_UNPARSER.unparse(mutatedAst2)).isEqualTo("[1].exists(x, x > 0) && false"); - assertThat(CEL.createProgram(CEL.check(mutatedAst2).getAst()).eval()).isEqualTo(false); + } + + @Test + public void replaceSubtree_rightBranchReplacedWithMacro_macroCallPopulated() throws Exception { + CelAbstractSyntaxTree ast = CEL.compile("true && false").getAst(); + CelAbstractSyntaxTree ast2 = CEL.compile("[1].exists(x, x > 0)").getAst(); + CelMutableAst mutableAst = CelMutableAst.fromCelAst(ast); + CelMutableAst mutableAst2 = CelMutableAst.fromCelAst(ast2); + + CelAbstractSyntaxTree mutatedAst = + AST_MUTATOR + .replaceSubtree(mutableAst, mutableAst2, 1) + .toParsedAst(); // Replace true with the macro expr + + assertThat(mutatedAst.getSource().getMacroCalls()).hasSize(1); + assertThat(CEL_UNPARSER.unparse(mutatedAst)).isEqualTo("[1].exists(x, x > 0) && false"); + assertThat(CEL.createProgram(CEL.check(mutatedAst).getAst()).eval()).isEqualTo(false); } @Test public void replaceSubtree_macroInsertedIntoExistingMacro_macroCallPopulated() throws Exception { CelAbstractSyntaxTree ast = CEL.compile("[1].exists(x, x > 0 && true)").getAst(); CelAbstractSyntaxTree ast2 = CEL.compile("[2].exists(y, y > 0)").getAst(); + CelMutableAst mutableAst = CelMutableAst.fromCelAst(ast); + CelMutableAst mutableAst2 = CelMutableAst.fromCelAst(ast2); CelAbstractSyntaxTree mutatedAst = - MUTABLE_AST.replaceSubtreeWithNewAst(ast, ast2, 9); // Replace true with the ast2 maro expr + AST_MUTATOR + .replaceSubtree(mutableAst, mutableAst2, 9) + .toParsedAst(); // Replace true with the ast2 maro expr assertThat(mutatedAst.getSource().getMacroCalls()).hasSize(2); assertThat(CEL_UNPARSER.unparse(mutatedAst)) @@ -252,24 +288,25 @@ public void replaceSubtree_macroInsertedIntoExistingMacro_macroCallPopulated() t @Test public void replaceSubtreeWithNewBindMacro_replaceRoot() throws Exception { CelAbstractSyntaxTree ast = CEL.compile("1 + 1").getAst(); + CelMutableAst mutableAst = CelMutableAst.fromCelAst(ast); String variableName = "@r0"; - CelExpr resultExpr = - CelExpr.newBuilder() - .setCall( - CelCall.newBuilder() - .setFunction(Operator.ADD.getFunction()) - .addArgs( - CelExpr.ofIdentExpr(0, variableName), CelExpr.ofIdentExpr(0, variableName)) - .build()) - .build(); + CelMutableExpr resultExpr = + CelMutableExpr.ofCall( + CelMutableCall.create( + Operator.ADD.getFunction(), + CelMutableExpr.ofIdent(variableName), + CelMutableExpr.ofIdent(variableName))); CelAbstractSyntaxTree mutatedAst = - MUTABLE_AST.replaceSubtreeWithNewBindMacro( - ast, - variableName, - CelExpr.ofConstantExpr(0, CelConstant.ofValue(3L)), - resultExpr, - CelNavigableAst.fromAst(ast).getRoot().id()); + AST_MUTATOR + .replaceSubtreeWithNewBindMacro( + mutableAst, + variableName, + CelMutableExpr.ofConstant(CelConstant.ofValue(3L)), + resultExpr, + mutableAst.expr().id(), + true) + .toParsedAst(); assertThat(mutatedAst.getSource().getMacroCalls()).hasSize(1); assertThat(CEL_UNPARSER.unparse(mutatedAst)).isEqualTo("cel.bind(@r0, 3, @r0 + @r0)"); @@ -282,58 +319,45 @@ public void replaceSubtreeWithNewBindMacro_nestedBindMacro_replaceComprehensionR throws Exception { // Arrange CelAbstractSyntaxTree ast = CEL.compile("1 + 1").getAst(); + CelMutableAst mutableAst = CelMutableAst.fromCelAst(ast); String variableName = "@r0"; - CelExpr resultExpr = - CelExpr.newBuilder() - .setCall( - CelCall.newBuilder() - .setFunction(Operator.ADD.getFunction()) - .addArgs( - CelExpr.ofIdentExpr(0, variableName), CelExpr.ofIdentExpr(0, variableName)) - .build()) - .build(); + CelMutableExpr resultExpr = + CelMutableExpr.ofCall( + CelMutableCall.create( + Operator.ADD.getFunction(), + CelMutableExpr.ofIdent(variableName), + CelMutableExpr.ofIdent(variableName))); // Act // Perform the initial replacement. (1 + 1) -> cel.bind(@r0, 3, @r0 + @r0) - CelAbstractSyntaxTree mutatedAst = - MUTABLE_AST.replaceSubtreeWithNewBindMacro( - ast, + mutableAst = + AST_MUTATOR.replaceSubtreeWithNewBindMacro( + mutableAst, variableName, - CelExpr.ofConstantExpr(0, CelConstant.ofValue(3L)), + CelMutableExpr.ofConstant(CelConstant.ofValue(3L)), resultExpr, - 2); // Replace + + 2, + true); // Replace + String nestedVariableName = "@r1"; // Construct a new result expression of the form @r0 + @r0 + @r1 + @r1 resultExpr = - CelExpr.newBuilder() - .setCall( - CelCall.newBuilder() - .setFunction(Operator.ADD.getFunction()) - .addArgs( - CelExpr.newBuilder() - .setCall( - CelCall.newBuilder() - .setFunction(Operator.ADD.getFunction()) - .addArgs( - CelExpr.newBuilder() - .setCall( - CelCall.newBuilder() - .setFunction(Operator.ADD.getFunction()) - .addArgs( - CelExpr.ofIdentExpr(0, variableName), - CelExpr.ofIdentExpr(0, variableName)) - .build()) - .build(), - CelExpr.ofIdentExpr(0, nestedVariableName)) - .build()) - .build(), - CelExpr.ofIdentExpr(0, nestedVariableName)) - .build()) - .build(); + CelMutableExpr.ofCall( + CelMutableCall.create( + Operator.ADD.getFunction(), + CelMutableExpr.ofCall( + CelMutableCall.create( + Operator.ADD.getFunction(), + CelMutableExpr.ofCall( + CelMutableCall.create( + Operator.ADD.getFunction(), + CelMutableExpr.ofIdent(variableName), + CelMutableExpr.ofIdent(variableName))), + CelMutableExpr.ofIdent(nestedVariableName))), + CelMutableExpr.ofIdent(nestedVariableName))); + // Find the call node (_+_) in the comprehension's result long exprIdToReplace = - CelNavigableAst.fromAst(mutatedAst) - .getRoot() + CelNavigableMutableExpr.fromExpr(mutableAst.expr()) .children() .filter( node -> @@ -344,14 +368,16 @@ public void replaceSubtreeWithNewBindMacro_nestedBindMacro_replaceComprehensionR .expr() .id(); // This should produce cel.bind(@r1, 1, cel.bind(@r0, 3, @r0 + @r0 + @r1 + @r1)) - mutatedAst = - MUTABLE_AST.replaceSubtreeWithNewBindMacro( - mutatedAst, + mutableAst = + AST_MUTATOR.replaceSubtreeWithNewBindMacro( + mutableAst, nestedVariableName, - CelExpr.ofConstantExpr(0, CelConstant.ofValue(1L)), + CelMutableExpr.ofConstant(CelConstant.ofValue(1L)), resultExpr, - exprIdToReplace); // Replace + + exprIdToReplace, + true); // Replace + + CelAbstractSyntaxTree mutatedAst = mutableAst.toParsedAst(); assertThat(mutatedAst.getSource().getMacroCalls()).hasSize(2); assertThat(CEL.createProgram(CEL.check(mutatedAst).getAst()).eval()).isEqualTo(8); assertThat(CEL_UNPARSER.unparse(mutatedAst)) @@ -363,62 +389,56 @@ public void replaceSubtreeWithNewBindMacro_nestedBindMacro_replaceComprehensionR public void replaceSubtreeWithNewBindMacro_replaceRootWithNestedBindMacro() throws Exception { // Arrange CelAbstractSyntaxTree ast = CEL.compile("1 + 1 + 3 + 3").getAst(); + CelMutableAst mutableAst = CelMutableAst.fromCelAst(ast); String variableName = "@r0"; - CelExpr resultExpr = - CelExpr.newBuilder() - .setCall( - CelCall.newBuilder() - .setFunction(Operator.ADD.getFunction()) - .addArgs( - CelExpr.ofIdentExpr(0, variableName), CelExpr.ofIdentExpr(0, variableName)) - .build()) - .build(); + CelMutableExpr resultExpr = + CelMutableExpr.ofCall( + CelMutableCall.create( + Operator.ADD.getFunction(), + CelMutableExpr.ofIdent(variableName), + CelMutableExpr.ofIdent(variableName))); // Act // Perform the initial replacement. (1 + 1 + 3 + 3) -> cel.bind(@r0, 1, @r0 + @r0) + 3 + 3 - CelAbstractSyntaxTree mutatedAst = - MUTABLE_AST.replaceSubtreeWithNewBindMacro( - ast, + mutableAst = + AST_MUTATOR.replaceSubtreeWithNewBindMacro( + mutableAst, variableName, - CelExpr.ofConstantExpr(0, CelConstant.ofValue(1L)), + CelMutableExpr.ofConstant(CelConstant.ofValue(1L)), resultExpr, - 2); // Replace + + 2, + true); // Replace + // Construct a new result expression of the form: // cel.bind(@r1, 3, cel.bind(@r0, 1, @r0 + @r0) + @r1 + @r1) String nestedVariableName = "@r1"; - CelExpr bindMacro = - CelNavigableAst.fromAst(mutatedAst) - .getRoot() + CelMutableExpr bindMacro = + CelNavigableMutableExpr.fromExpr(mutableAst.expr()) .descendants() .filter(node -> node.getKind().equals(Kind.COMPREHENSION)) .findAny() .get() .expr(); resultExpr = - CelExpr.newBuilder() - .setCall( - CelCall.newBuilder() - .setFunction(Operator.ADD.getFunction()) - .addArgs( - CelExpr.newBuilder() - .setCall( - CelCall.newBuilder() - .setFunction(Operator.ADD.getFunction()) - .addArgs(bindMacro, CelExpr.ofIdentExpr(0, nestedVariableName)) - .build()) - .build(), - CelExpr.ofIdentExpr(0, nestedVariableName)) - .build()) - .build(); + CelMutableExpr.ofCall( + CelMutableCall.create( + Operator.ADD.getFunction(), + CelMutableExpr.ofCall( + CelMutableCall.create( + Operator.ADD.getFunction(), + bindMacro, + CelMutableExpr.ofIdent(nestedVariableName))), + CelMutableExpr.ofIdent(nestedVariableName))); // Replace the root with the new result and a bind macro inserted - mutatedAst = - MUTABLE_AST.replaceSubtreeWithNewBindMacro( - mutatedAst, + mutableAst = + AST_MUTATOR.replaceSubtreeWithNewBindMacro( + mutableAst, nestedVariableName, - CelExpr.ofConstantExpr(0, CelConstant.ofValue(3L)), + CelMutableExpr.ofConstant(CelConstant.ofValue(3L)), resultExpr, - CelNavigableAst.fromAst(mutatedAst).getRoot().id()); + mutableAst.expr().id(), + true); + CelAbstractSyntaxTree mutatedAst = mutableAst.toParsedAst(); assertThat(mutatedAst.getSource().getMacroCalls()).hasSize(2); assertThat(CEL.createProgram(CEL.check(mutatedAst).getAst()).eval()).isEqualTo(8); assertThat(CEL_UNPARSER.unparse(mutatedAst)) @@ -431,10 +451,11 @@ public void replaceSubtree_macroReplacedWithConstExpr_macroCallCleared() throws CelAbstractSyntaxTree ast = CEL.compile("[1].exists(x, x > 0) && [2].exists(x, x > 0)").getAst(); CelAbstractSyntaxTree ast2 = CEL.compile("1").getAst(); + CelMutableAst mutableAst = CelMutableAst.fromCelAst(ast); + CelMutableAst mutableAst2 = CelMutableAst.fromCelAst(ast2); CelAbstractSyntaxTree mutatedAst = - MUTABLE_AST.replaceSubtreeWithNewAst( - ast, ast2, CelNavigableAst.fromAst(ast).getRoot().id()); + AST_MUTATOR.replaceSubtree(mutableAst, mutableAst2, mutableAst.expr().id()).toParsedAst(); assertThat(mutatedAst.getSource().getMacroCalls()).isEmpty(); assertThat(CEL_UNPARSER.unparse(mutatedAst)).isEqualTo("1"); @@ -461,19 +482,23 @@ public void replaceSubtree_replaceExtraneousListCreatedByMacro_unparseSuccess() // } // } CelAbstractSyntaxTree ast = CEL.compile("[1].map(x, 1)").getAst(); + CelMutableAst mutableAst = CelMutableAst.fromCelAst(ast); + CelMutableAst mutableAst2 = CelMutableAst.fromCelAst(ast); // These two mutation are equivalent. CelAbstractSyntaxTree mutatedAstWithList = - MUTABLE_AST.replaceSubtree( - ast, - CelExpr.ofCreateListExpr( - 0, - ImmutableList.of(CelExpr.newBuilder().setConstant(CelConstant.ofValue(2L)).build()), - ImmutableList.of()), - 9L); + AST_MUTATOR + .replaceSubtree( + mutableAst, + CelMutableExpr.ofCreateList( + CelMutableCreateList.create( + CelMutableExpr.ofConstant(CelConstant.ofValue(2L)))), + 9L) + .toParsedAst(); CelAbstractSyntaxTree mutatedAstWithConstant = - MUTABLE_AST.replaceSubtree( - ast, CelExpr.newBuilder().setConstant(CelConstant.ofValue(2L)).build(), 5L); + AST_MUTATOR + .replaceSubtree(mutableAst2, CelMutableExpr.ofConstant(CelConstant.ofValue(2L)), 5L) + .toParsedAst(); assertThat(CEL_UNPARSER.unparse(mutatedAstWithList)).isEqualTo("[1].map(x, 2)"); assertThat(CEL_UNPARSER.unparse(mutatedAstWithConstant)).isEqualTo("[1].map(x, 2)"); @@ -488,12 +513,13 @@ public void globalCallExpr_replaceRoot() throws Exception { // + [2] x [5] // 1 [1] 2 [3] CelAbstractSyntaxTree ast = CEL.compile("1 + 2 + x").getAst(); + CelMutableAst mutableAst = CelMutableAst.fromCelAst(ast); + CelMutableExpr newExpr = CelMutableExpr.ofConstant(CelConstant.ofValue(10)); - CelAbstractSyntaxTree replacedAst = - MUTABLE_AST.replaceSubtree( - ast, CelExpr.newBuilder().setConstant(CelConstant.ofValue(10)).build(), 4); + CelMutableAst result = AST_MUTATOR.replaceSubtree(mutableAst, newExpr, mutableAst.expr().id()); - assertThat(replacedAst.getExpr()).isEqualTo(CelExpr.ofConstantExpr(7, CelConstant.ofValue(10))); + assertThat(result.toParsedAst().getExpr()) + .isEqualTo(CelExpr.ofConstantExpr(7, CelConstant.ofValue(10))); } @Test @@ -503,12 +529,12 @@ public void globalCallExpr_replaceLeaf() throws Exception { // + [2] x [5] // 1 [1] 2 [3] CelAbstractSyntaxTree ast = CEL.compile("1 + 2 + x").getAst(); + CelMutableAst mutableAst = CelMutableAst.fromCelAst(ast); + CelMutableExpr newExpr = CelMutableExpr.ofConstant(CelConstant.ofValue(10)); - CelAbstractSyntaxTree replacedAst = - MUTABLE_AST.replaceSubtree( - ast, CelExpr.newBuilder().setConstant(CelConstant.ofValue(10)).build(), 1); + CelMutableAst result = AST_MUTATOR.replaceSubtree(mutableAst, newExpr, 1); - assertThat(CEL_UNPARSER.unparse(replacedAst)).isEqualTo("10 + 2 + x"); + assertThat(CEL_UNPARSER.unparse(result.toParsedAst())).isEqualTo("10 + 2 + x"); } @Test @@ -518,12 +544,12 @@ public void globalCallExpr_replaceMiddleBranch() throws Exception { // + [2] x [5] // 1 [1] 2 [3] CelAbstractSyntaxTree ast = CEL.compile("1 + 2 + x").getAst(); + CelMutableAst mutableAst = CelMutableAst.fromCelAst(ast); + CelMutableExpr newExpr = CelMutableExpr.ofConstant(CelConstant.ofValue(10)); - CelAbstractSyntaxTree replacedAst = - MUTABLE_AST.replaceSubtree( - ast, CelExpr.newBuilder().setConstant(CelConstant.ofValue(10)).build(), 2); + CelMutableAst result = AST_MUTATOR.replaceSubtree(mutableAst, newExpr, 2); - assertThat(CEL_UNPARSER.unparse(replacedAst)).isEqualTo("10 + x"); + assertThat(CEL_UNPARSER.unparse(result.toParsedAst())).isEqualTo("10 + x"); } @Test @@ -534,10 +560,12 @@ public void globalCallExpr_replaceMiddleBranch_withCallExpr() throws Exception { // 1 [1] 2 [3] CelAbstractSyntaxTree ast = CEL.compile("1 + 2 + x").getAst(); CelAbstractSyntaxTree ast2 = CEL.compile("4 + 5 + 6").getAst(); + CelMutableAst mutableAst = CelMutableAst.fromCelAst(ast); + CelMutableExpr newExpr = CelMutableExprConverter.fromCelExpr(ast2.getExpr()); - CelAbstractSyntaxTree replacedAst = MUTABLE_AST.replaceSubtree(ast, ast2.getExpr(), 2); + CelMutableAst result = AST_MUTATOR.replaceSubtree(mutableAst, newExpr, 2); - assertThat(CEL_UNPARSER.unparse(replacedAst)).isEqualTo("4 + 5 + 6 + x"); + assertThat(CEL_UNPARSER.unparse(result.toParsedAst())).isEqualTo("4 + 5 + 6 + x"); } @Test @@ -555,12 +583,12 @@ public void memberCallExpr_replaceLeafTarget() throws Exception { "func_overload", SimpleType.INT, SimpleType.INT, SimpleType.INT))) .build(); CelAbstractSyntaxTree ast = cel.compile("10.func(4.func(5))").getAst(); + CelMutableAst mutableAst = CelMutableAst.fromCelAst(ast); + CelMutableExpr newExpr = CelMutableExpr.ofConstant(CelConstant.ofValue(20)); - CelAbstractSyntaxTree replacedAst = - MUTABLE_AST.replaceSubtree( - ast, CelExpr.newBuilder().setConstant(CelConstant.ofValue(20)).build(), 3); + CelMutableAst result = AST_MUTATOR.replaceSubtree(mutableAst, newExpr, 3); - assertThat(CEL_UNPARSER.unparse(replacedAst)).isEqualTo("10.func(20.func(5))"); + assertThat(CEL_UNPARSER.unparse(result.toParsedAst())).isEqualTo("10.func(20.func(5))"); } @Test @@ -578,12 +606,12 @@ public void memberCallExpr_replaceLeafArgument() throws Exception { "func_overload", SimpleType.INT, SimpleType.INT, SimpleType.INT))) .build(); CelAbstractSyntaxTree ast = cel.compile("10.func(4.func(5))").getAst(); + CelMutableAst mutableAst = CelMutableAst.fromCelAst(ast); + CelMutableExpr newExpr = CelMutableExpr.ofConstant(CelConstant.ofValue(20)); - CelAbstractSyntaxTree replacedAst = - MUTABLE_AST.replaceSubtree( - ast, CelExpr.newBuilder().setConstant(CelConstant.ofValue(20)).build(), 5); + CelMutableAst result = AST_MUTATOR.replaceSubtree(mutableAst, newExpr, 5); - assertThat(CEL_UNPARSER.unparse(replacedAst)).isEqualTo("10.func(4.func(20))"); + assertThat(CEL_UNPARSER.unparse(result.toParsedAst())).isEqualTo("10.func(4.func(20))"); } @Test @@ -601,12 +629,12 @@ public void memberCallExpr_replaceMiddleBranchTarget() throws Exception { "func_overload", SimpleType.INT, SimpleType.INT, SimpleType.INT))) .build(); CelAbstractSyntaxTree ast = cel.compile("10.func(4.func(5))").getAst(); + CelMutableAst mutableAst = CelMutableAst.fromCelAst(ast); + CelMutableExpr newExpr = CelMutableExpr.ofConstant(CelConstant.ofValue(20)); - CelAbstractSyntaxTree replacedAst = - MUTABLE_AST.replaceSubtree( - ast, CelExpr.newBuilder().setConstant(CelConstant.ofValue(20)).build(), 1); + CelMutableAst result = AST_MUTATOR.replaceSubtree(mutableAst, newExpr, 1); - assertThat(CEL_UNPARSER.unparse(replacedAst)).isEqualTo("20.func(4.func(5))"); + assertThat(CEL_UNPARSER.unparse(result.toParsedAst())).isEqualTo("20.func(4.func(5))"); } @Test @@ -624,12 +652,12 @@ public void memberCallExpr_replaceMiddleBranchArgument() throws Exception { "func_overload", SimpleType.INT, SimpleType.INT, SimpleType.INT))) .build(); CelAbstractSyntaxTree ast = cel.compile("10.func(4.func(5))").getAst(); + CelMutableAst mutableAst = CelMutableAst.fromCelAst(ast); + CelMutableExpr newExpr = CelMutableExpr.ofConstant(CelConstant.ofValue(20)); - CelAbstractSyntaxTree replacedAst = - MUTABLE_AST.replaceSubtree( - ast, CelExpr.newBuilder().setConstant(CelConstant.ofValue(20)).build(), 4); + CelMutableAst result = AST_MUTATOR.replaceSubtree(mutableAst, newExpr, 4); - assertThat(CEL_UNPARSER.unparse(replacedAst)).isEqualTo("10.func(20)"); + assertThat(CEL_UNPARSER.unparse(result.toParsedAst())).isEqualTo("10.func(20)"); } @Test @@ -639,23 +667,14 @@ public void select_replaceField() throws Exception { // 5 [1] select [4] // msg [3] CelAbstractSyntaxTree ast = CEL.compile("5 + msg.single_int64").getAst(); + CelMutableAst mutableAst = CelMutableAst.fromCelAst(ast); + CelMutableExpr newExpr = + CelMutableExpr.ofSelect( + CelMutableSelect.create(CelMutableExpr.ofIdent("test"), "single_sint32")); - CelAbstractSyntaxTree replacedAst = - MUTABLE_AST.replaceSubtree( - ast, - CelExpr.newBuilder() - .setSelect( - CelSelect.newBuilder() - .setField("single_sint32") - .setOperand( - CelExpr.newBuilder() - .setIdent(CelIdent.newBuilder().setName("test").build()) - .build()) - .build()) - .build(), - 4); + CelMutableAst result = AST_MUTATOR.replaceSubtree(mutableAst, newExpr, 4); - assertThat(CEL_UNPARSER.unparse(replacedAst)).isEqualTo("5 + test.single_sint32"); + assertThat(CEL_UNPARSER.unparse(result.toParsedAst())).isEqualTo("5 + test.single_sint32"); } @Test @@ -665,14 +684,12 @@ public void select_replaceOperand() throws Exception { // 5 [1] select [4] // msg [3] CelAbstractSyntaxTree ast = CEL.compile("5 + msg.single_int64").getAst(); + CelMutableAst mutableAst = CelMutableAst.fromCelAst(ast); + CelMutableExpr newExpr = CelMutableExpr.ofIdent("test"); - CelAbstractSyntaxTree replacedAst = - MUTABLE_AST.replaceSubtree( - ast, - CelExpr.newBuilder().setIdent(CelIdent.newBuilder().setName("test").build()).build(), - 3); + CelMutableAst result = AST_MUTATOR.replaceSubtree(mutableAst, newExpr, 3); - assertThat(CEL_UNPARSER.unparse(replacedAst)).isEqualTo("5 + test.single_int64"); + assertThat(CEL_UNPARSER.unparse(result.toParsedAst())).isEqualTo("5 + test.single_int64"); } @Test @@ -681,12 +698,12 @@ public void list_replaceElement() throws Exception { // list [1] // 2 [2] 3 [3] 4 [4] CelAbstractSyntaxTree ast = CEL.compile("[2, 3, 4]").getAst(); + CelMutableAst mutableAst = CelMutableAst.fromCelAst(ast); + CelMutableExpr newExpr = CelMutableExpr.ofConstant(CelConstant.ofValue(5)); - CelAbstractSyntaxTree replacedAst = - MUTABLE_AST.replaceSubtree( - ast, CelExpr.newBuilder().setConstant(CelConstant.ofValue(5)).build(), 4); + CelMutableAst result = AST_MUTATOR.replaceSubtree(mutableAst, newExpr, 4); - assertThat(CEL_UNPARSER.unparse(replacedAst)).isEqualTo("[2, 3, 5]"); + assertThat(CEL_UNPARSER.unparse(result.toParsedAst())).isEqualTo("[2, 3, 5]"); } @Test @@ -696,12 +713,13 @@ public void createStruct_replaceValue() throws Exception { // single_int64 [2] // 2 [3] CelAbstractSyntaxTree ast = CEL.compile("TestAllTypes{single_int64: 2}").getAst(); + CelMutableAst mutableAst = CelMutableAst.fromCelAst(ast); + CelMutableExpr newExpr = CelMutableExpr.ofConstant(CelConstant.ofValue(5)); - CelAbstractSyntaxTree replacedAst = - MUTABLE_AST.replaceSubtree( - ast, CelExpr.newBuilder().setConstant(CelConstant.ofValue(5)).build(), 3); + CelMutableAst result = AST_MUTATOR.replaceSubtree(mutableAst, newExpr, 3); - assertThat(CEL_UNPARSER.unparse(replacedAst)).isEqualTo("TestAllTypes{single_int64: 5}"); + assertThat(CEL_UNPARSER.unparse(result.toParsedAst())) + .isEqualTo("TestAllTypes{single_int64: 5}"); } @Test @@ -711,12 +729,12 @@ public void createMap_replaceKey() throws Exception { // map_entry [2] // 'a' [3] : 1 [4] CelAbstractSyntaxTree ast = CEL.compile("{'a': 1}").getAst(); + CelMutableAst mutableAst = CelMutableAst.fromCelAst(ast); + CelMutableExpr newExpr = CelMutableExpr.ofConstant(CelConstant.ofValue(5)); - CelAbstractSyntaxTree replacedAst = - MUTABLE_AST.replaceSubtree( - ast, CelExpr.newBuilder().setConstant(CelConstant.ofValue(5)).build(), 3); + CelMutableAst result = AST_MUTATOR.replaceSubtree(mutableAst, newExpr, 3); - assertThat(CEL_UNPARSER.unparse(replacedAst)).isEqualTo("{5: 1}"); + assertThat(CEL_UNPARSER.unparse(result.toParsedAst())).isEqualTo("{5: 1}"); } @Test @@ -726,34 +744,36 @@ public void createMap_replaceValue() throws Exception { // map_entry [2] // 'a' [3] : 1 [4] CelAbstractSyntaxTree ast = CEL.compile("{'a': 1}").getAst(); + CelMutableAst mutableAst = CelMutableAst.fromCelAst(ast); + CelMutableExpr newExpr = CelMutableExpr.ofConstant(CelConstant.ofValue(5)); - CelAbstractSyntaxTree replacedAst = - MUTABLE_AST.replaceSubtree( - ast, CelExpr.newBuilder().setConstant(CelConstant.ofValue(5)).build(), 4); + CelMutableAst result = AST_MUTATOR.replaceSubtree(mutableAst, newExpr, 4); - assertThat(CEL_UNPARSER.unparse(replacedAst)).isEqualTo("{\"a\": 5}"); + assertThat(CEL_UNPARSER.unparse(result.toParsedAst())).isEqualTo("{\"a\": 5}"); } @Test public void comprehension_replaceIterRange() throws Exception { CelAbstractSyntaxTree ast = CEL.compile("[true].exists(i, i)").getAst(); + CelMutableAst mutableAst = CelMutableAst.fromCelAst(ast); + CelMutableExpr newExpr = CelMutableExpr.ofConstant(CelConstant.ofValue(false)); CelAbstractSyntaxTree replacedAst = - MUTABLE_AST.replaceSubtree( - ast, CelExpr.newBuilder().setConstant(CelConstant.ofValue(false)).build(), 2); + AST_MUTATOR.replaceSubtree(mutableAst, newExpr, 2).toParsedAst(); assertThat(CEL_UNPARSER.unparse(replacedAst)).isEqualTo("[false].exists(i, i)"); assertThat(CEL.createProgram(CEL.check(replacedAst).getAst()).eval()).isEqualTo(false); - assertConsistentMacroCalls(ast); + assertConsistentMacroCalls(replacedAst); } @Test public void comprehension_replaceAccuInit() throws Exception { CelAbstractSyntaxTree ast = CEL.compile("[false].exists(i, i)").getAst(); + CelMutableAst mutableAst = CelMutableAst.fromCelAst(ast); + CelMutableExpr newExpr = CelMutableExpr.ofConstant(CelConstant.ofValue(true)); CelAbstractSyntaxTree replacedAst = - MUTABLE_AST.replaceSubtree( - ast, CelExpr.newBuilder().setConstant(CelConstant.ofValue(true)).build(), 6); + AST_MUTATOR.replaceSubtree(mutableAst, newExpr, 6).toParsedAst(); assertThat(CEL_UNPARSER.unparse(replacedAst)).isEqualTo("[false].exists(i, i)"); assertThat(CEL.createProgram(CEL.check(replacedAst).getAst()).eval()).isEqualTo(true); @@ -766,12 +786,11 @@ public void comprehension_replaceAccuInit() throws Exception { @Test public void comprehension_replaceLoopStep() throws Exception { CelAbstractSyntaxTree ast = CEL.compile("[false].exists(i, i)").getAst(); + CelMutableAst mutableAst = CelMutableAst.fromCelAst(ast); + CelMutableExpr newExpr = CelMutableExpr.ofIdent("test"); CelAbstractSyntaxTree replacedAst = - MUTABLE_AST.replaceSubtree( - ast, - CelExpr.newBuilder().setIdent(CelIdent.newBuilder().setName("test").build()).build(), - 5); + AST_MUTATOR.replaceSubtree(mutableAst, newExpr, 5).toParsedAst(); assertThat(CEL_UNPARSER.unparse(replacedAst)).isEqualTo("[false].exists(i, test)"); assertConsistentMacroCalls(ast); @@ -782,7 +801,7 @@ public void mangleComprehensionVariable_singleMacro() throws Exception { CelAbstractSyntaxTree ast = CEL.compile("[false].exists(i, i)").getAst(); CelAbstractSyntaxTree mangledAst = - MUTABLE_AST.mangleComprehensionIdentifierNames(ast, "@c", "@x").ast(); + AST_MUTATOR.mangleComprehensionIdentifierNames(ast, "@c", "@x").mutableAst().toParsedAst(); assertThat(mangledAst.getExpr().toString()) .isEqualTo( @@ -838,12 +857,28 @@ public void mangleComprehensionVariable_singleMacro() throws Exception { assertConsistentMacroCalls(ast); } + @Test + public void mangleComprehensionVariable_macroSourceDisabled_macroCallMapIsEmpty() + throws Exception { + Cel cel = + CelFactory.standardCelBuilder() + .setStandardMacros(CelStandardMacro.STANDARD_MACROS) + .setOptions(CelOptions.current().populateMacroCalls(false).build()) + .build(); + CelAbstractSyntaxTree ast = cel.compile("[false].exists(i, i)").getAst(); + + CelAbstractSyntaxTree mangledAst = + AST_MUTATOR.mangleComprehensionIdentifierNames(ast, "@c", "@x").mutableAst().toParsedAst(); + + assertThat(mangledAst.getSource().getMacroCalls()).isEmpty(); + } + @Test public void mangleComprehensionVariable_nestedMacroWithShadowedVariables() throws Exception { CelAbstractSyntaxTree ast = CEL.compile("[x].exists(x, [x].exists(x, x == 1))").getAst(); CelAbstractSyntaxTree mangledAst = - MUTABLE_AST.mangleComprehensionIdentifierNames(ast, "@c", "@x").ast(); + AST_MUTATOR.mangleComprehensionIdentifierNames(ast, "@c", "@x").mutableAst().toParsedAst(); assertThat(mangledAst.getExpr().toString()) .isEqualTo( @@ -960,7 +995,7 @@ public void mangleComprehensionVariable_hasMacro_noOp() throws Exception { CelAbstractSyntaxTree ast = CEL.compile("has(msg.single_int64)").getAst(); CelAbstractSyntaxTree mangledAst = - MUTABLE_AST.mangleComprehensionIdentifierNames(ast, "@c", "@x").ast(); + AST_MUTATOR.mangleComprehensionIdentifierNames(ast, "@c", "@x").mutableAst().toParsedAst(); assertThat(CEL_UNPARSER.unparse(mangledAst)).isEqualTo("has(msg.single_int64)"); assertThat( @@ -973,6 +1008,7 @@ public void mangleComprehensionVariable_hasMacro_noOp() throws Exception { @Test public void replaceSubtree_iterationLimitReached_throws() throws Exception { CelAbstractSyntaxTree ast = CEL.compile("true && false").getAst(); + CelMutableAst mutableAst = CelMutableAst.fromCelAst(ast); AstMutator astMutator = AstMutator.newInstance(1); IllegalStateException e = @@ -980,7 +1016,7 @@ public void replaceSubtree_iterationLimitReached_throws() throws Exception { IllegalStateException.class, () -> astMutator.replaceSubtree( - ast, CelExpr.ofConstantExpr(0, CelConstant.ofValue(false)), 1)); + mutableAst, CelMutableExpr.ofConstant(CelConstant.ofValue(false)), 1)); assertThat(e).hasMessageThat().isEqualTo("Max iteration count reached."); } diff --git a/optimizer/src/test/java/dev/cel/optimizer/BUILD.bazel b/optimizer/src/test/java/dev/cel/optimizer/BUILD.bazel index 88e244154..4d751e4f9 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/BUILD.bazel +++ b/optimizer/src/test/java/dev/cel/optimizer/BUILD.bazel @@ -13,7 +13,9 @@ java_library( "//common:compiler_common", "//common:options", "//common/ast", + "//common/ast:mutable_ast", "//common/navigation", + "//common/navigation:mutable_navigation", "//common/resources/testdata/proto3:test_all_types_java_proto", "//common/types", "//compiler", From 8684d8f62da4d02d05e87f905300618e29559838 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Fri, 19 Apr 2024 09:28:26 -0700 Subject: [PATCH 092/486] Change ConstantFoldingOptimizer to leverage mutable exprs Includes a bugfix to prune optional.none in a nested list properly. PiperOrigin-RevId: 626387705 --- .../dev/cel/optimizer/optimizers/BUILD.bazel | 3 +- .../optimizers/ConstantFoldingOptimizer.java | 382 +++++++++--------- .../ConstantFoldingOptimizerTest.java | 1 + ...old_before_subexpression_unparsed.baseline | 22 +- 4 files changed, 195 insertions(+), 213 deletions(-) diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel b/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel index 1dbd78f3b..91da59716 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel @@ -16,11 +16,12 @@ java_library( deps = [ "//:auto_value", "//bundle:cel", - "//common", "//common:compiler_common", "//common/ast", "//common/ast:expr_util", + "//common/ast:mutable_ast", "//common/navigation", + "//common/navigation:mutable_navigation", "//extensions:optional_library", "//optimizer:ast_optimizer", "//optimizer:mutable_ast", diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java b/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java index 83100d183..4c9492a09 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java @@ -19,30 +19,33 @@ import com.google.auto.value.AutoValue; import com.google.common.collect.ImmutableList; import dev.cel.bundle.Cel; -import dev.cel.common.CelAbstractSyntaxTree; import dev.cel.common.CelValidationException; import dev.cel.common.ast.CelConstant; -import dev.cel.common.ast.CelExpr; -import dev.cel.common.ast.CelExpr.CelCall; -import dev.cel.common.ast.CelExpr.CelCreateList; -import dev.cel.common.ast.CelExpr.CelCreateMap; -import dev.cel.common.ast.CelExpr.CelCreateStruct; import dev.cel.common.ast.CelExpr.ExprKind.Kind; import dev.cel.common.ast.CelExprUtil; +import dev.cel.common.ast.CelMutableAst; +import dev.cel.common.ast.CelMutableExpr; +import dev.cel.common.ast.CelMutableExpr.CelMutableCall; +import dev.cel.common.ast.CelMutableExpr.CelMutableCreateList; +import dev.cel.common.ast.CelMutableExpr.CelMutableCreateMap; +import dev.cel.common.ast.CelMutableExpr.CelMutableCreateStruct; +import dev.cel.common.ast.CelMutableExprConverter; import dev.cel.common.navigation.CelNavigableAst; -import dev.cel.common.navigation.CelNavigableExpr; +import dev.cel.common.navigation.CelNavigableMutableAst; +import dev.cel.common.navigation.CelNavigableMutableExpr; import dev.cel.extensions.CelOptionalLibrary.Function; import dev.cel.optimizer.AstMutator; import dev.cel.optimizer.CelAstOptimizer; import dev.cel.optimizer.CelOptimizationException; import dev.cel.parser.Operator; import dev.cel.runtime.CelEvaluationException; +import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Optional; -import java.util.Set; /** * Performs optimization for inlining constant scalar and aggregate literal values within function @@ -66,65 +69,65 @@ public static ConstantFoldingOptimizer newInstance( return new ConstantFoldingOptimizer(constantFoldingOptions); } - // Use optional.of and optional.none as sentinel function names for folding optional calls. - // TODO: Leverage CelValue representation of Optionals instead when available. - private static final CelExpr OPTIONAL_NONE_EXPR = - CelExpr.ofCallExpr( - 0, Optional.empty(), Function.OPTIONAL_NONE.getFunction(), ImmutableList.of()); - private final ConstantFoldingOptions constantFoldingOptions; private final AstMutator astMutator; + // Use optional.of and optional.none as sentinel function names for folding optional calls. + // TODO: Leverage CelValue representation of Optionals instead when available. + private static CelMutableExpr newOptionalNoneExpr() { + return CelMutableExpr.ofCall(CelMutableCall.create(Function.OPTIONAL_NONE.getFunction())); + } + @Override - public OptimizationResult optimize(CelNavigableAst navigableAst, Cel cel) - throws CelOptimizationException { - Set visitedExprs = new HashSet<>(); + public OptimizationResult optimize(CelNavigableAst ast, Cel cel) throws CelOptimizationException { + CelMutableAst mutableAst = CelMutableAst.fromCelAst(ast.getAst()); int iterCount = 0; - while (true) { - iterCount++; + boolean continueFolding = true; + while (continueFolding) { if (iterCount >= constantFoldingOptions.maxIterationLimit()) { throw new IllegalStateException("Max iteration count reached."); } - Optional foldableExpr = - navigableAst + iterCount++; + continueFolding = false; + + ImmutableList foldableExprs = + CelNavigableMutableAst.fromAst(mutableAst) .getRoot() .allNodes() .filter(ConstantFoldingOptimizer::canFold) - .filter(node -> !visitedExprs.contains(node.expr())) - .findAny(); - if (!foldableExpr.isPresent()) { - break; - } - visitedExprs.add(foldableExpr.get().expr()); - - Optional mutatedAst; - // Attempt to prune if it is a non-strict call - mutatedAst = maybePruneBranches(navigableAst.getAst(), foldableExpr.get().expr()); - if (!mutatedAst.isPresent()) { - // Evaluate the call then fold - mutatedAst = maybeFold(cel, navigableAst.getAst(), foldableExpr.get()); - } + .collect(toImmutableList()); + for (CelNavigableMutableExpr foldableExpr : foldableExprs) { + iterCount++; + + Optional mutatedResult; + // Attempt to prune if it is a non-strict call + mutatedResult = maybePruneBranches(mutableAst, foldableExpr.expr()); + if (!mutatedResult.isPresent()) { + // Evaluate the call then fold + mutatedResult = maybeFold(cel, mutableAst, foldableExpr); + } - if (!mutatedAst.isPresent()) { - // Skip this expr. It's neither prune-able nor foldable. - continue; - } + if (!mutatedResult.isPresent()) { + // Skip this expr. It's neither prune-able nor foldable. + continue; + } - visitedExprs.clear(); - navigableAst = CelNavigableAst.fromAst(mutatedAst.get()); + continueFolding = true; + mutableAst = mutatedResult.get(); + } } // If the output is a list, map, or struct which contains optional entries, then prune it // to make sure that the optionals, if resolved, do not surface in the output literal. - CelAbstractSyntaxTree newAst = pruneOptionalElements(navigableAst); - return OptimizationResult.create(astMutator.renumberIdsConsecutively(newAst)); + mutableAst = pruneOptionalElements(mutableAst); + return OptimizationResult.create(astMutator.renumberIdsConsecutively(mutableAst).toParsedAst()); } - private static boolean canFold(CelNavigableExpr navigableExpr) { + private static boolean canFold(CelNavigableMutableExpr navigableExpr) { switch (navigableExpr.getKind()) { case CALL: - CelCall celCall = navigableExpr.expr().call(); - String functionName = celCall.function(); + CelMutableCall mutableCall = navigableExpr.expr().call(); + String functionName = mutableCall.function(); // These are already folded or do not need to be folded. if (functionName.equals(Function.OPTIONAL_OF.getFunction()) @@ -137,15 +140,15 @@ private static boolean canFold(CelNavigableExpr navigableExpr) { || functionName.equals(Operator.LOGICAL_OR.getFunction())) { // If any element is a constant, this could be a foldable expr (e.g: x && false -> x) - return celCall.args().stream() - .anyMatch(node -> node.exprKind().getKind().equals(Kind.CONSTANT)); + return mutableCall.args().stream().anyMatch(node -> node.getKind().equals(Kind.CONSTANT)); } if (functionName.equals(Operator.CONDITIONAL.getFunction())) { - CelExpr cond = celCall.args().get(0); + CelMutableExpr cond = mutableCall.args().get(0); // A ternary with a constant condition is trivially foldable - return cond.constantOrDefault().getKind().equals(CelConstant.Kind.BOOLEAN_VALUE); + return cond.getKind().equals(Kind.CONSTANT) + && cond.constant().getKind().equals(CelConstant.Kind.BOOLEAN_VALUE); } if (functionName.equals(Operator.IN.getFunction())) { @@ -156,7 +159,7 @@ private static boolean canFold(CelNavigableExpr navigableExpr) { // list, map), then its arguments must be a constant. return areChildrenArgConstant(navigableExpr); case SELECT: - CelNavigableExpr operand = navigableExpr.children().collect(onlyElement()); + CelNavigableMutableExpr operand = navigableExpr.children().collect(onlyElement()); return areChildrenArgConstant(operand); case COMPREHENSION: return !isNestedComprehension(navigableExpr); @@ -165,14 +168,14 @@ private static boolean canFold(CelNavigableExpr navigableExpr) { } } - private static boolean canFoldInOperator(CelNavigableExpr navigableExpr) { - ImmutableList allIdents = + private static boolean canFoldInOperator(CelNavigableMutableExpr navigableExpr) { + ImmutableList allIdents = navigableExpr .allNodes() .filter(node -> node.getKind().equals(Kind.IDENT)) .collect(toImmutableList()); - for (CelNavigableExpr identNode : allIdents) { - CelNavigableExpr parent = identNode.parent().orElse(null); + for (CelNavigableMutableExpr identNode : allIdents) { + CelNavigableMutableExpr parent = identNode.parent().orElse(null); while (parent != null) { if (parent.getKind().equals(Kind.COMPREHENSION)) { if (parent.expr().comprehension().accuVar().equals(identNode.expr().ident().name())) { @@ -189,7 +192,7 @@ private static boolean canFoldInOperator(CelNavigableExpr navigableExpr) { return true; } - private static boolean areChildrenArgConstant(CelNavigableExpr expr) { + private static boolean areChildrenArgConstant(CelNavigableMutableExpr expr) { if (expr.getKind().equals(Kind.CONSTANT)) { return true; } @@ -204,10 +207,10 @@ private static boolean areChildrenArgConstant(CelNavigableExpr expr) { return false; } - private static boolean isNestedComprehension(CelNavigableExpr expr) { - Optional maybeParent = expr.parent(); + private static boolean isNestedComprehension(CelNavigableMutableExpr expr) { + Optional maybeParent = expr.parent(); while (maybeParent.isPresent()) { - CelNavigableExpr parent = maybeParent.get(); + CelNavigableMutableExpr parent = maybeParent.get(); if (parent.getKind().equals(Kind.COMPREHENSION)) { return true; } @@ -217,11 +220,12 @@ private static boolean isNestedComprehension(CelNavigableExpr expr) { return false; } - private Optional maybeFold( - Cel cel, CelAbstractSyntaxTree ast, CelNavigableExpr node) throws CelOptimizationException { + private Optional maybeFold( + Cel cel, CelMutableAst mutableAst, CelNavigableMutableExpr node) + throws CelOptimizationException { Object result; try { - result = CelExprUtil.evaluateExpr(cel, node.expr()); + result = CelExprUtil.evaluateExpr(cel, CelMutableExprConverter.fromMutableExpr(node.expr())); } catch (CelValidationException | CelEvaluationException e) { throw new CelOptimizationException( "Constant folding failure. Failed to evaluate subtree due to: " + e.getMessage(), e); @@ -232,140 +236,126 @@ private Optional maybeFold( // ex2: optional.ofNonZeroValue(5) -> optional.of(5) if (result instanceof Optional) { Optional optResult = ((Optional) result); - return maybeRewriteOptional(optResult, ast, node.expr()); + return maybeRewriteOptional(optResult, mutableAst, node.expr()); } return maybeAdaptEvaluatedResult(result) - .map(celExpr -> astMutator.replaceSubtree(ast, celExpr, node.id())); + .map(celExpr -> astMutator.replaceSubtree(mutableAst, celExpr, node.id())); } - private Optional maybeAdaptEvaluatedResult(Object result) { + private Optional maybeAdaptEvaluatedResult(Object result) { if (CelConstant.isConstantValue(result)) { - return Optional.of( - CelExpr.newBuilder().setConstant(CelConstant.ofObjectValue(result)).build()); + return Optional.of(CelMutableExpr.ofConstant(CelConstant.ofObjectValue(result))); } else if (result instanceof Collection) { Collection collection = (Collection) result; - CelCreateList.Builder createListBuilder = CelCreateList.newBuilder(); + List listElements = new ArrayList<>(); for (Object evaluatedElement : collection) { - Optional adaptedExpr = maybeAdaptEvaluatedResult(evaluatedElement); - if (!adaptedExpr.isPresent()) { + CelMutableExpr adaptedExpr = maybeAdaptEvaluatedResult(evaluatedElement).orElse(null); + if (adaptedExpr == null) { return Optional.empty(); } - createListBuilder.addElements(adaptedExpr.get()); + listElements.add(adaptedExpr); } - return Optional.of(CelExpr.newBuilder().setCreateList(createListBuilder.build()).build()); + return Optional.of(CelMutableExpr.ofCreateList(CelMutableCreateList.create(listElements))); } else if (result instanceof Map) { Map map = (Map) result; - CelCreateMap.Builder createMapBuilder = CelCreateMap.newBuilder(); + List mapEntries = new ArrayList<>(); for (Entry entry : map.entrySet()) { - Optional adaptedKey = maybeAdaptEvaluatedResult(entry.getKey()); - if (!adaptedKey.isPresent()) { + CelMutableExpr adaptedKey = maybeAdaptEvaluatedResult(entry.getKey()).orElse(null); + if (adaptedKey == null) { return Optional.empty(); } - Optional adaptedValue = maybeAdaptEvaluatedResult(entry.getValue()); - if (!adaptedValue.isPresent()) { + CelMutableExpr adaptedValue = maybeAdaptEvaluatedResult(entry.getValue()).orElse(null); + if (adaptedValue == null) { return Optional.empty(); } - createMapBuilder.addEntries( - CelCreateMap.Entry.newBuilder() - .setKey(adaptedKey.get()) - .setValue(adaptedValue.get()) - .build()); + mapEntries.add(CelMutableCreateMap.Entry.create(adaptedKey, adaptedValue)); } - return Optional.of(CelExpr.newBuilder().setCreateMap(createMapBuilder.build()).build()); + return Optional.of(CelMutableExpr.ofCreateMap(CelMutableCreateMap.create(mapEntries))); } // Evaluated result cannot be folded (e.g: unknowns) return Optional.empty(); } - private Optional maybeRewriteOptional( - Optional optResult, CelAbstractSyntaxTree ast, CelExpr expr) { + private Optional maybeRewriteOptional( + Optional optResult, CelMutableAst mutableAst, CelMutableExpr expr) { if (!optResult.isPresent()) { - if (!expr.callOrDefault().function().equals(Function.OPTIONAL_NONE.getFunction())) { + if (!expr.call().function().equals(Function.OPTIONAL_NONE.getFunction())) { // An empty optional value was encountered. Rewrite the tree with optional.none call. // This is to account for other optional functions returning an empty optional value // e.g: optional.ofNonZeroValue(0) - return Optional.of(astMutator.replaceSubtree(ast, OPTIONAL_NONE_EXPR, expr.id())); + return Optional.of(astMutator.replaceSubtree(mutableAst, newOptionalNoneExpr(), expr.id())); } - } else if (!expr.callOrDefault().function().equals(Function.OPTIONAL_OF.getFunction())) { + } else if (!expr.call().function().equals(Function.OPTIONAL_OF.getFunction())) { Object unwrappedResult = optResult.get(); if (!CelConstant.isConstantValue(unwrappedResult)) { // Evaluated result is not a constant. Leave the optional as is. return Optional.empty(); } - CelExpr newOptionalOfCall = - CelExpr.newBuilder() - .setCall( - CelCall.newBuilder() - .setFunction(Function.OPTIONAL_OF.getFunction()) - .addArgs( - CelExpr.newBuilder() - .setConstant(CelConstant.ofObjectValue(unwrappedResult)) - .build()) - .build()) - .build(); - return Optional.of(astMutator.replaceSubtree(ast, newOptionalOfCall, expr.id())); + CelMutableExpr newOptionalOfCall = + CelMutableExpr.ofCall( + CelMutableCall.create( + Function.OPTIONAL_OF.getFunction(), + CelMutableExpr.ofConstant(CelConstant.ofObjectValue(unwrappedResult)))); + + return Optional.of(astMutator.replaceSubtree(mutableAst, newOptionalOfCall, expr.id())); } return Optional.empty(); } /** Inspects the non-strict calls to determine whether a branch can be removed. */ - private Optional maybePruneBranches( - CelAbstractSyntaxTree ast, CelExpr expr) { - if (!expr.exprKind().getKind().equals(Kind.CALL)) { + private Optional maybePruneBranches( + CelMutableAst mutableAst, CelMutableExpr expr) { + if (!expr.getKind().equals(Kind.CALL)) { return Optional.empty(); } - CelCall call = expr.call(); + CelMutableCall call = expr.call(); String function = call.function(); if (function.equals(Operator.LOGICAL_AND.getFunction()) || function.equals(Operator.LOGICAL_OR.getFunction())) { - return maybeShortCircuitCall(ast, expr); + return maybeShortCircuitCall(mutableAst, expr); } else if (function.equals(Operator.CONDITIONAL.getFunction())) { - CelExpr cond = call.args().get(0); - CelExpr truthy = call.args().get(1); - CelExpr falsy = call.args().get(2); - if (!cond.exprKind().getKind().equals(Kind.CONSTANT)) { + CelMutableExpr cond = call.args().get(0); + CelMutableExpr truthy = call.args().get(1); + CelMutableExpr falsy = call.args().get(2); + if (!cond.getKind().equals(Kind.CONSTANT)) { throw new IllegalStateException( - String.format( - "Expected constant condition. Got: %s instead.", cond.exprKind().getKind())); + String.format("Expected constant condition. Got: %s instead.", cond.getKind())); } - CelExpr result = cond.constant().booleanValue() ? truthy : falsy; + CelMutableExpr result = cond.constant().booleanValue() ? truthy : falsy; - return Optional.of(astMutator.replaceSubtree(ast, result, expr.id())); + return Optional.of(astMutator.replaceSubtree(mutableAst, result, expr.id())); } else if (function.equals(Operator.IN.getFunction())) { - CelExpr callArg = call.args().get(1); - if (!callArg.exprKind().getKind().equals(Kind.CREATE_LIST)) { + CelMutableExpr callArg = call.args().get(1); + if (!callArg.getKind().equals(Kind.CREATE_LIST)) { return Optional.empty(); } - CelCreateList haystack = callArg.createList(); + CelMutableCreateList haystack = callArg.createList(); if (haystack.elements().isEmpty()) { return Optional.of( astMutator.replaceSubtree( - ast, - CelExpr.newBuilder().setConstant(CelConstant.ofValue(false)).build(), - expr.id())); + mutableAst, CelMutableExpr.ofConstant(CelConstant.ofValue(false)), expr.id())); } - CelExpr needle = call.args().get(0); - if (needle.exprKind().getKind().equals(Kind.CONSTANT) - || needle.exprKind().getKind().equals(Kind.IDENT)) { + CelMutableExpr needle = call.args().get(0); + if (needle.getKind().equals(Kind.CONSTANT) || needle.getKind().equals(Kind.IDENT)) { Object needleValue = - needle.exprKind().getKind().equals(Kind.CONSTANT) ? needle.constant() : needle.ident(); - for (CelExpr elem : haystack.elements()) { - if (elem.constantOrDefault().equals(needleValue) - || elem.identOrDefault().equals(needleValue)) { + needle.getKind().equals(Kind.CONSTANT) ? needle.constant() : needle.ident(); + for (CelMutableExpr elem : haystack.elements()) { + if ((elem.getKind().equals(Kind.CONSTANT) && elem.constant().equals(needleValue)) + || (elem.getKind().equals(Kind.IDENT) && elem.ident().equals(needleValue))) { return Optional.of( astMutator.replaceSubtree( - ast, - CelExpr.newBuilder().setConstant(CelConstant.ofValue(true)).build(), + mutableAst.expr(), + CelMutableExpr.ofConstant(CelConstant.ofValue(true)), expr.id())); } } @@ -375,19 +365,19 @@ private Optional maybePruneBranches( return Optional.empty(); } - private Optional maybeShortCircuitCall( - CelAbstractSyntaxTree ast, CelExpr expr) { - CelCall call = expr.call(); + private Optional maybeShortCircuitCall( + CelMutableAst mutableAst, CelMutableExpr expr) { + CelMutableCall call = expr.call(); boolean shortCircuit = false; boolean skip = true; if (call.function().equals(Operator.LOGICAL_OR.getFunction())) { shortCircuit = true; skip = false; } - ImmutableList.Builder newArgsBuilder = new ImmutableList.Builder<>(); + ImmutableList.Builder newArgsBuilder = new ImmutableList.Builder<>(); - for (CelExpr arg : call.args()) { - if (!arg.exprKind().getKind().equals(Kind.CONSTANT)) { + for (CelMutableExpr arg : call.args()) { + if (!arg.getKind().equals(Kind.CONSTANT)) { newArgsBuilder.add(arg); continue; } @@ -396,17 +386,18 @@ private Optional maybeShortCircuitCall( } if (arg.constant().booleanValue() == shortCircuit) { - return Optional.of(astMutator.replaceSubtree(ast, arg, expr.id())); + return Optional.of(astMutator.replaceSubtree(mutableAst, arg, expr.id())); } } - ImmutableList newArgs = newArgsBuilder.build(); + ImmutableList newArgs = newArgsBuilder.build(); if (newArgs.isEmpty()) { - CelExpr shortCircuitTarget = call.args().get(0); // either args(0) or args(1) would work here - return Optional.of(astMutator.replaceSubtree(ast, shortCircuitTarget, expr.id())); + CelMutableExpr shortCircuitTarget = + call.args().get(0); // either args(0) or args(1) would work here + return Optional.of(astMutator.replaceSubtree(mutableAst, shortCircuitTarget, expr.id())); } if (newArgs.size() == 1) { - return Optional.of(astMutator.replaceSubtree(ast, newArgs.get(0), expr.id())); + return Optional.of(astMutator.replaceSubtree(mutableAst, newArgs.get(0), expr.id())); } // TODO: Support folding variadic AND/ORs. @@ -414,22 +405,20 @@ private Optional maybeShortCircuitCall( "Folding variadic logical operator is not supported yet."); } - private CelAbstractSyntaxTree pruneOptionalElements(CelNavigableAst navigableAst) { - ImmutableList aggregateLiterals = - navigableAst - .getRoot() + private CelMutableAst pruneOptionalElements(CelMutableAst ast) { + ImmutableList aggregateLiterals = + CelNavigableMutableExpr.fromExpr(ast.expr()) .allNodes() .filter( node -> node.getKind().equals(Kind.CREATE_LIST) || node.getKind().equals(Kind.CREATE_MAP) || node.getKind().equals(Kind.CREATE_STRUCT)) - .map(CelNavigableExpr::expr) + .map(CelNavigableMutableExpr::expr) .collect(toImmutableList()); - CelAbstractSyntaxTree ast = navigableAst.getAst(); - for (CelExpr expr : aggregateLiterals) { - switch (expr.exprKind().getKind()) { + for (CelMutableExpr expr : aggregateLiterals) { + switch (expr.getKind()) { case CREATE_LIST: ast = pruneOptionalListElements(ast, expr); break; @@ -440,40 +429,41 @@ private CelAbstractSyntaxTree pruneOptionalElements(CelNavigableAst navigableAst ast = pruneOptionalStructElements(ast, expr); break; default: - throw new IllegalArgumentException("Unexpected exprKind: " + expr.exprKind()); + throw new IllegalArgumentException("Unexpected exprKind: " + expr.getKind()); } } + return ast; } - private CelAbstractSyntaxTree pruneOptionalListElements(CelAbstractSyntaxTree ast, CelExpr expr) { - CelCreateList createList = expr.createList(); + private CelMutableAst pruneOptionalListElements(CelMutableAst mutableAst, CelMutableExpr expr) { + CelMutableCreateList createList = expr.createList(); if (createList.optionalIndices().isEmpty()) { - return ast; + return mutableAst; } HashSet optionalIndices = new HashSet<>(createList.optionalIndices()); - ImmutableList.Builder updatedElemBuilder = new ImmutableList.Builder<>(); + ImmutableList.Builder updatedElemBuilder = new ImmutableList.Builder<>(); ImmutableList.Builder updatedIndicesBuilder = new ImmutableList.Builder<>(); int newOptIndex = -1; for (int i = 0; i < createList.elements().size(); i++) { newOptIndex++; - CelExpr element = createList.elements().get(i); + CelMutableExpr element = createList.elements().get(i); if (!optionalIndices.contains(i)) { updatedElemBuilder.add(element); continue; } - if (element.exprKind().getKind().equals(Kind.CALL)) { - CelCall call = element.call(); + if (element.getKind().equals(Kind.CALL)) { + CelMutableCall call = element.call(); if (call.function().equals(Function.OPTIONAL_NONE.getFunction())) { // Skip optional.none. // Skipping causes the list to get smaller. newOptIndex--; continue; } else if (call.function().equals(Function.OPTIONAL_OF.getFunction())) { - CelExpr arg = call.args().get(0); - if (arg.exprKind().getKind().equals(Kind.CONSTANT)) { + CelMutableExpr arg = call.args().get(0); + if (arg.getKind().equals(Kind.CONSTANT)) { updatedElemBuilder.add(call.args().get(0)); continue; } @@ -485,26 +475,22 @@ private CelAbstractSyntaxTree pruneOptionalListElements(CelAbstractSyntaxTree as } return astMutator.replaceSubtree( - ast, - CelExpr.newBuilder() - .setCreateList( - CelCreateList.newBuilder() - .addElements(updatedElemBuilder.build()) - .addOptionalIndices(updatedIndicesBuilder.build()) - .build()) - .build(), + mutableAst, + CelMutableExpr.ofCreateList( + CelMutableCreateList.create(updatedElemBuilder.build(), updatedIndicesBuilder.build())), expr.id()); } - private CelAbstractSyntaxTree pruneOptionalMapElements(CelAbstractSyntaxTree ast, CelExpr expr) { - CelCreateMap createMap = expr.createMap(); - ImmutableList.Builder updatedEntryBuilder = new ImmutableList.Builder<>(); + private CelMutableAst pruneOptionalMapElements(CelMutableAst ast, CelMutableExpr expr) { + CelMutableCreateMap createMap = expr.createMap(); + ImmutableList.Builder updatedEntryBuilder = + new ImmutableList.Builder<>(); boolean modified = false; - for (CelCreateMap.Entry entry : createMap.entries()) { - CelExpr key = entry.key(); - Kind keyKind = key.exprKind().getKind(); - CelExpr value = entry.value(); - Kind valueKind = value.exprKind().getKind(); + for (CelMutableCreateMap.Entry entry : createMap.entries()) { + CelMutableExpr key = entry.key(); + Kind keyKind = key.getKind(); + CelMutableExpr value = entry.value(); + Kind valueKind = value.getKind(); if (!entry.optionalEntry() || !keyKind.equals(Kind.CONSTANT) || !valueKind.equals(Kind.CALL)) { @@ -512,17 +498,18 @@ private CelAbstractSyntaxTree pruneOptionalMapElements(CelAbstractSyntaxTree ast continue; } - CelCall call = value.call(); + CelMutableCall call = value.call(); if (call.function().equals(Function.OPTIONAL_NONE.getFunction())) { // Skip the element. This is resolving an optional.none: ex {?1: optional.none()}. modified = true; continue; } else if (call.function().equals(Function.OPTIONAL_OF.getFunction())) { - CelExpr arg = call.args().get(0); - if (arg.exprKind().getKind().equals(Kind.CONSTANT)) { + CelMutableExpr arg = call.args().get(0); + if (arg.getKind().equals(Kind.CONSTANT)) { modified = true; - updatedEntryBuilder.add( - entry.toBuilder().setOptionalEntry(false).setValue(call.args().get(0)).build()); + entry.setOptionalEntry(false); + entry.setValue(call.args().get(0)); + updatedEntryBuilder.add(entry); continue; } } @@ -533,42 +520,39 @@ private CelAbstractSyntaxTree pruneOptionalMapElements(CelAbstractSyntaxTree ast if (modified) { return astMutator.replaceSubtree( ast, - CelExpr.newBuilder() - .setCreateMap( - CelCreateMap.newBuilder().addEntries(updatedEntryBuilder.build()).build()) - .build(), + CelMutableExpr.ofCreateMap(CelMutableCreateMap.create(updatedEntryBuilder.build())), expr.id()); } return ast; } - private CelAbstractSyntaxTree pruneOptionalStructElements( - CelAbstractSyntaxTree ast, CelExpr expr) { - CelCreateStruct createStruct = expr.createStruct(); - ImmutableList.Builder updatedEntryBuilder = + private CelMutableAst pruneOptionalStructElements(CelMutableAst ast, CelMutableExpr expr) { + CelMutableCreateStruct createStruct = expr.createStruct(); + ImmutableList.Builder updatedEntryBuilder = new ImmutableList.Builder<>(); boolean modified = false; - for (CelCreateStruct.Entry entry : createStruct.entries()) { - CelExpr value = entry.value(); - Kind valueKind = value.exprKind().getKind(); + for (CelMutableCreateStruct.Entry entry : createStruct.entries()) { + CelMutableExpr value = entry.value(); + Kind valueKind = value.getKind(); if (!entry.optionalEntry() || !valueKind.equals(Kind.CALL)) { // Preserve the entry as is updatedEntryBuilder.add(entry); continue; } - CelCall call = value.call(); + CelMutableCall call = value.call(); if (call.function().equals(Function.OPTIONAL_NONE.getFunction())) { // Skip the element. This is resolving an optional.none: ex msg{?field: optional.none()}. modified = true; continue; } else if (call.function().equals(Function.OPTIONAL_OF.getFunction())) { - CelExpr arg = call.args().get(0); - if (arg.exprKind().getKind().equals(Kind.CONSTANT)) { + CelMutableExpr arg = call.args().get(0); + if (arg.getKind().equals(Kind.CONSTANT)) { modified = true; - updatedEntryBuilder.add( - entry.toBuilder().setOptionalEntry(false).setValue(call.args().get(0)).build()); + entry.setOptionalEntry(false); + entry.setValue(call.args().get(0)); + updatedEntryBuilder.add(entry); continue; } } @@ -579,13 +563,9 @@ private CelAbstractSyntaxTree pruneOptionalStructElements( if (modified) { return astMutator.replaceSubtree( ast, - CelExpr.newBuilder() - .setCreateStruct( - CelCreateStruct.newBuilder() - .setMessageName(createStruct.messageName()) - .addEntries(updatedEntryBuilder.build()) - .build()) - .build(), + CelMutableExpr.ofCreateStruct( + CelMutableCreateStruct.create( + createStruct.messageName(), updatedEntryBuilder.build())), expr.id()); } diff --git a/optimizer/src/test/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizerTest.java b/optimizer/src/test/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizerTest.java index ddadd5a20..306960b02 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizerTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizerTest.java @@ -160,6 +160,7 @@ public class ConstantFoldingOptimizerTest { "{source: '{\"a\": dyn([1, 2]), \"b\": x}', expected: '{\"a\": [1, 2], \"b\": x}'}") @TestParameters("{source: 'map_var[?\"key\"]', expected: 'map_var[?\"key\"]'}") @TestParameters("{source: '\"abc\" in list_var', expected: '\"abc\" in list_var'}") + @TestParameters("{source: '[?optional.none(), [?optional.none()]]', expected: '[[]]'}") @TestParameters( "{source: 'cel.bind(r0, [1, 2, 3], cel.bind(r1, 1 in r0, r1))', expected: 'true'}") // TODO: Support folding lists with mixed types. This requires mutable lists. diff --git a/optimizer/src/test/resources/constfold_before_subexpression_unparsed.baseline b/optimizer/src/test/resources/constfold_before_subexpression_unparsed.baseline index 849e8d5ca..8aeacf84e 100644 --- a/optimizer/src/test/resources/constfold_before_subexpression_unparsed.baseline +++ b/optimizer/src/test/resources/constfold_before_subexpression_unparsed.baseline @@ -514,17 +514,17 @@ Test case: OPTIONAL_LIST Source: [10, ?optional.none(), [?optional.none(), ?opt_x], [?optional.none(), ?opt_x]] == [10, [5], [5]] =====> Result: true -[CASCADED_BINDS]: cel.bind(@r0, optional.none(), [10, ?@r0, [?opt_x], [?@r0, ?opt_x]]) == cel.bind(@r1, [5], [10, @r1, @r1]) -[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([optional.none(), [5]], [10, ?@index0, [?opt_x], [?@index0, ?opt_x]] == [10, @index1, @index1]) -[BLOCK_RECURSION_DEPTH_1]: cel.@block([optional.none(), [5], [?opt_x], [?@index0, ?opt_x], [10, ?@index0, @index2, @index3], [10, @index1, @index1]], @index4 == @index5) -[BLOCK_RECURSION_DEPTH_2]: cel.@block([optional.none(), [5], [10, ?@index0, [?opt_x], [?@index0, ?opt_x]]], @index2 == [10, @index1, @index1]) -[BLOCK_RECURSION_DEPTH_3]: cel.@block([optional.none(), [5]], [10, ?@index0, [?opt_x], [?@index0, ?opt_x]] == [10, @index1, @index1]) -[BLOCK_RECURSION_DEPTH_4]: cel.@block([optional.none(), [5]], [10, ?@index0, [?opt_x], [?@index0, ?opt_x]] == [10, @index1, @index1]) -[BLOCK_RECURSION_DEPTH_5]: cel.@block([optional.none(), [5]], [10, ?@index0, [?opt_x], [?@index0, ?opt_x]] == [10, @index1, @index1]) -[BLOCK_RECURSION_DEPTH_6]: cel.@block([optional.none(), [5]], [10, ?@index0, [?opt_x], [?@index0, ?opt_x]] == [10, @index1, @index1]) -[BLOCK_RECURSION_DEPTH_7]: cel.@block([optional.none(), [5]], [10, ?@index0, [?opt_x], [?@index0, ?opt_x]] == [10, @index1, @index1]) -[BLOCK_RECURSION_DEPTH_8]: cel.@block([optional.none(), [5]], [10, ?@index0, [?opt_x], [?@index0, ?opt_x]] == [10, @index1, @index1]) -[BLOCK_RECURSION_DEPTH_9]: cel.@block([optional.none(), [5]], [10, ?@index0, [?opt_x], [?@index0, ?opt_x]] == [10, @index1, @index1]) +[CASCADED_BINDS]: cel.bind(@r0, [?opt_x], [10, @r0, @r0]) == cel.bind(@r1, [5], [10, @r1, @r1]) +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([[?opt_x], [5]], [10, @index0, @index0] == [10, @index1, @index1]) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([[?opt_x], [5], [10, @index0, @index0], [10, @index1, @index1]], @index2 == @index3) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([[?opt_x], [5]], [10, @index0, @index0] == [10, @index1, @index1]) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([[?opt_x], [5]], [10, @index0, @index0] == [10, @index1, @index1]) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([[?opt_x], [5]], [10, @index0, @index0] == [10, @index1, @index1]) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([[?opt_x], [5]], [10, @index0, @index0] == [10, @index1, @index1]) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([[?opt_x], [5]], [10, @index0, @index0] == [10, @index1, @index1]) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([[?opt_x], [5]], [10, @index0, @index0] == [10, @index1, @index1]) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([[?opt_x], [5]], [10, @index0, @index0] == [10, @index1, @index1]) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([[?opt_x], [5]], [10, @index0, @index0] == [10, @index1, @index1]) Test case: OPTIONAL_MAP Source: {?'hello': optional.of('hello')}['hello'] + {?'hello': optional.of('hello')}['hello'] == 'hellohello' From e694255cd1fa93f72758685f16f489d2e1288669 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Mon, 22 Apr 2024 09:37:07 -0700 Subject: [PATCH 093/486] Change SubexpressionOptimizer to leverage mutable exprs PiperOrigin-RevId: 627065192 --- .../main/java/dev/cel/common/CelSource.java | 6 + .../java/dev/cel/optimizer/AstMutator.java | 5 +- .../dev/cel/optimizer/optimizers/BUILD.bazel | 2 + .../optimizers/SubexpressionOptimizer.java | 374 ++++++++---------- .../dev/cel/optimizer/AstMutatorTest.java | 20 +- 5 files changed, 192 insertions(+), 215 deletions(-) diff --git a/common/src/main/java/dev/cel/common/CelSource.java b/common/src/main/java/dev/cel/common/CelSource.java index 2422f7b20..82b835180 100644 --- a/common/src/main/java/dev/cel/common/CelSource.java +++ b/common/src/main/java/dev/cel/common/CelSource.java @@ -279,6 +279,12 @@ public Builder clearMacroCall(long exprId) { return this; } + @CanIgnoreReturnValue + public Builder clearMacroCalls() { + this.macroCalls.clear(); + return this; + } + public ImmutableSet getExtensions() { return extensions.build(); } diff --git a/optimizer/src/main/java/dev/cel/optimizer/AstMutator.java b/optimizer/src/main/java/dev/cel/optimizer/AstMutator.java index 2ce5fdddc..ab38af797 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/AstMutator.java +++ b/optimizer/src/main/java/dev/cel/optimizer/AstMutator.java @@ -242,9 +242,8 @@ public CelMutableAst renumberIdsConsecutively(CelMutableAst mutableAst) { * @param newResultPrefix Prefix to use for new comprehensin result identifier names. */ public MangledComprehensionAst mangleComprehensionIdentifierNames( - CelAbstractSyntaxTree ast, String newIterVarPrefix, String newResultPrefix) { - CelNavigableMutableAst navigableMutableAst = - CelNavigableMutableAst.fromAst(CelMutableAst.fromCelAst(ast)); + CelMutableAst ast, String newIterVarPrefix, String newResultPrefix) { + CelNavigableMutableAst navigableMutableAst = CelNavigableMutableAst.fromAst(ast); Predicate comprehensionIdentifierPredicate = x -> true; comprehensionIdentifierPredicate = comprehensionIdentifierPredicate diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel b/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel index 91da59716..95acee0f9 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel @@ -46,8 +46,10 @@ java_library( "//common", "//common:compiler_common", "//common/ast", + "//common/ast:mutable_ast", "//common/navigation", "//common/navigation:common", + "//common/navigation:mutable_navigation", "//common/types", "//common/types:type_providers", "//extensions:optional_library", diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java index 7397d78dd..25d15cc4c 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java @@ -41,10 +41,14 @@ import dev.cel.common.CelVarDecl; import dev.cel.common.ast.CelExpr; import dev.cel.common.ast.CelExpr.CelCall; -import dev.cel.common.ast.CelExpr.CelIdent; import dev.cel.common.ast.CelExpr.ExprKind.Kind; +import dev.cel.common.ast.CelMutableAst; +import dev.cel.common.ast.CelMutableExpr; +import dev.cel.common.ast.CelMutableExprConverter; import dev.cel.common.navigation.CelNavigableAst; import dev.cel.common.navigation.CelNavigableExpr; +import dev.cel.common.navigation.CelNavigableMutableAst; +import dev.cel.common.navigation.CelNavigableMutableExpr; import dev.cel.common.navigation.TraversalOrder; import dev.cel.common.types.CelType; import dev.cel.common.types.ListType; @@ -61,9 +65,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; -import java.util.NoSuchElementException; import java.util.Optional; -import java.util.stream.Stream; /** * Performs Common Subexpression Elimination. @@ -127,86 +129,74 @@ public static SubexpressionOptimizer newInstance(SubexpressionOptimizerOptions c } @Override - public OptimizationResult optimize(CelNavigableAst navigableAst, Cel cel) { + public OptimizationResult optimize(CelNavigableAst ast, Cel cel) { OptimizationResult result = cseOptions.enableCelBlock() - ? optimizeUsingCelBlock(navigableAst, cel) - : optimizeUsingCelBind(navigableAst); + ? optimizeUsingCelBlock(ast.getAst(), cel) + : optimizeUsingCelBind(ast.getAst()); verifyOptimizedAstCorrectness(result.optimizedAst()); return result; } - private OptimizationResult optimizeUsingCelBlock(CelNavigableAst navigableAst, Cel cel) { + private OptimizationResult optimizeUsingCelBlock(CelAbstractSyntaxTree ast, Cel cel) { + CelMutableAst astToModify = CelMutableAst.fromCelAst(ast); + if (!cseOptions.populateMacroCalls()) { + astToModify.source().clearMacroCalls(); + } + MangledComprehensionAst mangledComprehensionAst = astMutator.mangleComprehensionIdentifierNames( - navigableAst.getAst(), + astToModify, MANGLED_COMPREHENSION_IDENTIFIER_PREFIX, MANGLED_COMPREHENSION_RESULT_PREFIX); - CelAbstractSyntaxTree astToModify = mangledComprehensionAst.ast(); - CelSource sourceToModify = astToModify.getSource(); + astToModify = mangledComprehensionAst.mutableAst(); + CelSource.Builder sourceToModify = astToModify.source(); int blockIdentifierIndex = 0; int iterCount; - ArrayList subexpressions = new ArrayList<>(); + ArrayList subexpressions = new ArrayList<>(); + for (iterCount = 0; iterCount < cseOptions.iterationLimit(); iterCount++) { - CelExpr cseCandidate = findCseCandidate(astToModify).map(CelNavigableExpr::expr).orElse(null); - if (cseCandidate == null) { + CelNavigableMutableAst navAst = CelNavigableMutableAst.fromAst(astToModify); + List cseCandidates = getCseCandidates(navAst); + if (cseCandidates.isEmpty()) { break; } - subexpressions.add(cseCandidate); - String blockIdentifier = BLOCK_INDEX_PREFIX + blockIdentifierIndex++; + subexpressions.add(cseCandidates.get(0)); - // Using the CSE candidate, fetch all semantically equivalent subexpressions ahead of time. - ImmutableList allCseCandidates = - getAllCseCandidatesStream(astToModify, cseCandidate).collect(toImmutableList()); + String blockIdentifier = BLOCK_INDEX_PREFIX + blockIdentifierIndex++; // Replace all CSE candidates with new block index identifier - for (CelExpr semanticallyEqualNode : allCseCandidates) { + for (CelMutableExpr cseCandidate : cseCandidates) { iterCount++; - // Refetch the candidate expr as mutating the AST could have renumbered its IDs. - CelExpr exprToReplace = - getAllCseCandidatesStream(astToModify, semanticallyEqualNode) - .findAny() - .orElseThrow( - () -> - new NoSuchElementException( - "No value present for expr ID: " + semanticallyEqualNode.id())); astToModify = astMutator.replaceSubtree( - astToModify, - CelExpr.newBuilder() - .setIdent(CelIdent.newBuilder().setName(blockIdentifier).build()) - .build(), - exprToReplace.id()); + navAst, + CelNavigableMutableAst.fromAst( + CelMutableAst.of( + CelMutableExpr.ofIdent(blockIdentifier), + CelSource.newBuilder() + .addAllMacroCalls(navAst.getAst().source().getMacroCalls()))), + cseCandidate.id()); + + // Retain the existing macro calls in case if the block identifiers are replacing a subtree + // that contains a comprehension. + sourceToModify.addAllMacroCalls(astToModify.source().getMacroCalls()); + astToModify = CelMutableAst.of(astToModify.expr(), sourceToModify); } - - sourceToModify = - sourceToModify.toBuilder() - .addAllMacroCalls(astToModify.getSource().getMacroCalls()) - .build(); - astToModify = CelAbstractSyntaxTree.newParsedAst(astToModify.getExpr(), sourceToModify); - - // Retain the existing macro calls in case if the block identifiers are replacing a subtree - // that contains a comprehension. - sourceToModify = astToModify.getSource(); } if (iterCount >= cseOptions.iterationLimit()) { throw new IllegalStateException("Max iteration count reached."); } - if (!cseOptions.populateMacroCalls()) { - astToModify = - CelAbstractSyntaxTree.newParsedAst(astToModify.getExpr(), CelSource.newBuilder().build()); - } - if (iterCount == 0) { // No modification has been made. - return OptimizationResult.create(astToModify); + return OptimizationResult.create(astToModify.toParsedAst()); } ImmutableList.Builder newVarDecls = ImmutableList.builder(); @@ -234,12 +224,12 @@ private OptimizationResult optimizeUsingCelBlock(CelNavigableAst navigableAst, C astToModify = astMutator.renumberIdsConsecutively(astToModify); // Tag the AST with cel.block designated as an extension - astToModify = tagAstExtension(astToModify); + CelAbstractSyntaxTree optimizedAst = tagAstExtension(astToModify.toParsedAst()); return OptimizationResult.create( - astToModify, + optimizedAst, newVarDecls.build(), - ImmutableList.of(newCelBlockFunctionDecl(navigableAst.getAst().getResultType()))); + ImmutableList.of(newCelBlockFunctionDecl(ast.getResultType()))); } /** @@ -249,11 +239,10 @@ private OptimizationResult optimizeUsingCelBlock(CelNavigableAst navigableAst, C */ @VisibleForTesting static void verifyOptimizedAstCorrectness(CelAbstractSyntaxTree ast) { - CelNavigableAst celNavigableAst = CelNavigableAst.fromAst(ast); + CelNavigableExpr celNavigableExpr = CelNavigableExpr.fromExpr(ast.getExpr()); ImmutableList allCelBlocks = - celNavigableAst - .getRoot() + celNavigableExpr .allNodes() .map(CelNavigableExpr::expr) .filter(expr -> expr.callOrDefault().function().equals(CEL_BLOCK_FUNCTION)) @@ -268,8 +257,7 @@ static void verifyOptimizedAstCorrectness(CelAbstractSyntaxTree ast) { "Expected 1 cel.block function to be present but found %s", allCelBlocks.size()); Verify.verify( - celNavigableAst.getRoot().expr().equals(celBlockExpr), - "Expected cel.block to be present at root"); + celNavigableExpr.expr().equals(celBlockExpr), "Expected cel.block to be present at root"); // Assert correctness on block indices used in subexpressions CelCall celBlockCall = celBlockExpr.call(); @@ -323,7 +311,7 @@ private static CelAbstractSyntaxTree tagAstExtension(CelAbstractSyntaxTree ast) * is used as the new identifiers' types. */ private static ImmutableList newBlockIndexVariableDeclarations( - Cel cel, ImmutableList mangledVarDecls, List subexpressions) { + Cel cel, ImmutableList mangledVarDecls, List subexpressions) { // The resulting type of the subexpressions will likely be different from the // entire expression's expected result type. CelBuilder celBuilder = cel.toCelBuilder().setResultType(SimpleType.DYN); @@ -333,10 +321,12 @@ private static ImmutableList newBlockIndexVariableDeclarations( ImmutableList.Builder varDeclBuilder = ImmutableList.builder(); for (int i = 0; i < subexpressions.size(); i++) { - CelExpr subexpression = subexpressions.get(i); + CelMutableExpr subexpression = subexpressions.get(i); CelAbstractSyntaxTree subAst = - CelAbstractSyntaxTree.newParsedAst(subexpression, CelSource.newBuilder().build()); + CelAbstractSyntaxTree.newParsedAst( + CelMutableExprConverter.fromMutableExpr(subexpression), + CelSource.newBuilder().build()); try { subAst = celBuilder.build().check(subAst).getAst(); @@ -352,118 +342,100 @@ private static ImmutableList newBlockIndexVariableDeclarations( return varDeclBuilder.build(); } - private OptimizationResult optimizeUsingCelBind(CelNavigableAst navigableAst) { - CelAbstractSyntaxTree astToModify = + private OptimizationResult optimizeUsingCelBind(CelAbstractSyntaxTree ast) { + CelMutableAst astToModify = CelMutableAst.fromCelAst(ast); + if (!cseOptions.populateMacroCalls()) { + astToModify.source().clearMacroCalls(); + } + + astToModify = astMutator .mangleComprehensionIdentifierNames( - navigableAst.getAst(), + astToModify, MANGLED_COMPREHENSION_IDENTIFIER_PREFIX, MANGLED_COMPREHENSION_RESULT_PREFIX) - .ast(); - CelSource sourceToModify = astToModify.getSource(); + .mutableAst(); + CelSource.Builder sourceToModify = astToModify.source(); int bindIdentifierIndex = 0; int iterCount; for (iterCount = 0; iterCount < cseOptions.iterationLimit(); iterCount++) { - CelExpr cseCandidate = findCseCandidate(astToModify).map(CelNavigableExpr::expr).orElse(null); - if (cseCandidate == null) { + CelNavigableMutableAst navAst = CelNavigableMutableAst.fromAst(astToModify); + List cseCandidates = getCseCandidates(navAst); + if (cseCandidates.isEmpty()) { break; } String bindIdentifier = BIND_IDENTIFIER_PREFIX + bindIdentifierIndex; bindIdentifierIndex++; - // Using the CSE candidate, fetch all semantically equivalent subexpressions ahead of time. - ImmutableList allCseCandidates = - getAllCseCandidatesStream(astToModify, cseCandidate).collect(toImmutableList()); - // Replace all CSE candidates with new bind identifier - for (CelExpr semanticallyEqualNode : allCseCandidates) { + for (CelMutableExpr cseCandidate : cseCandidates) { iterCount++; - // Refetch the candidate expr as mutating the AST could have renumbered its IDs. - CelExpr exprToReplace = - getAllCseCandidatesStream(astToModify, semanticallyEqualNode) - .findAny() - .orElseThrow( - () -> - new NoSuchElementException( - "No value present for expr ID: " + semanticallyEqualNode.id())); astToModify = astMutator.replaceSubtree( - astToModify, - CelExpr.newBuilder() - .setIdent(CelIdent.newBuilder().setName(bindIdentifier).build()) - .build(), - exprToReplace.id()); + astToModify, CelMutableExpr.ofIdent(bindIdentifier), cseCandidate.id()); } // Find LCA to insert the new cel.bind macro into. - CelNavigableExpr lca = getLca(astToModify, bindIdentifier); - - sourceToModify = - sourceToModify.toBuilder() - .addAllMacroCalls(astToModify.getSource().getMacroCalls()) - .build(); - astToModify = CelAbstractSyntaxTree.newParsedAst(astToModify.getExpr(), sourceToModify); + CelNavigableMutableExpr lca = getLca(navAst, bindIdentifier); // Insert the new bind call + CelMutableExpr subexpressionToBind = cseCandidates.get(0); + // Re-add the macro source for bind identifiers that might have been lost from previous + // iteration of CSE + astToModify.source().addAllMacroCalls(sourceToModify.getMacroCalls()); astToModify = astMutator.replaceSubtreeWithNewBindMacro( - astToModify, bindIdentifier, cseCandidate, lca.expr(), lca.id()); + astToModify, + bindIdentifier, + subexpressionToBind, + lca.expr(), + lca.id(), + cseOptions.populateMacroCalls()); // Retain the existing macro calls in case if the bind identifiers are replacing a subtree // that contains a comprehension. - sourceToModify = astToModify.getSource(); + sourceToModify = astToModify.source(); } if (iterCount >= cseOptions.iterationLimit()) { throw new IllegalStateException("Max iteration count reached."); } - if (!cseOptions.populateMacroCalls()) { - astToModify = - CelAbstractSyntaxTree.newParsedAst(astToModify.getExpr(), CelSource.newBuilder().build()); - } - if (iterCount == 0) { // No modification has been made. - return OptimizationResult.create(astToModify); + return OptimizationResult.create(astToModify.toParsedAst()); } astToModify = astMutator.renumberIdsConsecutively(astToModify); - return OptimizationResult.create(astToModify); - } - - private Stream getAllCseCandidatesStream( - CelAbstractSyntaxTree ast, CelExpr cseCandidate) { - return CelNavigableAst.fromAst(ast) - .getRoot() - .allNodes() - .filter(this::canEliminate) - .map(CelNavigableExpr::expr) - .filter(expr -> areSemanticallyEqual(cseCandidate, expr)); + return OptimizationResult.create(astToModify.toParsedAst()); } - private static CelNavigableExpr getLca(CelAbstractSyntaxTree ast, String boundIdentifier) { - CelNavigableExpr root = CelNavigableAst.fromAst(ast).getRoot(); - ImmutableList allNodesWithIdentifier = + private static CelNavigableMutableExpr getLca( + CelNavigableMutableAst navAst, String boundIdentifier) { + CelNavigableMutableExpr root = navAst.getRoot(); + ImmutableList allNodesWithIdentifier = root.allNodes() - .filter(node -> node.expr().identOrDefault().name().equals(boundIdentifier)) + .filter( + node -> + node.getKind().equals(Kind.IDENT) + && node.expr().ident().name().equals(boundIdentifier)) .collect(toImmutableList()); if (allNodesWithIdentifier.size() < 2) { throw new IllegalStateException("Expected at least 2 bound identifiers to be present."); } - CelNavigableExpr lca = root; + CelNavigableMutableExpr lca = root; long lcaAncestorCount = 0; HashMap ancestors = new HashMap<>(); - for (CelNavigableExpr navigableExpr : allNodesWithIdentifier) { - Optional maybeParent = Optional.of(navigableExpr); + for (CelNavigableMutableExpr navigableExpr : allNodesWithIdentifier) { + Optional maybeParent = Optional.of(navigableExpr); while (maybeParent.isPresent()) { - CelNavigableExpr parent = maybeParent.get(); + CelNavigableMutableExpr parent = maybeParent.get(); if (!ancestors.containsKey(parent.id())) { ancestors.put(parent.id(), 1L); continue; @@ -484,114 +456,132 @@ private static CelNavigableExpr getLca(CelAbstractSyntaxTree ast, String boundId return lca; } - private Optional findCseCandidate(CelAbstractSyntaxTree ast) { + private List getCseCandidates(CelNavigableMutableAst navAst) { if (cseOptions.enableCelBlock() && cseOptions.subexpressionMaxRecursionDepth() > 0) { - return findCseCandidateWithRecursionDepth(ast, cseOptions.subexpressionMaxRecursionDepth()); + return getCseCandidatesWithRecursionDepth( + navAst, cseOptions.subexpressionMaxRecursionDepth()); } else { - return findCseCandidateWithCommonSubexpr(ast); + return getCseCandidatesWithCommonSubexpr(navAst); } } /** - * This retrieves a subexpr candidate based on the recursion limit even if there's no duplicate + * Retrieves all subexpr candidates based on the recursion limit even if there's no duplicate * subexpr found. - * - *

TODO: Improve the extraction logic using a suffix tree. */ - private Optional findCseCandidateWithRecursionDepth( - CelAbstractSyntaxTree ast, int recursionLimit) { + private List getCseCandidatesWithRecursionDepth( + CelNavigableMutableAst navAst, int recursionLimit) { Preconditions.checkArgument(recursionLimit > 0); - ImmutableList allNodes = - CelNavigableAst.fromAst(ast) + ImmutableList descendants = + navAst .getRoot() - .allNodes(TraversalOrder.PRE_ORDER) + .descendants(TraversalOrder.PRE_ORDER) .filter(this::canEliminate) .filter(node -> node.height() <= recursionLimit) - .filter(node -> !areSemanticallyEqual(ast.getExpr(), node.expr())) - .sorted(Comparator.comparingInt(CelNavigableExpr::height).reversed()) + .sorted(Comparator.comparingInt(CelNavigableMutableExpr::height).reversed()) .collect(toImmutableList()); - - if (allNodes.isEmpty()) { - return Optional.empty(); + if (descendants.isEmpty()) { + return new ArrayList<>(); } - Optional commonSubexpr = findCseCandidateWithCommonSubexpr(allNodes); - if (commonSubexpr.isPresent()) { - return commonSubexpr; + List cseCandidates = getCseCandidatesWithCommonSubexpr(descendants); + if (!cseCandidates.isEmpty()) { + return cseCandidates; } // If there's no common subexpr, just return the one with the highest height that's still below // the recursion limit, but only if it actually needs to be extracted due to exceeding the // recursion limit. boolean astHasMoreExtractableSubexprs = - CelNavigableAst.fromAst(ast) + navAst .getRoot() .allNodes(TraversalOrder.POST_ORDER) .filter(node -> node.height() > recursionLimit) .anyMatch(this::canEliminate); if (astHasMoreExtractableSubexprs) { - return Optional.of(allNodes.get(0)); + cseCandidates.add(descendants.get(0).expr()); + return cseCandidates; } // The height of the remaining subexpression is already below the recursion limit. No need to // extract. - return Optional.empty(); + return new ArrayList<>(); } - private Optional findCseCandidateWithCommonSubexpr( - ImmutableList allNodes) { - HashSet encounteredNodes = new HashSet<>(); - for (CelNavigableExpr node : allNodes) { + private List getCseCandidatesWithCommonSubexpr(CelNavigableMutableAst navAst) { + ImmutableList allNodes = + navAst + .getRoot() + .allNodes(TraversalOrder.PRE_ORDER) + .filter(this::canEliminate) + .collect(toImmutableList()); + + return getCseCandidatesWithCommonSubexpr(allNodes); + } + + private List getCseCandidatesWithCommonSubexpr( + ImmutableList allNodes) { + CelMutableExpr normalizedCseCandidate = null; + HashSet semanticallyEqualNodes = new HashSet<>(); + for (CelNavigableMutableExpr node : allNodes) { // Normalize the expr to test semantic equivalence. - CelExpr celExpr = normalizeForEquality(node.expr()); - if (encounteredNodes.contains(celExpr)) { - return Optional.of(node); + CelMutableExpr normalizedExpr = normalizeForEquality(node.expr()); + if (semanticallyEqualNodes.contains(normalizedExpr)) { + normalizedCseCandidate = normalizedExpr; + break; } - encounteredNodes.add(celExpr); + semanticallyEqualNodes.add(normalizedExpr); } - return Optional.empty(); - } + List cseCandidates = new ArrayList<>(); + if (normalizedCseCandidate == null) { + return cseCandidates; + } - private Optional findCseCandidateWithCommonSubexpr(CelAbstractSyntaxTree ast) { - ImmutableList allNodes = - CelNavigableAst.fromAst(ast) - .getRoot() - .allNodes(TraversalOrder.PRE_ORDER) - .filter(this::canEliminate) - .collect(toImmutableList()); + for (CelNavigableMutableExpr node : allNodes) { + // Normalize the expr to test semantic equivalence. + CelMutableExpr normalizedExpr = normalizeForEquality(node.expr()); + if (normalizedExpr.equals(normalizedCseCandidate)) { + cseCandidates.add(node.expr()); + } + } - return findCseCandidateWithCommonSubexpr(allNodes); + return cseCandidates; } - private boolean canEliminate(CelNavigableExpr navigableExpr) { + private boolean canEliminate(CelNavigableMutableExpr navigableExpr) { return !navigableExpr.getKind().equals(Kind.CONSTANT) && !navigableExpr.getKind().equals(Kind.IDENT) - && !navigableExpr.expr().identOrDefault().name().startsWith(BIND_IDENTIFIER_PREFIX) - && !navigableExpr.expr().selectOrDefault().testOnly() + && !(navigableExpr.getKind().equals(Kind.IDENT) + && navigableExpr.expr().ident().name().startsWith(BIND_IDENTIFIER_PREFIX)) + && !(navigableExpr.getKind().equals(Kind.SELECT) + && navigableExpr.expr().select().testOnly()) && containsEliminableFunctionOnly(navigableExpr) && isWithinInlineableComprehension(navigableExpr); } - private static boolean isWithinInlineableComprehension(CelNavigableExpr expr) { - Optional maybeParent = expr.parent(); + private static boolean isWithinInlineableComprehension(CelNavigableMutableExpr expr) { + Optional maybeParent = expr.parent(); while (maybeParent.isPresent()) { - CelNavigableExpr parent = maybeParent.get(); + CelNavigableMutableExpr parent = maybeParent.get(); if (parent.getKind().equals(Kind.COMPREHENSION)) { return Streams.concat( // If the expression is within a comprehension, it is eligible for CSE iff is in // result, loopStep or iterRange. While result is not human authored, it needs to be // included to extract subexpressions that are already in cel.bind macro. - CelNavigableExpr.fromExpr(parent.expr().comprehension().result()).descendants(), - CelNavigableExpr.fromExpr(parent.expr().comprehension().loopStep()).allNodes(), - CelNavigableExpr.fromExpr(parent.expr().comprehension().iterRange()).allNodes()) + CelNavigableMutableExpr.fromExpr(parent.expr().comprehension().result()) + .descendants(), + CelNavigableMutableExpr.fromExpr(parent.expr().comprehension().loopStep()) + .allNodes(), + CelNavigableMutableExpr.fromExpr(parent.expr().comprehension().iterRange()) + .allNodes()) .filter( node -> // Exclude empty lists (cel.bind sets this for iterRange). !node.getKind().equals(Kind.CREATE_LIST) || !node.expr().createList().elements().isEmpty()) - .map(CelNavigableExpr::expr) + .map(CelNavigableMutableExpr::expr) .anyMatch(node -> node.equals(expr.expr())); } maybeParent = parent.parent(); @@ -600,11 +590,7 @@ private static boolean isWithinInlineableComprehension(CelNavigableExpr expr) { return true; } - private boolean areSemanticallyEqual(CelExpr expr1, CelExpr expr2) { - return normalizeForEquality(expr1).equals(normalizeForEquality(expr2)); - } - - private boolean containsEliminableFunctionOnly(CelNavigableExpr navigableExpr) { + private boolean containsEliminableFunctionOnly(CelNavigableMutableExpr navigableExpr) { return navigableExpr .allNodes() .allMatch( @@ -618,44 +604,16 @@ private boolean containsEliminableFunctionOnly(CelNavigableExpr navigableExpr) { } /** - * Converts the {@link CelExpr} to make it suitable for performing semantically equals check in - * {@link #areSemanticallyEqual(CelExpr, CelExpr)}. + * Converts the {@link CelMutableExpr} to make it suitable for performing a semantically equals + * check. * - *

Specifically, this will: - * - *

    - *
  • Set all expr IDs in the expression tree to 0. - *
  • Strip all presence tests (i.e: testOnly is marked as false on {@link - * CelExpr.ExprKind.Kind#SELECT} - *
+ *

Specifically, this will deep copy the mutable expr then set all expr IDs in the expression + * tree to 0. */ - private CelExpr normalizeForEquality(CelExpr celExpr) { - int iterCount; - for (iterCount = 0; iterCount < cseOptions.iterationLimit(); iterCount++) { - CelExpr presenceTestExpr = - CelNavigableExpr.fromExpr(celExpr) - .allNodes() - .map(CelNavigableExpr::expr) - .filter(expr -> expr.selectOrDefault().testOnly()) - .findAny() - .orElse(null); - if (presenceTestExpr == null) { - break; - } - - CelExpr newExpr = - presenceTestExpr.toBuilder() - .setSelect(presenceTestExpr.select().toBuilder().setTestOnly(false).build()) - .build(); - - celExpr = astMutator.replaceSubtree(celExpr, newExpr, newExpr.id()); - } - - if (iterCount >= cseOptions.iterationLimit()) { - throw new IllegalStateException("Max iteration count reached."); - } + private CelMutableExpr normalizeForEquality(CelMutableExpr mutableExpr) { + CelMutableExpr copiedExpr = CelMutableExpr.newInstance(mutableExpr); - return astMutator.clearExprIds(celExpr); + return astMutator.clearExprIds(copiedExpr); } @VisibleForTesting diff --git a/optimizer/src/test/java/dev/cel/optimizer/AstMutatorTest.java b/optimizer/src/test/java/dev/cel/optimizer/AstMutatorTest.java index 5f254dc07..8947ad34a 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/AstMutatorTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/AstMutatorTest.java @@ -801,7 +801,10 @@ public void mangleComprehensionVariable_singleMacro() throws Exception { CelAbstractSyntaxTree ast = CEL.compile("[false].exists(i, i)").getAst(); CelAbstractSyntaxTree mangledAst = - AST_MUTATOR.mangleComprehensionIdentifierNames(ast, "@c", "@x").mutableAst().toParsedAst(); + AST_MUTATOR + .mangleComprehensionIdentifierNames(CelMutableAst.fromCelAst(ast), "@c", "@x") + .mutableAst() + .toParsedAst(); assertThat(mangledAst.getExpr().toString()) .isEqualTo( @@ -868,7 +871,10 @@ public void mangleComprehensionVariable_macroSourceDisabled_macroCallMapIsEmpty( CelAbstractSyntaxTree ast = cel.compile("[false].exists(i, i)").getAst(); CelAbstractSyntaxTree mangledAst = - AST_MUTATOR.mangleComprehensionIdentifierNames(ast, "@c", "@x").mutableAst().toParsedAst(); + AST_MUTATOR + .mangleComprehensionIdentifierNames(CelMutableAst.fromCelAst(ast), "@c", "@x") + .mutableAst() + .toParsedAst(); assertThat(mangledAst.getSource().getMacroCalls()).isEmpty(); } @@ -878,7 +884,10 @@ public void mangleComprehensionVariable_nestedMacroWithShadowedVariables() throw CelAbstractSyntaxTree ast = CEL.compile("[x].exists(x, [x].exists(x, x == 1))").getAst(); CelAbstractSyntaxTree mangledAst = - AST_MUTATOR.mangleComprehensionIdentifierNames(ast, "@c", "@x").mutableAst().toParsedAst(); + AST_MUTATOR + .mangleComprehensionIdentifierNames(CelMutableAst.fromCelAst(ast), "@c", "@x") + .mutableAst() + .toParsedAst(); assertThat(mangledAst.getExpr().toString()) .isEqualTo( @@ -995,7 +1004,10 @@ public void mangleComprehensionVariable_hasMacro_noOp() throws Exception { CelAbstractSyntaxTree ast = CEL.compile("has(msg.single_int64)").getAst(); CelAbstractSyntaxTree mangledAst = - AST_MUTATOR.mangleComprehensionIdentifierNames(ast, "@c", "@x").mutableAst().toParsedAst(); + AST_MUTATOR + .mangleComprehensionIdentifierNames(CelMutableAst.fromCelAst(ast), "@c", "@x") + .mutableAst() + .toParsedAst(); assertThat(CEL_UNPARSER.unparse(mangledAst)).isEqualTo("has(msg.single_int64)"); assertThat( From 95cb753ebfbceb67240e67b9fe53e81619831962 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Mon, 22 Apr 2024 09:59:45 -0700 Subject: [PATCH 094/486] Fully perform CSE on presence tests where possible PiperOrigin-RevId: 627071810 --- .../optimizers/SubexpressionOptimizer.java | 2 - ...old_before_subexpression_unparsed.baseline | 14 +- ...ion_ast_block_common_subexpr_only.baseline | 32 +-- ...ssion_ast_block_recursion_depth_1.baseline | 271 +++++++++++------- ...ssion_ast_block_recursion_depth_2.baseline | 120 ++++---- ...ssion_ast_block_recursion_depth_3.baseline | 52 ++-- ...ssion_ast_block_recursion_depth_4.baseline | 32 +-- ...ssion_ast_block_recursion_depth_5.baseline | 32 +-- ...ssion_ast_block_recursion_depth_6.baseline | 32 +-- ...ssion_ast_block_recursion_depth_7.baseline | 32 +-- ...ssion_ast_block_recursion_depth_8.baseline | 32 +-- ...ssion_ast_block_recursion_depth_9.baseline | 32 +-- .../subexpression_ast_cascaded_binds.baseline | 36 ++- .../resources/subexpression_unparsed.baseline | 38 +-- 14 files changed, 392 insertions(+), 365 deletions(-) diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java index 25d15cc4c..a71e83912 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java @@ -555,8 +555,6 @@ private boolean canEliminate(CelNavigableMutableExpr navigableExpr) { && !navigableExpr.getKind().equals(Kind.IDENT) && !(navigableExpr.getKind().equals(Kind.IDENT) && navigableExpr.expr().ident().name().startsWith(BIND_IDENTIFIER_PREFIX)) - && !(navigableExpr.getKind().equals(Kind.SELECT) - && navigableExpr.expr().select().testOnly()) && containsEliminableFunctionOnly(navigableExpr) && isWithinInlineableComprehension(navigableExpr); } diff --git a/optimizer/src/test/resources/constfold_before_subexpression_unparsed.baseline b/optimizer/src/test/resources/constfold_before_subexpression_unparsed.baseline index 8aeacf84e..ab1e6e12b 100644 --- a/optimizer/src/test/resources/constfold_before_subexpression_unparsed.baseline +++ b/optimizer/src/test/resources/constfold_before_subexpression_unparsed.baseline @@ -452,7 +452,7 @@ Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : 0) Result: true [CASCADED_BINDS]: cel.bind(@r0, msg.oneof_type, has(@r0.payload) ? @r0.payload.single_int64 : 0) == 10 [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.oneof_type], (has(@index0.payload) ? @index0.payload.single_int64 : 0) == 10) -[BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64], (has(@index0.payload) ? @index2 : 0) == 10) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, has(@index0.payload), @index0.payload, @index2.single_int64, @index1 ? @index3 : 0], @index4 == 10) [BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type, @index0.payload.single_int64, has(@index0.payload) ? @index1 : 0], @index2 == 10) [BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type, has(@index0.payload) ? @index0.payload.single_int64 : 0], @index1 == 10) [BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.oneof_type], (has(@index0.payload) ? @index0.payload.single_int64 : 0) == 10) @@ -468,8 +468,8 @@ Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : msg Result: true [CASCADED_BINDS]: cel.bind(@r0, msg.oneof_type, cel.bind(@r1, @r0.payload.single_int64, has(@r0.payload) ? @r1 : (@r1 * 0))) == 10 [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.oneof_type, @index0.payload.single_int64], (has(@index0.payload) ? @index1 : (@index1 * 0)) == 10) -[BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, @index2 * 0], (has(@index0.payload) ? @index2 : @index3) == 10) -[BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type.payload, @index0.single_int64, msg.oneof_type, has(@index2.payload) ? @index1 : (@index1 * 0)], @index3 == 10) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, has(@index0.payload), @index2 * 0, @index3 ? @index2 : @index4], @index5 == 10) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type.payload, @index0.single_int64, has(msg.oneof_type.payload), @index2 ? @index1 : (@index1 * 0)], @index3 == 10) [BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type.payload.single_int64, has(msg.oneof_type.payload) ? @index0 : (@index0 * 0)], @index1 == 10) [BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.oneof_type.payload.single_int64], (has(msg.oneof_type.payload) ? @index0 : (@index0 * 0)) == 10) [BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.oneof_type.payload.single_int64], (has(msg.oneof_type.payload) ? @index0 : (@index0 * 0)) == 10) @@ -484,9 +484,9 @@ Source: (has(msg.oneof_type.payload.single_int64) ? msg.oneof_type.payload.singl Result: true [CASCADED_BINDS]: cel.bind(@r0, msg.oneof_type.payload, cel.bind(@r1, @r0.single_int64, has(@r0.single_int64) ? @r1 : (@r1 * 0))) == 10 [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.oneof_type.payload, @index0.single_int64], (has(@index0.single_int64) ? @index1 : (@index1 * 0)) == 10) -[BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, @index2 * 0], (has(@index1.single_int64) ? @index2 : @index3) == 10) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, has(@index1.single_int64), @index2 * 0, @index3 ? @index2 : @index4], @index5 == 10) [BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type.payload, @index0.single_int64, has(@index0.single_int64) ? @index1 : (@index1 * 0)], @index2 == 10) -[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type.payload.single_int64, msg.oneof_type.payload], (has(@index1.single_int64) ? @index0 : (@index0 * 0)) == 10) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type.payload.single_int64, has(msg.oneof_type.payload.single_int64)], (@index1 ? @index0 : (@index0 * 0)) == 10) [BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.oneof_type.payload.single_int64, has(msg.oneof_type.payload.single_int64) ? @index0 : (@index0 * 0)], @index1 == 10) [BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.oneof_type.payload.single_int64], (has(msg.oneof_type.payload.single_int64) ? @index0 : (@index0 * 0)) == 10) [BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.oneof_type.payload.single_int64], (has(msg.oneof_type.payload.single_int64) ? @index0 : (@index0 * 0)) == 10) @@ -500,8 +500,8 @@ Source: (has(msg.oneof_type) && has(msg.oneof_type.payload) && has(msg.oneof_typ Result: true [CASCADED_BINDS]: cel.bind(@r0, msg.oneof_type, cel.bind(@r1, @r0.payload, (has(msg.oneof_type) && has(@r0.payload) && has(@r1.single_int64)) ? cel.bind(@r2, @r1.map_string_string, (has(@r1.map_string_string) && has(@r2.key)) ? (@r2.key == "A") : false) : false)) [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_string_string], (has(msg.oneof_type) && has(@index0.payload) && has(@index1.single_int64)) ? ((has(@index1.map_string_string) && has(@index2.key)) ? (@index2.key == "A") : false) : false) -[BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_string_string, @index2.key, @index3 == "A"], (has(msg.oneof_type) && has(@index0.payload) && has(@index1.single_int64)) ? ((has(@index1.map_string_string) && has(@index2.key)) ? @index4 : false) : false) -[BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type.payload, @index0.map_string_string, has(@index0.map_string_string) && has(@index1.key), @index1.key == "A", msg.oneof_type, has(msg.oneof_type) && has(@index4.payload), @index5 && has(@index0.single_int64)], @index6 ? (@index2 ? @index3 : false) : false) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_string_string, has(msg.oneof_type), has(@index0.payload), @index3 && @index4, has(@index1.single_int64), @index5 && @index6, has(@index1.map_string_string), has(@index2.key), @index8 && @index9, @index2.key, @index11 == "A", @index10 ? @index12 : false], @index7 ? @index13 : false) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type.payload, @index0.map_string_string, has(msg.oneof_type.payload), has(msg.oneof_type) && @index2, @index3 && has(@index0.single_int64), has(@index0.map_string_string) && has(@index1.key), @index1.key == "A"], @index4 ? (@index5 ? @index6 : false) : false) [BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type.payload.map_string_string, msg.oneof_type.payload, has(msg.oneof_type) && has(msg.oneof_type.payload), (has(@index1.map_string_string) && has(@index0.key)) ? (@index0.key == "A") : false], (@index2 && has(@index1.single_int64)) ? @index3 : false) [BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.oneof_type.payload.map_string_string, msg.oneof_type.payload, has(msg.oneof_type) && has(msg.oneof_type.payload) && has(@index1.single_int64)], @index2 ? ((has(@index1.map_string_string) && has(@index0.key)) ? (@index0.key == "A") : false) : false) [BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.oneof_type.payload.map_string_string, msg.oneof_type.payload], (has(msg.oneof_type) && has(msg.oneof_type.payload) && has(@index1.single_int64)) ? ((has(@index1.map_string_string) && has(@index0.key)) ? (@index0.key == "A") : false) : false) diff --git a/optimizer/src/test/resources/subexpression_ast_block_common_subexpr_only.baseline b/optimizer/src/test/resources/subexpression_ast_block_common_subexpr_only.baseline index d3026dd15..552ed004c 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_common_subexpr_only.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_common_subexpr_only.baseline @@ -2236,30 +2236,28 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_MAP [3] { - MAP_ENTRY [4] { - key: { - CONSTANT [5] { value: "a" } - } - value: { - CONSTANT [6] { value: true } + SELECT [3] { + CREATE_MAP [4] { + MAP_ENTRY [5] { + key: { + CONSTANT [6] { value: "a" } + } + value: { + CONSTANT [7] { value: true } + } } - } + }.a~presence_test } } } - CALL [7] { + CALL [8] { function: _&&_ args: { - SELECT [8] { - IDENT [9] { - name: @index0 - }.a~presence_test + IDENT [9] { + name: @index0 } - SELECT [10] { - IDENT [11] { - name: @index0 - }.a~presence_test + IDENT [10] { + name: @index0 } } } diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_1.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_1.baseline index 4a37c61ff..cc88bd2e0 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_1.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_1.baseline @@ -2820,28 +2820,31 @@ CALL [1] { } } } - CALL [7] { + SELECT [7] { + IDENT [8] { + name: @index0 + }.a~presence_test + } + CALL [9] { function: _[_] args: { - IDENT [8] { + IDENT [10] { name: @index0 } - CONSTANT [9] { value: "a" } + CONSTANT [11] { value: "a" } } } } } - CALL [10] { + CALL [12] { function: _&&_ args: { - SELECT [11] { - IDENT [12] { - name: @index0 - }.a~presence_test - } IDENT [13] { name: @index1 } + IDENT [14] { + name: @index2 + } } } } @@ -2864,20 +2867,21 @@ CALL [1] { } } } + SELECT [7] { + IDENT [8] { + name: @index0 + }.a~presence_test + } } } - CALL [7] { + CALL [9] { function: _&&_ args: { - SELECT [8] { - IDENT [9] { - name: @index0 - }.a~presence_test + IDENT [10] { + name: @index1 } - SELECT [10] { - IDENT [11] { - name: @index0 - }.a~presence_test + IDENT [11] { + name: @index1 } } } @@ -2899,33 +2903,39 @@ CALL [1] { SELECT [5] { IDENT [6] { name: @index0 - }.payload + }.payload~presence_test } SELECT [7] { IDENT [8] { - name: @index1 + name: @index0 + }.payload + } + SELECT [9] { + IDENT [10] { + name: @index2 }.single_int64 } - } - } - CALL [9] { - function: _==_ - args: { - CALL [10] { + CALL [11] { function: _?_:_ args: { - SELECT [11] { - IDENT [12] { - name: @index0 - }.payload~presence_test + IDENT [12] { + name: @index1 } IDENT [13] { - name: @index2 + name: @index3 } CONSTANT [14] { value: 0 } } } - CONSTANT [15] { value: 10 } + } + } + CALL [15] { + function: _==_ + args: { + IDENT [16] { + name: @index4 + } + CONSTANT [17] { value: 10 } } } } @@ -2953,37 +2963,43 @@ CALL [1] { name: @index1 }.single_int64 } - CALL [9] { + SELECT [9] { + IDENT [10] { + name: @index0 + }.payload~presence_test + } + CALL [11] { function: _*_ args: { - IDENT [10] { + IDENT [12] { name: @index2 } - CONSTANT [11] { value: 0 } + CONSTANT [13] { value: 0 } } } - } - } - CALL [12] { - function: _==_ - args: { - CALL [13] { + CALL [14] { function: _?_:_ args: { - SELECT [14] { - IDENT [15] { - name: @index0 - }.payload~presence_test + IDENT [15] { + name: @index3 } IDENT [16] { name: @index2 } IDENT [17] { - name: @index3 + name: @index4 } } } - CONSTANT [18] { value: 10 } + } + } + CALL [18] { + function: _==_ + args: { + IDENT [19] { + name: @index5 + } + CONSTANT [20] { value: 10 } } } } @@ -3011,37 +3027,43 @@ CALL [1] { name: @index1 }.single_int64 } - CALL [9] { + SELECT [9] { + IDENT [10] { + name: @index1 + }.single_int64~presence_test + } + CALL [11] { function: _*_ args: { - IDENT [10] { + IDENT [12] { name: @index2 } - CONSTANT [11] { value: 0 } + CONSTANT [13] { value: 0 } } } - } - } - CALL [12] { - function: _==_ - args: { - CALL [13] { + CALL [14] { function: _?_:_ args: { - SELECT [14] { - IDENT [15] { - name: @index1 - }.single_int64~presence_test + IDENT [15] { + name: @index3 } IDENT [16] { name: @index2 } IDENT [17] { - name: @index3 + name: @index4 } } } - CONSTANT [18] { value: 10 } + } + } + CALL [18] { + function: _==_ + args: { + IDENT [19] { + name: @index5 + } + CONSTANT [20] { value: 10 } } } } @@ -3071,73 +3093,100 @@ CALL [1] { } SELECT [9] { IDENT [10] { - name: @index2 - }.key + name: msg + }.oneof_type~presence_test } - CALL [11] { - function: _==_ + SELECT [11] { + IDENT [12] { + name: @index0 + }.payload~presence_test + } + CALL [13] { + function: _&&_ args: { - IDENT [12] { + IDENT [14] { name: @index3 } - CONSTANT [13] { value: "A" } + IDENT [15] { + name: @index4 + } } } - } - } - CALL [14] { - function: _?_:_ - args: { - CALL [15] { + SELECT [16] { + IDENT [17] { + name: @index1 + }.single_int64~presence_test + } + CALL [18] { function: _&&_ args: { - CALL [16] { - function: _&&_ - args: { - SELECT [17] { - IDENT [18] { - name: msg - }.oneof_type~presence_test - } - SELECT [19] { - IDENT [20] { - name: @index0 - }.payload~presence_test - } - } + IDENT [19] { + name: @index5 } - SELECT [21] { - IDENT [22] { - name: @index1 - }.single_int64~presence_test + IDENT [20] { + name: @index6 } } } - CALL [23] { + SELECT [21] { + IDENT [22] { + name: @index1 + }.map_string_string~presence_test + } + SELECT [23] { + IDENT [24] { + name: @index2 + }.key~presence_test + } + CALL [25] { + function: _&&_ + args: { + IDENT [26] { + name: @index8 + } + IDENT [27] { + name: @index9 + } + } + } + SELECT [28] { + IDENT [29] { + name: @index2 + }.key + } + CALL [30] { + function: _==_ + args: { + IDENT [31] { + name: @index11 + } + CONSTANT [32] { value: "A" } + } + } + CALL [33] { function: _?_:_ args: { - CALL [24] { - function: _&&_ - args: { - SELECT [25] { - IDENT [26] { - name: @index1 - }.map_string_string~presence_test - } - SELECT [27] { - IDENT [28] { - name: @index2 - }.key~presence_test - } - } + IDENT [34] { + name: @index10 } - IDENT [29] { - name: @index4 + IDENT [35] { + name: @index12 } - CONSTANT [30] { value: false } + CONSTANT [36] { value: false } } } - CONSTANT [31] { value: false } + } + } + CALL [37] { + function: _?_:_ + args: { + IDENT [38] { + name: @index7 + } + IDENT [39] { + name: @index13 + } + CONSTANT [40] { value: false } } } } diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_2.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_2.baseline index 47c8e9e13..aca5d438e 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_2.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_2.baseline @@ -2637,30 +2637,28 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_MAP [3] { - MAP_ENTRY [4] { - key: { - CONSTANT [5] { value: "a" } - } - value: { - CONSTANT [6] { value: true } + SELECT [3] { + CREATE_MAP [4] { + MAP_ENTRY [5] { + key: { + CONSTANT [6] { value: "a" } + } + value: { + CONSTANT [7] { value: true } + } } - } + }.a~presence_test } } } - CALL [7] { + CALL [8] { function: _&&_ args: { - SELECT [8] { - IDENT [9] { - name: @index0 - }.a~presence_test + IDENT [9] { + name: @index0 } - SELECT [10] { - IDENT [11] { - name: @index0 - }.a~presence_test + IDENT [10] { + name: @index0 } } } @@ -2734,17 +2732,17 @@ CALL [1] { }.single_int64 } SELECT [8] { - IDENT [9] { - name: msg - }.oneof_type + SELECT [9] { + IDENT [10] { + name: msg + }.oneof_type + }.payload~presence_test } - CALL [10] { + CALL [11] { function: _?_:_ args: { - SELECT [11] { - IDENT [12] { - name: @index2 - }.payload~presence_test + IDENT [12] { + name: @index2 } IDENT [13] { name: @index1 @@ -2848,63 +2846,63 @@ CALL [1] { name: @index0 }.map_string_string } - CALL [8] { + SELECT [8] { + SELECT [9] { + IDENT [10] { + name: msg + }.oneof_type + }.payload~presence_test + } + CALL [11] { function: _&&_ args: { - SELECT [9] { - IDENT [10] { - name: @index0 - }.map_string_string~presence_test + SELECT [12] { + IDENT [13] { + name: msg + }.oneof_type~presence_test } - SELECT [11] { - IDENT [12] { - name: @index1 - }.key~presence_test + IDENT [14] { + name: @index2 } } } - CALL [13] { - function: _==_ + CALL [15] { + function: _&&_ args: { - SELECT [14] { - IDENT [15] { - name: @index1 - }.key + IDENT [16] { + name: @index3 + } + SELECT [17] { + IDENT [18] { + name: @index0 + }.single_int64~presence_test } - CONSTANT [16] { value: "A" } } } - SELECT [17] { - IDENT [18] { - name: msg - }.oneof_type - } CALL [19] { function: _&&_ args: { SELECT [20] { IDENT [21] { - name: msg - }.oneof_type~presence_test + name: @index0 + }.map_string_string~presence_test } SELECT [22] { IDENT [23] { - name: @index4 - }.payload~presence_test + name: @index1 + }.key~presence_test } } } CALL [24] { - function: _&&_ + function: _==_ args: { - IDENT [25] { - name: @index5 - } - SELECT [26] { - IDENT [27] { - name: @index0 - }.single_int64~presence_test + SELECT [25] { + IDENT [26] { + name: @index1 + }.key } + CONSTANT [27] { value: "A" } } } } @@ -2913,16 +2911,16 @@ CALL [1] { function: _?_:_ args: { IDENT [29] { - name: @index6 + name: @index4 } CALL [30] { function: _?_:_ args: { IDENT [31] { - name: @index2 + name: @index5 } IDENT [32] { - name: @index3 + name: @index6 } CONSTANT [33] { value: false } } diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_3.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_3.baseline index ae572aed0..babd462ba 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_3.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_3.baseline @@ -2392,30 +2392,28 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_MAP [3] { - MAP_ENTRY [4] { - key: { - CONSTANT [5] { value: "a" } - } - value: { - CONSTANT [6] { value: true } + SELECT [3] { + CREATE_MAP [4] { + MAP_ENTRY [5] { + key: { + CONSTANT [6] { value: "a" } + } + value: { + CONSTANT [7] { value: true } + } } - } + }.a~presence_test } } } - CALL [7] { + CALL [8] { function: _&&_ args: { - SELECT [8] { - IDENT [9] { - name: @index0 - }.a~presence_test + IDENT [9] { + name: @index0 } - SELECT [10] { - IDENT [11] { - name: @index0 - }.a~presence_test + IDENT [10] { + name: @index0 } } } @@ -2538,23 +2536,23 @@ CALL [1] { } SELECT [7] { SELECT [8] { - IDENT [9] { - name: msg - }.oneof_type - }.payload + SELECT [9] { + IDENT [10] { + name: msg + }.oneof_type + }.payload + }.single_int64~presence_test } } } - CALL [10] { + CALL [11] { function: _==_ args: { - CALL [11] { + CALL [12] { function: _?_:_ args: { - SELECT [12] { - IDENT [13] { - name: @index1 - }.single_int64~presence_test + IDENT [13] { + name: @index1 } IDENT [14] { name: @index0 diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_4.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_4.baseline index d7df4463a..34e6aaca1 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_4.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_4.baseline @@ -2329,30 +2329,28 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_MAP [3] { - MAP_ENTRY [4] { - key: { - CONSTANT [5] { value: "a" } - } - value: { - CONSTANT [6] { value: true } + SELECT [3] { + CREATE_MAP [4] { + MAP_ENTRY [5] { + key: { + CONSTANT [6] { value: "a" } + } + value: { + CONSTANT [7] { value: true } + } } - } + }.a~presence_test } } } - CALL [7] { + CALL [8] { function: _&&_ args: { - SELECT [8] { - IDENT [9] { - name: @index0 - }.a~presence_test + IDENT [9] { + name: @index0 } - SELECT [10] { - IDENT [11] { - name: @index0 - }.a~presence_test + IDENT [10] { + name: @index0 } } } diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_5.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_5.baseline index ce5eafd5f..36fe2713b 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_5.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_5.baseline @@ -2299,30 +2299,28 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_MAP [3] { - MAP_ENTRY [4] { - key: { - CONSTANT [5] { value: "a" } - } - value: { - CONSTANT [6] { value: true } + SELECT [3] { + CREATE_MAP [4] { + MAP_ENTRY [5] { + key: { + CONSTANT [6] { value: "a" } + } + value: { + CONSTANT [7] { value: true } + } } - } + }.a~presence_test } } } - CALL [7] { + CALL [8] { function: _&&_ args: { - SELECT [8] { - IDENT [9] { - name: @index0 - }.a~presence_test + IDENT [9] { + name: @index0 } - SELECT [10] { - IDENT [11] { - name: @index0 - }.a~presence_test + IDENT [10] { + name: @index0 } } } diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_6.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_6.baseline index 614a372a6..affa76d8c 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_6.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_6.baseline @@ -2293,30 +2293,28 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_MAP [3] { - MAP_ENTRY [4] { - key: { - CONSTANT [5] { value: "a" } - } - value: { - CONSTANT [6] { value: true } + SELECT [3] { + CREATE_MAP [4] { + MAP_ENTRY [5] { + key: { + CONSTANT [6] { value: "a" } + } + value: { + CONSTANT [7] { value: true } + } } - } + }.a~presence_test } } } - CALL [7] { + CALL [8] { function: _&&_ args: { - SELECT [8] { - IDENT [9] { - name: @index0 - }.a~presence_test + IDENT [9] { + name: @index0 } - SELECT [10] { - IDENT [11] { - name: @index0 - }.a~presence_test + IDENT [10] { + name: @index0 } } } diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_7.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_7.baseline index 773c56aa2..d962803ee 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_7.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_7.baseline @@ -2290,30 +2290,28 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_MAP [3] { - MAP_ENTRY [4] { - key: { - CONSTANT [5] { value: "a" } - } - value: { - CONSTANT [6] { value: true } + SELECT [3] { + CREATE_MAP [4] { + MAP_ENTRY [5] { + key: { + CONSTANT [6] { value: "a" } + } + value: { + CONSTANT [7] { value: true } + } } - } + }.a~presence_test } } } - CALL [7] { + CALL [8] { function: _&&_ args: { - SELECT [8] { - IDENT [9] { - name: @index0 - }.a~presence_test + IDENT [9] { + name: @index0 } - SELECT [10] { - IDENT [11] { - name: @index0 - }.a~presence_test + IDENT [10] { + name: @index0 } } } diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_8.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_8.baseline index 1d8371442..feab00f27 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_8.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_8.baseline @@ -2272,30 +2272,28 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_MAP [3] { - MAP_ENTRY [4] { - key: { - CONSTANT [5] { value: "a" } - } - value: { - CONSTANT [6] { value: true } + SELECT [3] { + CREATE_MAP [4] { + MAP_ENTRY [5] { + key: { + CONSTANT [6] { value: "a" } + } + value: { + CONSTANT [7] { value: true } + } } - } + }.a~presence_test } } } - CALL [7] { + CALL [8] { function: _&&_ args: { - SELECT [8] { - IDENT [9] { - name: @index0 - }.a~presence_test + IDENT [9] { + name: @index0 } - SELECT [10] { - IDENT [11] { - name: @index0 - }.a~presence_test + IDENT [10] { + name: @index0 } } } diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_9.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_9.baseline index cd73ba02a..03f9e8cad 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_9.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_9.baseline @@ -2260,30 +2260,28 @@ CALL [1] { args: { CREATE_LIST [2] { elements: { - CREATE_MAP [3] { - MAP_ENTRY [4] { - key: { - CONSTANT [5] { value: "a" } - } - value: { - CONSTANT [6] { value: true } + SELECT [3] { + CREATE_MAP [4] { + MAP_ENTRY [5] { + key: { + CONSTANT [6] { value: "a" } + } + value: { + CONSTANT [7] { value: true } + } } - } + }.a~presence_test } } } - CALL [7] { + CALL [8] { function: _&&_ args: { - SELECT [8] { - IDENT [9] { - name: @index0 - }.a~presence_test + IDENT [9] { + name: @index0 } - SELECT [10] { - IDENT [11] { - name: @index0 - }.a~presence_test + IDENT [10] { + name: @index0 } } } diff --git a/optimizer/src/test/resources/subexpression_ast_cascaded_binds.baseline b/optimizer/src/test/resources/subexpression_ast_cascaded_binds.baseline index 78f8c433b..aea45bde5 100644 --- a/optimizer/src/test/resources/subexpression_ast_cascaded_binds.baseline +++ b/optimizer/src/test/resources/subexpression_ast_cascaded_binds.baseline @@ -2962,38 +2962,36 @@ COMPREHENSION [1] { } accu_var: @r0 accu_init: { - CREATE_MAP [3] { - MAP_ENTRY [4] { - key: { - CONSTANT [5] { value: "a" } - } - value: { - CONSTANT [6] { value: true } + SELECT [3] { + CREATE_MAP [4] { + MAP_ENTRY [5] { + key: { + CONSTANT [6] { value: "a" } + } + value: { + CONSTANT [7] { value: true } + } } - } + }.a~presence_test } } loop_condition: { - CONSTANT [7] { value: false } + CONSTANT [8] { value: false } } loop_step: { - IDENT [8] { + IDENT [9] { name: @r0 } } result: { - CALL [9] { + CALL [10] { function: _&&_ args: { - SELECT [10] { - IDENT [11] { - name: @r0 - }.a~presence_test + IDENT [11] { + name: @r0 } - SELECT [12] { - IDENT [13] { - name: @r0 - }.a~presence_test + IDENT [12] { + name: @r0 } } } diff --git a/optimizer/src/test/resources/subexpression_unparsed.baseline b/optimizer/src/test/resources/subexpression_unparsed.baseline index b38a971aa..1c4c11f7b 100644 --- a/optimizer/src/test/resources/subexpression_unparsed.baseline +++ b/optimizer/src/test/resources/subexpression_unparsed.baseline @@ -420,7 +420,7 @@ Source: has({'a': true}.a) && {'a':true}['a'] Result: true [CASCADED_BINDS]: cel.bind(@r0, {"a": true}, has(@r0.a) && @r0["a"]) [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([{"a": true}], has(@index0.a) && @index0["a"]) -[BLOCK_RECURSION_DEPTH_1]: cel.@block([{"a": true}, @index0["a"]], has(@index0.a) && @index1) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([{"a": true}, has(@index0.a), @index0["a"]], @index1 && @index2) [BLOCK_RECURSION_DEPTH_2]: cel.@block([{"a": true}], has(@index0.a) && @index0["a"]) [BLOCK_RECURSION_DEPTH_3]: cel.@block([{"a": true}], has(@index0.a) && @index0["a"]) [BLOCK_RECURSION_DEPTH_4]: cel.@block([{"a": true}], has(@index0.a) && @index0["a"]) @@ -434,17 +434,17 @@ Test case: PRESENCE_TEST_2 Source: has({'a': true}.a) && has({'a': true}.a) =====> Result: true -[CASCADED_BINDS]: cel.bind(@r0, {"a": true}, has(@r0.a) && has(@r0.a)) -[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([{"a": true}], has(@index0.a) && has(@index0.a)) -[BLOCK_RECURSION_DEPTH_1]: cel.@block([{"a": true}], has(@index0.a) && has(@index0.a)) -[BLOCK_RECURSION_DEPTH_2]: cel.@block([{"a": true}], has(@index0.a) && has(@index0.a)) -[BLOCK_RECURSION_DEPTH_3]: cel.@block([{"a": true}], has(@index0.a) && has(@index0.a)) -[BLOCK_RECURSION_DEPTH_4]: cel.@block([{"a": true}], has(@index0.a) && has(@index0.a)) -[BLOCK_RECURSION_DEPTH_5]: cel.@block([{"a": true}], has(@index0.a) && has(@index0.a)) -[BLOCK_RECURSION_DEPTH_6]: cel.@block([{"a": true}], has(@index0.a) && has(@index0.a)) -[BLOCK_RECURSION_DEPTH_7]: cel.@block([{"a": true}], has(@index0.a) && has(@index0.a)) -[BLOCK_RECURSION_DEPTH_8]: cel.@block([{"a": true}], has(@index0.a) && has(@index0.a)) -[BLOCK_RECURSION_DEPTH_9]: cel.@block([{"a": true}], has(@index0.a) && has(@index0.a)) +[CASCADED_BINDS]: cel.bind(@r0, has({"a": true}.a), @r0 && @r0) +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([has({"a": true}.a)], @index0 && @index0) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([{"a": true}, has(@index0.a)], @index1 && @index1) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([has({"a": true}.a)], @index0 && @index0) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([has({"a": true}.a)], @index0 && @index0) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([has({"a": true}.a)], @index0 && @index0) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([has({"a": true}.a)], @index0 && @index0) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([has({"a": true}.a)], @index0 && @index0) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([has({"a": true}.a)], @index0 && @index0) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([has({"a": true}.a)], @index0 && @index0) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([has({"a": true}.a)], @index0 && @index0) Test case: PRESENCE_TEST_WITH_TERNARY Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : 0) == 10 @@ -452,7 +452,7 @@ Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : 0) Result: true [CASCADED_BINDS]: cel.bind(@r0, msg.oneof_type, has(@r0.payload) ? @r0.payload.single_int64 : 0) == 10 [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.oneof_type], (has(@index0.payload) ? @index0.payload.single_int64 : 0) == 10) -[BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64], (has(@index0.payload) ? @index2 : 0) == 10) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, has(@index0.payload), @index0.payload, @index2.single_int64, @index1 ? @index3 : 0], @index4 == 10) [BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type, @index0.payload.single_int64, has(@index0.payload) ? @index1 : 0], @index2 == 10) [BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type, has(@index0.payload) ? @index0.payload.single_int64 : 0], @index1 == 10) [BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.oneof_type], (has(@index0.payload) ? @index0.payload.single_int64 : 0) == 10) @@ -468,8 +468,8 @@ Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : msg Result: true [CASCADED_BINDS]: cel.bind(@r0, msg.oneof_type, cel.bind(@r1, @r0.payload.single_int64, has(@r0.payload) ? @r1 : (@r1 * 0))) == 10 [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.oneof_type, @index0.payload.single_int64], (has(@index0.payload) ? @index1 : (@index1 * 0)) == 10) -[BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, @index2 * 0], (has(@index0.payload) ? @index2 : @index3) == 10) -[BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type.payload, @index0.single_int64, msg.oneof_type, has(@index2.payload) ? @index1 : (@index1 * 0)], @index3 == 10) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, has(@index0.payload), @index2 * 0, @index3 ? @index2 : @index4], @index5 == 10) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type.payload, @index0.single_int64, has(msg.oneof_type.payload), @index2 ? @index1 : (@index1 * 0)], @index3 == 10) [BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type.payload.single_int64, has(msg.oneof_type.payload) ? @index0 : (@index0 * 0)], @index1 == 10) [BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.oneof_type.payload.single_int64], (has(msg.oneof_type.payload) ? @index0 : (@index0 * 0)) == 10) [BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.oneof_type.payload.single_int64], (has(msg.oneof_type.payload) ? @index0 : (@index0 * 0)) == 10) @@ -484,9 +484,9 @@ Source: (has(msg.oneof_type.payload.single_int64) ? msg.oneof_type.payload.singl Result: true [CASCADED_BINDS]: cel.bind(@r0, msg.oneof_type.payload, cel.bind(@r1, @r0.single_int64, has(@r0.single_int64) ? @r1 : (@r1 * 0))) == 10 [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.oneof_type.payload, @index0.single_int64], (has(@index0.single_int64) ? @index1 : (@index1 * 0)) == 10) -[BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, @index2 * 0], (has(@index1.single_int64) ? @index2 : @index3) == 10) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, has(@index1.single_int64), @index2 * 0, @index3 ? @index2 : @index4], @index5 == 10) [BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type.payload, @index0.single_int64, has(@index0.single_int64) ? @index1 : (@index1 * 0)], @index2 == 10) -[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type.payload.single_int64, msg.oneof_type.payload], (has(@index1.single_int64) ? @index0 : (@index0 * 0)) == 10) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type.payload.single_int64, has(msg.oneof_type.payload.single_int64)], (@index1 ? @index0 : (@index0 * 0)) == 10) [BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.oneof_type.payload.single_int64, has(msg.oneof_type.payload.single_int64) ? @index0 : (@index0 * 0)], @index1 == 10) [BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.oneof_type.payload.single_int64], (has(msg.oneof_type.payload.single_int64) ? @index0 : (@index0 * 0)) == 10) [BLOCK_RECURSION_DEPTH_6]: cel.@block([msg.oneof_type.payload.single_int64], (has(msg.oneof_type.payload.single_int64) ? @index0 : (@index0 * 0)) == 10) @@ -500,8 +500,8 @@ Source: (has(msg.oneof_type) && has(msg.oneof_type.payload) && has(msg.oneof_typ Result: true [CASCADED_BINDS]: cel.bind(@r0, msg.oneof_type, cel.bind(@r1, @r0.payload, (has(msg.oneof_type) && has(@r0.payload) && has(@r1.single_int64)) ? cel.bind(@r2, @r1.map_string_string, (has(@r1.map_string_string) && has(@r2.key)) ? (@r2.key == "A") : false) : false)) [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_string_string], (has(msg.oneof_type) && has(@index0.payload) && has(@index1.single_int64)) ? ((has(@index1.map_string_string) && has(@index2.key)) ? (@index2.key == "A") : false) : false) -[BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_string_string, @index2.key, @index3 == "A"], (has(msg.oneof_type) && has(@index0.payload) && has(@index1.single_int64)) ? ((has(@index1.map_string_string) && has(@index2.key)) ? @index4 : false) : false) -[BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type.payload, @index0.map_string_string, has(@index0.map_string_string) && has(@index1.key), @index1.key == "A", msg.oneof_type, has(msg.oneof_type) && has(@index4.payload), @index5 && has(@index0.single_int64)], @index6 ? (@index2 ? @index3 : false) : false) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_string_string, has(msg.oneof_type), has(@index0.payload), @index3 && @index4, has(@index1.single_int64), @index5 && @index6, has(@index1.map_string_string), has(@index2.key), @index8 && @index9, @index2.key, @index11 == "A", @index10 ? @index12 : false], @index7 ? @index13 : false) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type.payload, @index0.map_string_string, has(msg.oneof_type.payload), has(msg.oneof_type) && @index2, @index3 && has(@index0.single_int64), has(@index0.map_string_string) && has(@index1.key), @index1.key == "A"], @index4 ? (@index5 ? @index6 : false) : false) [BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type.payload.map_string_string, msg.oneof_type.payload, has(msg.oneof_type) && has(msg.oneof_type.payload), (has(@index1.map_string_string) && has(@index0.key)) ? (@index0.key == "A") : false], (@index2 && has(@index1.single_int64)) ? @index3 : false) [BLOCK_RECURSION_DEPTH_4]: cel.@block([msg.oneof_type.payload.map_string_string, msg.oneof_type.payload, has(msg.oneof_type) && has(msg.oneof_type.payload) && has(@index1.single_int64)], @index2 ? ((has(@index1.map_string_string) && has(@index0.key)) ? (@index0.key == "A") : false) : false) [BLOCK_RECURSION_DEPTH_5]: cel.@block([msg.oneof_type.payload.map_string_string, msg.oneof_type.payload], (has(msg.oneof_type) && has(msg.oneof_type.payload) && has(@index1.single_int64)) ? ((has(@index1.map_string_string) && has(@index0.key)) ? (@index0.key == "A") : false) : false) From 4fce8efd0e24fc29f241ed87412a4c219ac86723 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Mon, 22 Apr 2024 14:39:31 -0700 Subject: [PATCH 095/486] Remove maven artifacts for optimizer, validator and extensions PiperOrigin-RevId: 627160425 --- publish/BUILD.bazel | 66 --------------------------------------------- publish/publish.sh | 2 +- 2 files changed, 1 insertion(+), 67 deletions(-) diff --git a/publish/BUILD.bazel b/publish/BUILD.bazel index a07bed4d0..050292eab 100644 --- a/publish/BUILD.bazel +++ b/publish/BUILD.bazel @@ -126,72 +126,6 @@ java_export( runtime_deps = RUNTIME_TARGETS, ) -pom_file( - name = "cel_extensions_pom", - substitutions = { - "CEL_VERSION": CEL_VERSION, - "CEL_ARTIFACT_ID": "extensions", - "PACKAGE_NAME": "CEL Java Extensions", - "PACKAGE_DESC": "Common Expression Language Extensions for Java", - }, - targets = EXTENSION_TARGETS, - template_file = "pom_template.xml", -) - -java_export( - name = "cel_extensions", - deploy_env = [ - "@com_google_googleapis//google/api/expr/v1alpha1:expr_java_proto", - ], - maven_coordinates = "dev.cel:extensions:%s" % CEL_VERSION, - pom_template = ":cel_extensions_pom", - runtime_deps = EXTENSION_TARGETS, -) - -pom_file( - name = "cel_validators_pom", - substitutions = { - "CEL_VERSION": CEL_VERSION, - "CEL_ARTIFACT_ID": "validators", - "PACKAGE_NAME": "CEL Java Validators", - "PACKAGE_DESC": "Common Expression Language Validators for Java", - }, - targets = VALIDATOR_TARGETS, - template_file = "pom_template.xml", -) - -java_export( - name = "cel_validators", - deploy_env = [ - "@com_google_googleapis//google/api/expr/v1alpha1:expr_java_proto", - ], - maven_coordinates = "dev.cel:validators:%s" % CEL_VERSION, - pom_template = ":cel_validators_pom", - runtime_deps = VALIDATOR_TARGETS, -) - -pom_file( - name = "cel_optimizers_pom", - substitutions = { - "CEL_VERSION": CEL_VERSION, - "CEL_ARTIFACT_ID": "optimizers", - "PACKAGE_NAME": "CEL Java Optimizers", - "PACKAGE_DESC": "Common Expression Language Optimizers for Java", - }, - targets = OPTIMIZER_TARGETS, - template_file = "pom_template.xml", -) - -java_export( - name = "cel_optimizers", - deploy_env = [ - "@com_google_googleapis//google/api/expr/v1alpha1:expr_java_proto", - ], - maven_coordinates = "dev.cel:optimizers:%s" % CEL_VERSION, - pom_template = ":cel_optimizers_pom", - runtime_deps = OPTIMIZER_TARGETS, -) - pom_file( name = "cel_v1alpha1_pom", substitutions = { diff --git a/publish/publish.sh b/publish/publish.sh index 0814b16df..b5d301ce2 100755 --- a/publish/publish.sh +++ b/publish/publish.sh @@ -25,7 +25,7 @@ # 2. You will need to enter the key's password. The prompt appears in GUI, not in terminal. The publish operation will eventually timeout if the password is not entered. -ALL_TARGETS=("//publish:cel.publish" "//publish:cel_compiler.publish" "//publish:cel_runtime.publish" "//publish:cel_extensions.publish" "//publish:cel_optimizers.publish" "//publish:cel_validators.publish" "//publish:cel_v1alpha1.publish") +ALL_TARGETS=("//publish:cel.publish" "//publish:cel_compiler.publish" "//publish:cel_runtime.publish" "//publish:cel_v1alpha1.publish") function publish_maven_remote() { maven_repo_url=$1 From b5b6eaba5a9ef0ef39987a3ca9ed53d7749b2e2e Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Tue, 23 Apr 2024 16:36:39 -0700 Subject: [PATCH 096/486] Update bazel WORKSPACE dependencies PiperOrigin-RevId: 627541307 --- WORKSPACE | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/WORKSPACE b/WORKSPACE index f7b21a719..e965fca90 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -52,29 +52,29 @@ load("@rules_jvm_external//:setup.bzl", "rules_jvm_external_setup") rules_jvm_external_setup() -ANTLR4_VERSION = "4.11.1" +ANTLR4_VERSION = "4.13.1" # Important: there can only be one maven_install rule. Add new maven deps here. maven_install( # keep sorted artifacts = [ - "com.google.api.grpc:proto-google-common-protos:2.27.0", + "com.google.api.grpc:proto-google-common-protos:2.38.0", "com.google.auto.value:auto-value:1.10.4", "com.google.auto.value:auto-value-annotations:1.10.4", "com.google.code.findbugs:annotations:3.0.1", - "com.google.errorprone:error_prone_annotations:2.23.0", - "com.google.guava:guava:33.0.0-jre", - "com.google.guava:guava-testlib:33.0.0-jre", - "com.google.protobuf:protobuf-java:3.24.4", - "com.google.protobuf:protobuf-java-util:3.24.4", + "com.google.errorprone:error_prone_annotations:2.26.1", + "com.google.guava:guava:33.1.0-jre", + "com.google.guava:guava-testlib:33.1.0-jre", + "com.google.protobuf:protobuf-java:3.25.3", + "com.google.protobuf:protobuf-java-util:3.25.3", "com.google.re2j:re2j:1.7", "com.google.testparameterinjector:test-parameter-injector:1.15", - "com.google.truth.extensions:truth-java8-extension:1.4.0", - "com.google.truth.extensions:truth-proto-extension:1.4.0", - "com.google.truth:truth:1.4.0", + "com.google.truth.extensions:truth-java8-extension:1.4.2", + "com.google.truth.extensions:truth-proto-extension:1.4.2", + "com.google.truth:truth:1.4.2", "org.antlr:antlr4-runtime:" + ANTLR4_VERSION, "org.jspecify:jspecify:0.2.0", - "org.threeten:threeten-extra:1.7.2", + "org.threeten:threeten-extra:1.8.0", ], repositories = [ "https://maven.google.com", @@ -138,10 +138,10 @@ http_archive( # cel-spec api/expr canonical protos http_archive( name = "cel_spec", - sha256 = "3579c97b13548714f9059ef6f30c5264d439efef4b438e76e7180709efd93a6b", - strip_prefix = "cel-spec-0.14.0", + sha256 = "3ee09eb69dbe77722e9dee23dc48dc2cd9f765869fcf5ffb1226587c81791a0b", + strip_prefix = "cel-spec-0.15.0", urls = [ - "https://github.com/google/cel-spec/archive/refs/tags/v0.14.0.tar.gz", + "https://github.com/google/cel-spec/archive/refs/tags/v0.15.0.tar.gz", ], ) @@ -157,7 +157,7 @@ http_archive( http_jar( name = "antlr4_jar", - sha256 = "62975e192b4af2622b72b5f0131553ee3cbce97f76dc2a41632dcc55e25473e1", + sha256 = "bc13a9c57a8dd7d5196888211e5ede657cb64a3ce968608697e4f668251a8487", urls = ["https://www.antlr.org/download/antlr-" + ANTLR4_VERSION + "-complete.jar"], ) From ec41e7e36457697906d05102ad5afc329f86fd50 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Wed, 24 Apr 2024 10:02:04 -0700 Subject: [PATCH 097/486] Change CelAstOptimizer interface signature. Cleanup unused methods. PiperOrigin-RevId: 627764180 --- .../main/java/dev/cel/common/ast/CelExpr.java | 1 + .../java/dev/cel/optimizer/AstMutator.java | 89 ------------------- .../main/java/dev/cel/optimizer/BUILD.bazel | 2 - .../dev/cel/optimizer/CelAstOptimizer.java | 4 +- .../dev/cel/optimizer/CelOptimizerImpl.java | 4 +- .../dev/cel/optimizer/MutableExprVisitor.java | 21 ----- .../dev/cel/optimizer/optimizers/BUILD.bazel | 2 +- .../optimizers/ConstantFoldingOptimizer.java | 7 +- .../optimizers/SubexpressionOptimizer.java | 7 +- .../cel/optimizer/CelOptimizerImplTest.java | 16 ++-- .../dev/cel/optimizer/optimizers/BUILD.bazel | 4 +- .../SubexpressionOptimizerTest.java | 75 ++++++---------- 12 files changed, 45 insertions(+), 187 deletions(-) diff --git a/common/src/main/java/dev/cel/common/ast/CelExpr.java b/common/src/main/java/dev/cel/common/ast/CelExpr.java index 3970c8598..2ea228268 100644 --- a/common/src/main/java/dev/cel/common/ast/CelExpr.java +++ b/common/src/main/java/dev/cel/common/ast/CelExpr.java @@ -38,6 +38,7 @@ @AutoValue @Internal @Immutable +@SuppressWarnings("unchecked") // Class ensures only the super type is used public abstract class CelExpr implements Expression { @Override diff --git a/optimizer/src/main/java/dev/cel/optimizer/AstMutator.java b/optimizer/src/main/java/dev/cel/optimizer/AstMutator.java index ab38af797..87942d2bd 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/AstMutator.java +++ b/optimizer/src/main/java/dev/cel/optimizer/AstMutator.java @@ -55,7 +55,6 @@ /** AstMutator contains logic for mutating a {@link CelAbstractSyntaxTree}. */ @Immutable -@SuppressWarnings("InlineMeSuggester") // Deprecated methods are not used and will be removed. public final class AstMutator { private static final ExprIdGenerator NO_OP_ID_GENERATOR = id -> id; private static final ExprIdGenerator UNSET_ID_GENERATOR = id -> 0; @@ -80,39 +79,11 @@ private AstMutator(long iterationLimit) { this.iterationLimit = iterationLimit; } - /** - * TODO: Temporarily kept to retain method signature. Remove in the upcoming CLs. - * - * @deprecated Use MutableExpr based APIs instead. - */ - @Deprecated - public CelExpr clearExprIds(CelExpr expr) { - return CelMutableExprConverter.fromMutableExpr( - clearExprIds(CelMutableExprConverter.fromCelExpr(expr))); - } - /** Replaces all the expression IDs in the expression tree with 0. */ public CelMutableExpr clearExprIds(CelMutableExpr expr) { return renumberExprIds(UNSET_ID_GENERATOR, expr); } - /** - * TODO: Temporarily kept to retain method signature. Remove in the upcoming CLs. - * - * @deprecated Use MutableExpr based APIs instead. - */ - @Deprecated - public CelAbstractSyntaxTree wrapAstWithNewCelBlock( - String celBlockFunction, CelAbstractSyntaxTree ast, List subexpressions) { - return wrapAstWithNewCelBlock( - celBlockFunction, - CelMutableAst.fromCelAst(ast), - subexpressions.stream() - .map(CelMutableExprConverter::fromCelExpr) - .collect(toCollection(ArrayList::new))) - .toParsedAst(); - } - /** Wraps the given AST and its subexpressions with a new cel.@block call. */ public CelMutableAst wrapAstWithNewCelBlock( String celBlockFunction, CelMutableAst ast, List subexpressions) { @@ -128,24 +99,6 @@ public CelMutableAst wrapAstWithNewCelBlock( return CelMutableAst.of(blockExpr, ast.source()); } - /** - * TODO: Temporarily kept to retain method signature. Remove in the upcoming CLs. - * - * @deprecated Use MutableExpr based APIs instead. - */ - @Deprecated - public CelAbstractSyntaxTree replaceSubtreeWithNewBindMacro( - CelAbstractSyntaxTree ast, String varName, CelExpr varInit, CelExpr resultExpr, long id) { - return replaceSubtreeWithNewBindMacro( - CelMutableAst.fromCelAst(ast), - varName, - CelMutableExprConverter.fromCelExpr(varInit), - CelMutableExprConverter.fromCelExpr(resultExpr), - id, - true) - .toParsedAst(); - } - /** * Generates a new bind macro using the provided initialization and result expression, then * replaces the subtree using the new bind expr at the designated expr ID. @@ -195,10 +148,6 @@ public CelMutableAst replaceSubtreeWithNewBindMacro( return replaceSubtree(ast, newBindAst, exprIdToReplace); } - public CelAbstractSyntaxTree renumberIdsConsecutively(CelAbstractSyntaxTree ast) { - return renumberIdsConsecutively(CelMutableAst.fromCelAst(ast)).toParsedAst(); - } - /** Renumbers all the expr IDs in the given AST in a consecutive manner starting from 1. */ public CelMutableAst renumberIdsConsecutively(CelMutableAst mutableAst) { StableIdGenerator stableIdGenerator = CelExprIdGeneratorFactory.newStableIdGenerator(0); @@ -385,34 +334,6 @@ public MangledComprehensionAst mangleComprehensionIdentifierNames( ImmutableMap.copyOf(mangledIdentNamesToType)); } - /** - * TODO: Temporarily kept to retain method signature. Remove in the upcoming CLs. - * - * @deprecated Use MutableExpr based APIs instead. - */ - @Deprecated - public CelExpr replaceSubtree(CelExpr celExpr, CelExpr newExpr, long id) { - return replaceSubtree( - CelMutableExprConverter.fromCelExpr(celExpr), - CelMutableExprConverter.fromCelExpr(newExpr), - id) - .toParsedAst() - .getExpr(); - } - - /** - * TODO: Temporarily kept to retain method signature. Remove in the upcoming CLs. - * - * @deprecated Use MutableExpr based APIs instead. - */ - @Deprecated - public CelAbstractSyntaxTree replaceSubtree( - CelAbstractSyntaxTree root, CelExpr newExpr, long id) { - return replaceSubtree( - CelMutableAst.fromCelAst(root), CelMutableExprConverter.fromCelExpr(newExpr), id) - .toParsedAst(); - } - /** * Replaces a subtree in the given expression node. This operation is intended for AST * optimization purposes. @@ -948,16 +869,6 @@ public abstract static class MangledComprehensionAst { public abstract ImmutableMap mangledComprehensionMap(); - /** - * TODO: Temporarily kept to retain method signature. Remove in the upcoming CLs. - * - * @deprecated Use MutableExpr based APIs instead. - */ - @Deprecated - public CelAbstractSyntaxTree ast() { - return mutableAst().toParsedAst(); - } - private static MangledComprehensionAst of( CelMutableAst ast, ImmutableMap mangledComprehensionMap) { diff --git a/optimizer/src/main/java/dev/cel/optimizer/BUILD.bazel b/optimizer/src/main/java/dev/cel/optimizer/BUILD.bazel index d7833098f..9ddbf2f8a 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/BUILD.bazel +++ b/optimizer/src/main/java/dev/cel/optimizer/BUILD.bazel @@ -55,7 +55,6 @@ java_library( "//bundle:cel", "//common", "//common:compiler_common", - "//common/navigation", "@maven//:com_google_guava_guava", ], ) @@ -71,7 +70,6 @@ java_library( "//bundle:cel", "//common", "//common:compiler_common", - "//common/navigation", "@maven//:com_google_guava_guava", ], ) diff --git a/optimizer/src/main/java/dev/cel/optimizer/CelAstOptimizer.java b/optimizer/src/main/java/dev/cel/optimizer/CelAstOptimizer.java index 0d2edc4b5..7a14f0f70 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/CelAstOptimizer.java +++ b/optimizer/src/main/java/dev/cel/optimizer/CelAstOptimizer.java @@ -20,14 +20,12 @@ import dev.cel.common.CelAbstractSyntaxTree; import dev.cel.common.CelFunctionDecl; import dev.cel.common.CelVarDecl; -import dev.cel.common.navigation.CelNavigableAst; /** Public interface for performing a single, custom optimization on an AST. */ public interface CelAstOptimizer { /** Optimizes a single AST. */ - OptimizationResult optimize(CelNavigableAst navigableAst, Cel cel) - throws CelOptimizationException; + OptimizationResult optimize(CelAbstractSyntaxTree ast, Cel cel) throws CelOptimizationException; /** * Denotes the result of a single optimization pass on an AST. diff --git a/optimizer/src/main/java/dev/cel/optimizer/CelOptimizerImpl.java b/optimizer/src/main/java/dev/cel/optimizer/CelOptimizerImpl.java index 136788d83..4ac8764f1 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/CelOptimizerImpl.java +++ b/optimizer/src/main/java/dev/cel/optimizer/CelOptimizerImpl.java @@ -20,7 +20,6 @@ import dev.cel.bundle.Cel; import dev.cel.common.CelAbstractSyntaxTree; import dev.cel.common.CelValidationException; -import dev.cel.common.navigation.CelNavigableAst; import dev.cel.optimizer.CelAstOptimizer.OptimizationResult; import java.util.Arrays; @@ -43,8 +42,7 @@ public CelAbstractSyntaxTree optimize(CelAbstractSyntaxTree ast) throws CelOptim CelAbstractSyntaxTree optimizedAst = ast; try { for (CelAstOptimizer optimizer : astOptimizers) { - CelNavigableAst navigableAst = CelNavigableAst.fromAst(optimizedAst); - OptimizationResult result = optimizer.optimize(navigableAst, celOptimizerEnv); + OptimizationResult result = optimizer.optimize(optimizedAst, celOptimizerEnv); if (!result.newFunctionDecls().isEmpty() || !result.newVarDecls().isEmpty()) { celOptimizerEnv = celOptimizerEnv diff --git a/optimizer/src/main/java/dev/cel/optimizer/MutableExprVisitor.java b/optimizer/src/main/java/dev/cel/optimizer/MutableExprVisitor.java index ea751313a..e5109eef0 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/MutableExprVisitor.java +++ b/optimizer/src/main/java/dev/cel/optimizer/MutableExprVisitor.java @@ -17,7 +17,6 @@ import com.google.common.base.Preconditions; import com.google.errorprone.annotations.CanIgnoreReturnValue; import dev.cel.common.annotations.Internal; -import dev.cel.common.ast.CelExpr; import dev.cel.common.ast.CelExprIdGeneratorFactory.ExprIdGenerator; import dev.cel.common.ast.CelMutableExpr; import dev.cel.common.ast.CelMutableExpr.CelMutableCall; @@ -26,7 +25,6 @@ import dev.cel.common.ast.CelMutableExpr.CelMutableCreateMap; import dev.cel.common.ast.CelMutableExpr.CelMutableCreateStruct; import dev.cel.common.ast.CelMutableExpr.CelMutableSelect; -import dev.cel.common.ast.CelMutableExprConverter; import java.util.List; /** @@ -44,19 +42,6 @@ final class MutableExprVisitor { private int iterationCount; private long exprIdToReplace; - /** TODO: Temporarily kept to retain method signature. Remove in the upcoming CLs. */ - static MutableExprVisitor newInstance( - ExprIdGenerator idGenerator, - CelExpr.Builder newExpr, - long exprIdToReplace, - long iterationLimit) { - return newInstance( - idGenerator, - CelMutableExprConverter.fromCelExpr(newExpr.build()), - exprIdToReplace, - iterationLimit); - } - static MutableExprVisitor newInstance( ExprIdGenerator idGenerator, CelMutableExpr newExpr, @@ -67,12 +52,6 @@ static MutableExprVisitor newInstance( return new MutableExprVisitor(idGenerator, newExpr, exprIdToReplace, iterationLimit * 2); } - /** TODO: Temporarily kept to retain method signature. Remove in the upcoming CLs. */ - CelExpr.Builder visit(CelExpr.Builder root) { - CelMutableExpr mutatedRoot = visit(CelMutableExprConverter.fromCelExpr(root.build())); - return CelMutableExprConverter.fromMutableExpr(mutatedRoot).toBuilder(); - } - CelMutableExpr visit(CelMutableExpr root) { if (++iterationCount > iterationLimit) { throw new IllegalStateException("Max iteration count reached."); diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel b/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel index 95acee0f9..409421e08 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel @@ -16,11 +16,11 @@ java_library( deps = [ "//:auto_value", "//bundle:cel", + "//common", "//common:compiler_common", "//common/ast", "//common/ast:expr_util", "//common/ast:mutable_ast", - "//common/navigation", "//common/navigation:mutable_navigation", "//extensions:optional_library", "//optimizer:ast_optimizer", diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java b/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java index 4c9492a09..fd17df9d6 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java @@ -19,6 +19,7 @@ import com.google.auto.value.AutoValue; import com.google.common.collect.ImmutableList; import dev.cel.bundle.Cel; +import dev.cel.common.CelAbstractSyntaxTree; import dev.cel.common.CelValidationException; import dev.cel.common.ast.CelConstant; import dev.cel.common.ast.CelExpr.ExprKind.Kind; @@ -30,7 +31,6 @@ import dev.cel.common.ast.CelMutableExpr.CelMutableCreateMap; import dev.cel.common.ast.CelMutableExpr.CelMutableCreateStruct; import dev.cel.common.ast.CelMutableExprConverter; -import dev.cel.common.navigation.CelNavigableAst; import dev.cel.common.navigation.CelNavigableMutableAst; import dev.cel.common.navigation.CelNavigableMutableExpr; import dev.cel.extensions.CelOptionalLibrary.Function; @@ -79,8 +79,9 @@ private static CelMutableExpr newOptionalNoneExpr() { } @Override - public OptimizationResult optimize(CelNavigableAst ast, Cel cel) throws CelOptimizationException { - CelMutableAst mutableAst = CelMutableAst.fromCelAst(ast.getAst()); + public OptimizationResult optimize(CelAbstractSyntaxTree ast, Cel cel) + throws CelOptimizationException { + CelMutableAst mutableAst = CelMutableAst.fromCelAst(ast); int iterCount = 0; boolean continueFolding = true; while (continueFolding) { diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java index a71e83912..28151ff4e 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java @@ -45,7 +45,6 @@ import dev.cel.common.ast.CelMutableAst; import dev.cel.common.ast.CelMutableExpr; import dev.cel.common.ast.CelMutableExprConverter; -import dev.cel.common.navigation.CelNavigableAst; import dev.cel.common.navigation.CelNavigableExpr; import dev.cel.common.navigation.CelNavigableMutableAst; import dev.cel.common.navigation.CelNavigableMutableExpr; @@ -129,11 +128,9 @@ public static SubexpressionOptimizer newInstance(SubexpressionOptimizerOptions c } @Override - public OptimizationResult optimize(CelNavigableAst ast, Cel cel) { + public OptimizationResult optimize(CelAbstractSyntaxTree ast, Cel cel) { OptimizationResult result = - cseOptions.enableCelBlock() - ? optimizeUsingCelBlock(ast.getAst(), cel) - : optimizeUsingCelBind(ast.getAst()); + cseOptions.enableCelBlock() ? optimizeUsingCelBlock(ast, cel) : optimizeUsingCelBind(ast); verifyOptimizedAstCorrectness(result.optimizedAst()); diff --git a/optimizer/src/test/java/dev/cel/optimizer/CelOptimizerImplTest.java b/optimizer/src/test/java/dev/cel/optimizer/CelOptimizerImplTest.java index 23ffc192a..570233dd6 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/CelOptimizerImplTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/CelOptimizerImplTest.java @@ -40,9 +40,9 @@ public void constructCelOptimizer_success() { CelOptimizer celOptimizer = CelOptimizerImpl.newBuilder(CEL) .addAstOptimizers( - (navigableAst, cel) -> + (ast, cel) -> // no-op - OptimizationResult.create(navigableAst.getAst())) + OptimizationResult.create(ast)) .build(); assertThat(celOptimizer).isNotNull(); @@ -56,19 +56,19 @@ public void astOptimizers_invokedInOrder() throws Exception { CelOptimizer celOptimizer = CelOptimizerImpl.newBuilder(CEL) .addAstOptimizers( - (navigableAst, cel) -> { + (ast, cel) -> { list.add(1); - return OptimizationResult.create(navigableAst.getAst()); + return OptimizationResult.create(ast); }) .addAstOptimizers( - (navigableAst, cel) -> { + (ast, cel) -> { list.add(2); - return OptimizationResult.create(navigableAst.getAst()); + return OptimizationResult.create(ast); }) .addAstOptimizers( - (navigableAst, cel) -> { + (ast, cel) -> { list.add(3); - return OptimizationResult.create(navigableAst.getAst()); + return OptimizationResult.create(ast); }) .build(); diff --git a/optimizer/src/test/java/dev/cel/optimizer/optimizers/BUILD.bazel b/optimizer/src/test/java/dev/cel/optimizer/optimizers/BUILD.bazel index 5973bca8e..17389a5a5 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/optimizers/BUILD.bazel +++ b/optimizer/src/test/java/dev/cel/optimizer/optimizers/BUILD.bazel @@ -14,13 +14,13 @@ java_library( "//common:compiler_common", "//common:options", "//common/ast", - "//common/navigation", + "//common/ast:mutable_ast", + "//common/navigation:mutable_navigation", "//common/resources/testdata/proto3:test_all_types_java_proto", "//common/types", "//extensions", "//extensions:optional_library", "//optimizer", - "//optimizer:mutable_ast", "//optimizer:optimization_exception", "//optimizer:optimizer_builder", "//optimizer/optimizers:common_subexpression_elimination", diff --git a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java index 6eb4a2f52..a174238d9 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java @@ -39,13 +39,13 @@ import dev.cel.common.ast.CelConstant; import dev.cel.common.ast.CelExpr; import dev.cel.common.ast.CelExpr.ExprKind.Kind; -import dev.cel.common.navigation.CelNavigableAst; -import dev.cel.common.navigation.CelNavigableExpr; +import dev.cel.common.ast.CelMutableAst; +import dev.cel.common.navigation.CelNavigableMutableAst; +import dev.cel.common.navigation.CelNavigableMutableExpr; import dev.cel.common.types.ListType; import dev.cel.common.types.SimpleType; import dev.cel.common.types.StructTypeReference; import dev.cel.extensions.CelExtensions; -import dev.cel.optimizer.AstMutator; import dev.cel.optimizer.CelOptimizationException; import dev.cel.optimizer.CelOptimizer; import dev.cel.optimizer.CelOptimizerFactory; @@ -555,53 +555,28 @@ public void verifyOptimizedAstCorrectness_indexIsNotForwardReferencing_throws(St */ private static CelAbstractSyntaxTree compileUsingInternalFunctions(String expression) throws CelValidationException { - AstMutator astMutator = AstMutator.newInstance(1000); CelAbstractSyntaxTree astToModify = CEL_FOR_EVALUATING_BLOCK.compile(expression).getAst(); - while (true) { - CelExpr celExpr = - CelNavigableAst.fromAst(astToModify) - .getRoot() - .allNodes() - .filter(node -> node.getKind().equals(Kind.CALL)) - .map(CelNavigableExpr::expr) - .filter(expr -> expr.call().function().equals("cel.block")) - .findAny() - .orElse(null); - if (celExpr == null) { - break; - } - astToModify = - astMutator.replaceSubtree( - astToModify, - celExpr.toBuilder() - .setCall(celExpr.call().toBuilder().setFunction("cel.@block").build()) - .build(), - celExpr.id()); - } - - while (true) { - CelExpr celExpr = - CelNavigableAst.fromAst(astToModify) - .getRoot() - .allNodes() - .filter(node -> node.getKind().equals(Kind.IDENT)) - .map(CelNavigableExpr::expr) - .filter(expr -> expr.ident().name().startsWith("index")) - .findAny() - .orElse(null); - if (celExpr == null) { - break; - } - String internalIdentName = "@" + celExpr.ident().name(); - astToModify = - astMutator.replaceSubtree( - astToModify, - celExpr.toBuilder() - .setIdent(celExpr.ident().toBuilder().setName(internalIdentName).build()) - .build(), - celExpr.id()); - } - - return CEL_FOR_EVALUATING_BLOCK.check(astToModify).getAst(); + CelMutableAst mutableAst = CelMutableAst.fromCelAst(astToModify); + CelNavigableMutableAst.fromAst(mutableAst) + .getRoot() + .allNodes() + .filter(node -> node.getKind().equals(Kind.CALL)) + .map(CelNavigableMutableExpr::expr) + .filter(expr -> expr.call().function().equals("cel.block")) + .forEach(expr -> expr.call().setFunction("cel.@block")); + + CelNavigableMutableAst.fromAst(mutableAst) + .getRoot() + .allNodes() + .filter(node -> node.getKind().equals(Kind.IDENT)) + .map(CelNavigableMutableExpr::expr) + .filter(expr -> expr.ident().name().startsWith("index")) + .forEach( + indexExpr -> { + String internalIdentName = "@" + indexExpr.ident().name(); + indexExpr.ident().setName(internalIdentName); + }); + + return CEL_FOR_EVALUATING_BLOCK.check(mutableAst.toParsedAst()).getAst(); } } From 91b20d59d7cee3df014f9376b4e6db53da115992 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Wed, 24 Apr 2024 10:13:04 -0700 Subject: [PATCH 098/486] Improve canEliminate logic by excluding nodes from ineligible comprehension branches PiperOrigin-RevId: 627768195 --- .../dev/cel/common/ast/CelMutableExpr.java | 5 ++ .../optimizers/SubexpressionOptimizer.java | 72 +++++++++++-------- 2 files changed, 46 insertions(+), 31 deletions(-) diff --git a/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java b/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java index 0a44f4234..f83021b0b 100644 --- a/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java +++ b/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java @@ -1148,6 +1148,11 @@ public boolean equals(Object obj) { return false; } + @Override + public String toString() { + return CelMutableExprConverter.fromMutableExpr(this).toString(); + } + @Override public int hashCode() { int h = 1; diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java index 28151ff4e..311ce34de 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java @@ -18,6 +18,7 @@ import static com.google.common.collect.ImmutableList.toImmutableList; import static com.google.common.collect.ImmutableSet.toImmutableSet; import static java.util.Arrays.stream; +import static java.util.stream.Collectors.toCollection; import com.google.auto.value.AutoValue; import com.google.common.annotations.VisibleForTesting; @@ -65,6 +66,7 @@ import java.util.HashSet; import java.util.List; import java.util.Optional; +import java.util.Set; /** * Performs Common Subexpression Elimination. @@ -469,11 +471,12 @@ private List getCseCandidates(CelNavigableMutableAst navAst) { private List getCseCandidatesWithRecursionDepth( CelNavigableMutableAst navAst, int recursionLimit) { Preconditions.checkArgument(recursionLimit > 0); + Set ineligibleExprs = getIneligibleExprsFromComprehensionBranches(navAst); ImmutableList descendants = navAst .getRoot() .descendants(TraversalOrder.PRE_ORDER) - .filter(this::canEliminate) + .filter(node -> canEliminate(node, ineligibleExprs)) .filter(node -> node.height() <= recursionLimit) .sorted(Comparator.comparingInt(CelNavigableMutableExpr::height).reversed()) .collect(toImmutableList()); @@ -494,7 +497,7 @@ private List getCseCandidatesWithRecursionDepth( .getRoot() .allNodes(TraversalOrder.POST_ORDER) .filter(node -> node.height() > recursionLimit) - .anyMatch(this::canEliminate); + .anyMatch(node -> canEliminate(node, ineligibleExprs)); if (astHasMoreExtractableSubexprs) { cseCandidates.add(descendants.get(0).expr()); return cseCandidates; @@ -506,11 +509,12 @@ private List getCseCandidatesWithRecursionDepth( } private List getCseCandidatesWithCommonSubexpr(CelNavigableMutableAst navAst) { + Set ineligibleExprs = getIneligibleExprsFromComprehensionBranches(navAst); ImmutableList allNodes = navAst .getRoot() .allNodes(TraversalOrder.PRE_ORDER) - .filter(this::canEliminate) + .filter(node -> canEliminate(node, ineligibleExprs)) .collect(toImmutableList()); return getCseCandidatesWithCommonSubexpr(allNodes); @@ -547,42 +551,48 @@ private List getCseCandidatesWithCommonSubexpr( return cseCandidates; } - private boolean canEliminate(CelNavigableMutableExpr navigableExpr) { + private boolean canEliminate( + CelNavigableMutableExpr navigableExpr, Set ineligibleExprs) { return !navigableExpr.getKind().equals(Kind.CONSTANT) && !navigableExpr.getKind().equals(Kind.IDENT) && !(navigableExpr.getKind().equals(Kind.IDENT) && navigableExpr.expr().ident().name().startsWith(BIND_IDENTIFIER_PREFIX)) + // Exclude empty lists (cel.bind sets this for iterRange). + && !(navigableExpr.getKind().equals(Kind.CREATE_LIST) + && navigableExpr.expr().createList().elements().isEmpty()) && containsEliminableFunctionOnly(navigableExpr) - && isWithinInlineableComprehension(navigableExpr); + && !ineligibleExprs.contains(navigableExpr.expr()); } - private static boolean isWithinInlineableComprehension(CelNavigableMutableExpr expr) { - Optional maybeParent = expr.parent(); - while (maybeParent.isPresent()) { - CelNavigableMutableExpr parent = maybeParent.get(); - if (parent.getKind().equals(Kind.COMPREHENSION)) { - return Streams.concat( - // If the expression is within a comprehension, it is eligible for CSE iff is in - // result, loopStep or iterRange. While result is not human authored, it needs to be - // included to extract subexpressions that are already in cel.bind macro. - CelNavigableMutableExpr.fromExpr(parent.expr().comprehension().result()) - .descendants(), - CelNavigableMutableExpr.fromExpr(parent.expr().comprehension().loopStep()) - .allNodes(), - CelNavigableMutableExpr.fromExpr(parent.expr().comprehension().iterRange()) - .allNodes()) - .filter( - node -> - // Exclude empty lists (cel.bind sets this for iterRange). - !node.getKind().equals(Kind.CREATE_LIST) - || !node.expr().createList().elements().isEmpty()) - .map(CelNavigableMutableExpr::expr) - .anyMatch(node -> node.equals(expr.expr())); - } - maybeParent = parent.parent(); - } + /** + * Collects a set of nodes that are not eligible to be optimized from comprehension branches. + * + *

All nodes from accumulator initializer and loop condition are not eligible to be optimized + * as that can interfere with scoping of shadowed variables. + */ + private static Set getIneligibleExprsFromComprehensionBranches( + CelNavigableMutableAst navAst) { + HashSet ineligibleExprs = new HashSet<>(); + navAst + .getRoot() + .allNodes() + .filter(node -> node.getKind().equals(Kind.COMPREHENSION)) + .forEach( + node -> { + Set nodes = + Streams.concat( + CelNavigableMutableExpr.fromExpr(node.expr().comprehension().accuInit()) + .allNodes(), + CelNavigableMutableExpr.fromExpr( + node.expr().comprehension().loopCondition()) + .allNodes()) + .map(CelNavigableMutableExpr::expr) + .collect(toCollection(HashSet::new)); + + ineligibleExprs.addAll(nodes); + }); - return true; + return ineligibleExprs; } private boolean containsEliminableFunctionOnly(CelNavigableMutableExpr navigableExpr) { From 20eab0e568a7951ee78d8d28ff4262de7a490bae Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Wed, 24 Apr 2024 10:54:48 -0700 Subject: [PATCH 099/486] Change AstMutator to augment macro source using mutable expr PiperOrigin-RevId: 627782261 --- common/BUILD.bazel | 10 ++ common/ast/BUILD.bazel | 4 +- .../src/main/java/dev/cel/common/BUILD.bazel | 28 +++++ .../cel/common/{ast => }/CelMutableAst.java | 30 ++--- .../java/dev/cel/common/CelMutableSource.java | 114 ++++++++++++++++++ .../main/java/dev/cel/common/CelSource.java | 6 - .../main/java/dev/cel/common/ast/BUILD.bazel | 9 +- .../dev/cel/common/ast/CelMutableExpr.java | 3 + .../common/ast/CelMutableExprConverter.java | 2 - .../dev/cel/common/navigation/BUILD.bazel | 3 +- .../navigation/CelNavigableMutableAst.java | 2 +- .../test/java/dev/cel/common/ast/BUILD.bazel | 4 +- .../dev/cel/common/ast/CelMutableAstTest.java | 9 +- .../dev/cel/common/navigation/BUILD.bazel | 3 +- .../CelNavigableMutableAstTest.java | 2 +- .../java/dev/cel/optimizer/AstMutator.java | 111 +++++++---------- .../main/java/dev/cel/optimizer/BUILD.bazel | 5 +- .../dev/cel/optimizer/optimizers/BUILD.bazel | 7 +- .../optimizers/ConstantFoldingOptimizer.java | 2 +- .../optimizers/SubexpressionOptimizer.java | 11 +- .../dev/cel/optimizer/AstMutatorTest.java | 2 +- .../test/java/dev/cel/optimizer/BUILD.bazel | 3 +- .../dev/cel/optimizer/optimizers/BUILD.bazel | 2 +- .../SubexpressionOptimizerTest.java | 2 +- 24 files changed, 255 insertions(+), 119 deletions(-) rename common/src/main/java/dev/cel/common/{ast => }/CelMutableAst.java (80%) create mode 100644 common/src/main/java/dev/cel/common/CelMutableSource.java diff --git a/common/BUILD.bazel b/common/BUILD.bazel index 032a61150..7ad38b830 100644 --- a/common/BUILD.bazel +++ b/common/BUILD.bazel @@ -39,6 +39,16 @@ java_library( exports = ["//common/src/main/java/dev/cel/common:error_codes"], ) +java_library( + name = "mutable_ast", + exports = ["//common/src/main/java/dev/cel/common:mutable_ast"], +) + +java_library( + name = "mutable_source", + exports = ["//common/src/main/java/dev/cel/common:mutable_source"], +) + java_library( name = "runtime_exception", visibility = ["//visibility:public"], diff --git a/common/ast/BUILD.bazel b/common/ast/BUILD.bazel index cd18dca31..5400e6a8e 100644 --- a/common/ast/BUILD.bazel +++ b/common/ast/BUILD.bazel @@ -34,6 +34,6 @@ java_library( ) java_library( - name = "mutable_ast", - exports = ["//common/src/main/java/dev/cel/common/ast:mutable_ast"], + name = "mutable_expr", + exports = ["//common/src/main/java/dev/cel/common/ast:mutable_expr"], ) diff --git a/common/src/main/java/dev/cel/common/BUILD.bazel b/common/src/main/java/dev/cel/common/BUILD.bazel index 31b593708..de5995c9b 100644 --- a/common/src/main/java/dev/cel/common/BUILD.bazel +++ b/common/src/main/java/dev/cel/common/BUILD.bazel @@ -134,3 +134,31 @@ java_library( "//common/annotations", ], ) + +java_library( + name = "mutable_ast", + srcs = ["CelMutableAst.java"], + tags = [ + ], + deps = [ + ":mutable_source", + "//common", + "//common/ast", + "//common/ast:mutable_expr", + "//common/types:type_providers", + ], +) + +java_library( + name = "mutable_source", + srcs = ["CelMutableSource.java"], + tags = [ + ], + deps = [ + ":common", + "//:auto_value", + "//common/ast:mutable_expr", + "@maven//:com_google_errorprone_error_prone_annotations", + "@maven//:com_google_guava_guava", + ], +) diff --git a/common/src/main/java/dev/cel/common/ast/CelMutableAst.java b/common/src/main/java/dev/cel/common/CelMutableAst.java similarity index 80% rename from common/src/main/java/dev/cel/common/ast/CelMutableAst.java rename to common/src/main/java/dev/cel/common/CelMutableAst.java index f529e2e8d..fd3fe28f8 100644 --- a/common/src/main/java/dev/cel/common/ast/CelMutableAst.java +++ b/common/src/main/java/dev/cel/common/CelMutableAst.java @@ -12,10 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -package dev.cel.common.ast; +package dev.cel.common; -import dev.cel.common.CelAbstractSyntaxTree; -import dev.cel.common.CelSource; +import dev.cel.common.ast.CelMutableExpr; +import dev.cel.common.ast.CelMutableExprConverter; +import dev.cel.common.ast.CelReference; import dev.cel.common.types.CelType; import java.util.HashMap; import java.util.Map; @@ -30,7 +31,7 @@ */ public final class CelMutableAst { private final CelMutableExpr mutatedExpr; - private final CelSource.Builder source; + private final CelMutableSource source; private final Map references; private final Map types; @@ -40,9 +41,10 @@ public CelMutableExpr expr() { } /** - * Returns the {@link CelSource} that was used during construction of the abstract syntax tree. + * Returns the {@link CelMutableSource} that was used during construction of the abstract syntax + * tree. */ - public CelSource.Builder source() { + public CelMutableSource source() { return source; } @@ -69,7 +71,7 @@ public Optional getType(long exprId) { /** Converts this mutable AST into a parsed {@link CelAbstractSyntaxTree}. */ public CelAbstractSyntaxTree toParsedAst() { return CelAbstractSyntaxTree.newParsedAst( - CelMutableExprConverter.fromMutableExpr(mutatedExpr), source.build()); + CelMutableExprConverter.fromMutableExpr(mutatedExpr), source.toCelSource()); } /** @@ -79,7 +81,7 @@ public CelAbstractSyntaxTree toParsedAst() { public static CelMutableAst fromCelAst(CelAbstractSyntaxTree ast) { return new CelMutableAst( CelMutableExprConverter.fromCelExpr(ast.getExpr()), - ast.getSource().toBuilder(), + CelMutableSource.fromCelSource(ast.getSource()), ast.getReferenceMap(), ast.getTypeMap()); } @@ -88,21 +90,21 @@ public static CelMutableAst fromCelAst(CelAbstractSyntaxTree ast) { * Constructs an instance of {@link CelMutableAst} with the mutable expression and its source * builder. */ - public static CelMutableAst of(CelMutableExpr mutableExpr, CelSource.Builder sourceBuilder) { - return new CelMutableAst(mutableExpr, sourceBuilder); + public static CelMutableAst of(CelMutableExpr mutableExpr, CelMutableSource mutableSource) { + return new CelMutableAst(mutableExpr, mutableSource); } - private CelMutableAst(CelMutableExpr mutatedExpr, CelSource.Builder source) { - this(mutatedExpr, source, new HashMap<>(), new HashMap<>()); + private CelMutableAst(CelMutableExpr mutatedExpr, CelMutableSource mutableSource) { + this(mutatedExpr, mutableSource, new HashMap<>(), new HashMap<>()); } private CelMutableAst( CelMutableExpr mutatedExpr, - CelSource.Builder source, + CelMutableSource mutableSource, Map references, Map types) { this.mutatedExpr = mutatedExpr; - this.source = source; + this.source = mutableSource; this.references = new HashMap<>(references); this.types = new HashMap<>(types); } diff --git a/common/src/main/java/dev/cel/common/CelMutableSource.java b/common/src/main/java/dev/cel/common/CelMutableSource.java new file mode 100644 index 000000000..250963b9a --- /dev/null +++ b/common/src/main/java/dev/cel/common/CelMutableSource.java @@ -0,0 +1,114 @@ +// Copyright 2024 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.common; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.collect.ImmutableMap.toImmutableMap; + +import com.google.errorprone.annotations.CanIgnoreReturnValue; +import dev.cel.common.CelSource.Extension; +import dev.cel.common.ast.CelMutableExpr; +import dev.cel.common.ast.CelMutableExprConverter; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * Represents the mutable portion of the {@link CelSource}. This is intended for the purposes of + * augmenting an AST through CEL optimizers. + */ +public final class CelMutableSource { + + final Map macroCalls; + final Set extensions; + + @CanIgnoreReturnValue + public CelMutableSource addMacroCalls(long exprId, CelMutableExpr expr) { + this.macroCalls.put(exprId, checkNotNull(CelMutableExpr.newInstance(expr))); + return this; + } + + @CanIgnoreReturnValue + public CelMutableSource addAllMacroCalls(Map macroCalls) { + this.macroCalls.putAll(macroCalls); + return this; + } + + @CanIgnoreReturnValue + public CelMutableSource addAllExtensions(Collection extensions) { + checkNotNull(extensions); + this.extensions.addAll(extensions); + return this; + } + + @CanIgnoreReturnValue + public CelMutableSource clearMacroCall(long exprId) { + this.macroCalls.remove(exprId); + return this; + } + + @CanIgnoreReturnValue + public CelMutableSource clearMacroCalls() { + this.macroCalls.clear(); + return this; + } + + public Map getMacroCalls() { + return macroCalls; + } + + public Set getExtensions() { + return extensions; + } + + public CelSource toCelSource() { + return CelSource.newBuilder() + .addAllExtensions(extensions) + .addAllMacroCalls( + macroCalls.entrySet().stream() + .collect( + toImmutableMap( + Entry::getKey, v -> CelMutableExprConverter.fromMutableExpr(v.getValue())))) + .build(); + } + + public static CelMutableSource newInstance() { + return new CelMutableSource(new HashMap<>(), new HashSet<>()); + } + + public static CelMutableSource fromCelSource(CelSource source) { + return new CelMutableSource( + source.getMacroCalls().entrySet().stream() + .collect( + Collectors.toMap( + Entry::getKey, + v -> CelMutableExprConverter.fromCelExpr(v.getValue()), + (prev, next) -> { + throw new IllegalStateException( + "Unexpected source collision at ID: " + prev.id()); + }, + HashMap::new)), + source.getExtensions()); + } + + CelMutableSource(Map macroCalls, Set extensions) { + this.macroCalls = checkNotNull(macroCalls); + this.extensions = checkNotNull(extensions); + } +} diff --git a/common/src/main/java/dev/cel/common/CelSource.java b/common/src/main/java/dev/cel/common/CelSource.java index 82b835180..2422f7b20 100644 --- a/common/src/main/java/dev/cel/common/CelSource.java +++ b/common/src/main/java/dev/cel/common/CelSource.java @@ -279,12 +279,6 @@ public Builder clearMacroCall(long exprId) { return this; } - @CanIgnoreReturnValue - public Builder clearMacroCalls() { - this.macroCalls.clear(); - return this; - } - public ImmutableSet getExtensions() { return extensions.build(); } diff --git a/common/src/main/java/dev/cel/common/ast/BUILD.bazel b/common/src/main/java/dev/cel/common/ast/BUILD.bazel index 9ed6c80fc..c59178bcd 100644 --- a/common/src/main/java/dev/cel/common/ast/BUILD.bazel +++ b/common/src/main/java/dev/cel/common/ast/BUILD.bazel @@ -33,8 +33,7 @@ EXPR_FACTORY_SOURCES = [ ] # keep sorted -MUTABLE_AST_SOURCES = [ - "CelMutableAst.java", +MUTABLE_EXPR_SOURCES = [ "CelMutableExpr.java", "CelMutableExprConverter.java", ] @@ -119,14 +118,12 @@ java_library( ) java_library( - name = "mutable_ast", - srcs = MUTABLE_AST_SOURCES, + name = "mutable_expr", + srcs = MUTABLE_EXPR_SOURCES, tags = [ ], deps = [ ":ast", - "//common", - "//common/types:type_providers", "@maven//:com_google_guava_guava", ], ) diff --git a/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java b/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java index f83021b0b..ff2c83285 100644 --- a/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java +++ b/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java @@ -1064,6 +1064,9 @@ private CelMutableExpr(CelMutableExpr other) { this.id = other.id; this.exprKind = other.exprKind; switch (other.getKind()) { + case NOT_SET: + this.exprValue = CelExpr.newBuilder().build().exprKind().notSet(); + break; case CONSTANT: this.exprValue = other.exprValue; // Constant is immutable. break; diff --git a/common/src/main/java/dev/cel/common/ast/CelMutableExprConverter.java b/common/src/main/java/dev/cel/common/ast/CelMutableExprConverter.java index 64b9cdb10..2e6ffdadd 100644 --- a/common/src/main/java/dev/cel/common/ast/CelMutableExprConverter.java +++ b/common/src/main/java/dev/cel/common/ast/CelMutableExprConverter.java @@ -134,8 +134,6 @@ private static CelMutableCreateMap fromCelMapToMutableMap(CelCreateMap celCreate return CelMutableCreateMap.create(entries); } - /////////////////////// - public static CelExpr fromMutableExpr(CelMutableExpr mutableExpr) { long id = mutableExpr.id(); switch (mutableExpr.getKind()) { diff --git a/common/src/main/java/dev/cel/common/navigation/BUILD.bazel b/common/src/main/java/dev/cel/common/navigation/BUILD.bazel index 903ae3f0f..b3bccf67b 100644 --- a/common/src/main/java/dev/cel/common/navigation/BUILD.bazel +++ b/common/src/main/java/dev/cel/common/navigation/BUILD.bazel @@ -56,7 +56,8 @@ java_library( deps = [ ":common", "//:auto_value", - "//common/ast:mutable_ast", + "//common:mutable_ast", + "//common/ast:mutable_expr", "//common/types:type_providers", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", diff --git a/common/src/main/java/dev/cel/common/navigation/CelNavigableMutableAst.java b/common/src/main/java/dev/cel/common/navigation/CelNavigableMutableAst.java index bda18dc03..70d33ab41 100644 --- a/common/src/main/java/dev/cel/common/navigation/CelNavigableMutableAst.java +++ b/common/src/main/java/dev/cel/common/navigation/CelNavigableMutableAst.java @@ -14,7 +14,7 @@ package dev.cel.common.navigation; -import dev.cel.common.ast.CelMutableAst; +import dev.cel.common.CelMutableAst; import dev.cel.common.types.CelType; import java.util.Optional; diff --git a/common/src/test/java/dev/cel/common/ast/BUILD.bazel b/common/src/test/java/dev/cel/common/ast/BUILD.bazel index 103f4804a..61e6beb11 100644 --- a/common/src/test/java/dev/cel/common/ast/BUILD.bazel +++ b/common/src/test/java/dev/cel/common/ast/BUILD.bazel @@ -13,13 +13,15 @@ java_library( "//:java_truth", "//common", "//common:compiler_common", + "//common:mutable_ast", + "//common:mutable_source", "//common:options", "//common/ast", "//common/ast:cel_expr_visitor", "//common/ast:expr_converter", "//common/ast:expr_factory", "//common/ast:expr_v1alpha1_converter", - "//common/ast:mutable_ast", + "//common/ast:mutable_expr", "//common/resources/testdata/proto3:test_all_types_java_proto", "//common/types", "//compiler", diff --git a/common/src/test/java/dev/cel/common/ast/CelMutableAstTest.java b/common/src/test/java/dev/cel/common/ast/CelMutableAstTest.java index 1b249484d..6d2c07b17 100644 --- a/common/src/test/java/dev/cel/common/ast/CelMutableAstTest.java +++ b/common/src/test/java/dev/cel/common/ast/CelMutableAstTest.java @@ -17,8 +17,9 @@ import static com.google.common.truth.Truth.assertThat; import dev.cel.common.CelAbstractSyntaxTree; +import dev.cel.common.CelMutableAst; +import dev.cel.common.CelMutableSource; import dev.cel.common.CelOptions; -import dev.cel.common.CelSource; import dev.cel.common.types.SimpleType; import dev.cel.compiler.CelCompiler; import dev.cel.compiler.CelCompilerFactory; @@ -33,12 +34,12 @@ public final class CelMutableAstTest { @Test public void constructMutableAst() { CelMutableExpr mutableExpr = CelMutableExpr.ofConstant(1L, CelConstant.ofValue("hello world")); - CelSource.Builder sourceBuilder = CelSource.newBuilder(); + CelMutableSource mutableSource = CelMutableSource.newInstance(); - CelMutableAst celMutableAst = CelMutableAst.of(mutableExpr, sourceBuilder); + CelMutableAst celMutableAst = CelMutableAst.of(mutableExpr, mutableSource); assertThat(celMutableAst.expr()).isEqualTo(mutableExpr); - assertThat(celMutableAst.source()).isSameInstanceAs(sourceBuilder); + assertThat(celMutableAst.source()).isSameInstanceAs(mutableSource); } @Test diff --git a/common/src/test/java/dev/cel/common/navigation/BUILD.bazel b/common/src/test/java/dev/cel/common/navigation/BUILD.bazel index 40e04a70d..f79a59482 100644 --- a/common/src/test/java/dev/cel/common/navigation/BUILD.bazel +++ b/common/src/test/java/dev/cel/common/navigation/BUILD.bazel @@ -10,9 +10,10 @@ java_library( "//:java_truth", "//common", "//common:compiler_common", + "//common:mutable_ast", "//common:options", "//common/ast", - "//common/ast:mutable_ast", + "//common/ast:mutable_expr", "//common/navigation", "//common/navigation:common", "//common/navigation:mutable_navigation", diff --git a/common/src/test/java/dev/cel/common/navigation/CelNavigableMutableAstTest.java b/common/src/test/java/dev/cel/common/navigation/CelNavigableMutableAstTest.java index 3d7f8bfcd..6b78b5f23 100644 --- a/common/src/test/java/dev/cel/common/navigation/CelNavigableMutableAstTest.java +++ b/common/src/test/java/dev/cel/common/navigation/CelNavigableMutableAstTest.java @@ -16,8 +16,8 @@ import static com.google.common.truth.Truth.assertThat; +import dev.cel.common.CelMutableAst; import dev.cel.common.ast.CelConstant; -import dev.cel.common.ast.CelMutableAst; import dev.cel.common.ast.CelMutableExpr; import dev.cel.compiler.CelCompiler; import dev.cel.compiler.CelCompilerFactory; diff --git a/optimizer/src/main/java/dev/cel/optimizer/AstMutator.java b/optimizer/src/main/java/dev/cel/optimizer/AstMutator.java index 87942d2bd..7a8b636fb 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/AstMutator.java +++ b/optimizer/src/main/java/dev/cel/optimizer/AstMutator.java @@ -25,20 +25,17 @@ import com.google.common.collect.Table; import com.google.errorprone.annotations.Immutable; import dev.cel.common.CelAbstractSyntaxTree; -import dev.cel.common.CelSource; +import dev.cel.common.CelMutableAst; +import dev.cel.common.CelMutableSource; import dev.cel.common.ast.CelConstant; -import dev.cel.common.ast.CelExpr; import dev.cel.common.ast.CelExpr.ExprKind.Kind; import dev.cel.common.ast.CelExprIdGeneratorFactory; import dev.cel.common.ast.CelExprIdGeneratorFactory.ExprIdGenerator; import dev.cel.common.ast.CelExprIdGeneratorFactory.StableIdGenerator; -import dev.cel.common.ast.CelMutableAst; import dev.cel.common.ast.CelMutableExpr; import dev.cel.common.ast.CelMutableExpr.CelMutableCall; import dev.cel.common.ast.CelMutableExpr.CelMutableComprehension; import dev.cel.common.ast.CelMutableExpr.CelMutableCreateList; -import dev.cel.common.ast.CelMutableExprConverter; -import dev.cel.common.navigation.CelNavigableExpr; import dev.cel.common.navigation.CelNavigableMutableAst; import dev.cel.common.navigation.CelNavigableMutableExpr; import dev.cel.common.navigation.TraversalOrder; @@ -125,7 +122,7 @@ public CelMutableAst replaceSubtreeWithNewBindMacro( CelMutableExpr newBindMacroExpr = newBindMacroExpr( varName, varInit, CelMutableExpr.newInstance(resultExpr), stableIdGenerator); - CelSource.Builder celSource = CelSource.newBuilder(); + CelMutableSource celSource = CelMutableSource.newInstance(); if (populateMacroSource) { CelMutableExpr newBindMacroSourceExpr = newBindMacroSourceExpr(newBindMacroExpr, varName, stableIdGenerator); @@ -134,13 +131,11 @@ public CelMutableAst replaceSubtreeWithNewBindMacro( // macro. celSource = normalizeMacroSource( - ast.source(), - -1, // Do not replace any of the subexpr in the macro map. - newBindMacroSourceExpr, - stableIdGenerator::renumberId) - .addMacroCalls( - newBindMacroExpr.id(), - CelMutableExprConverter.fromMutableExpr(newBindMacroSourceExpr)); + ast.source(), + -1, // Do not replace any of the subexpr in the macro map. + newBindMacroSourceExpr, + stableIdGenerator::renumberId); + celSource.addMacroCalls(newBindMacroExpr.id(), newBindMacroSourceExpr); } CelMutableAst newBindAst = CelMutableAst.of(newBindMacroExpr, celSource); @@ -152,7 +147,7 @@ public CelMutableAst replaceSubtreeWithNewBindMacro( public CelMutableAst renumberIdsConsecutively(CelMutableAst mutableAst) { StableIdGenerator stableIdGenerator = CelExprIdGeneratorFactory.newStableIdGenerator(0); CelMutableExpr mutableExpr = renumberExprIds(stableIdGenerator::renumberId, mutableAst.expr()); - CelSource.Builder newSource = + CelMutableSource newSource = normalizeMacroSource( mutableAst.source(), Integer.MIN_VALUE, mutableExpr, stableIdGenerator::renumberId); @@ -275,7 +270,7 @@ public MangledComprehensionAst mangleComprehensionIdentifierNames( Table comprehensionLevelToType = HashBasedTable.create(); CelMutableExpr mutatedComprehensionExpr = navigableMutableAst.getAst().expr(); - CelSource.Builder newSource = navigableMutableAst.getAst().source(); + CelMutableSource newSource = navigableMutableAst.getAst().source(); for (Entry comprehensionEntry : comprehensionsToMangle.entrySet()) { iterCount++; @@ -353,7 +348,8 @@ public MangledComprehensionAst mangleComprehensionIdentifierNames( */ public CelMutableAst replaceSubtree( CelMutableExpr root, CelMutableExpr newExpr, long exprIdToReplace) { - return replaceSubtree(CelMutableAst.of(root, CelSource.newBuilder()), newExpr, exprIdToReplace); + return replaceSubtree( + CelMutableAst.of(root, CelMutableSource.newInstance()), newExpr, exprIdToReplace); } /** @@ -381,7 +377,7 @@ public CelMutableAst replaceSubtree( newExpr, // Copy the macro call information to the new AST such that macro call map can be // normalized post-replacement. - CelSource.newBuilder().addAllMacroCalls(ast.source().getMacroCalls())), + ast.source()), exprIdToReplace); } @@ -444,7 +440,7 @@ public CelMutableAst replaceSubtree( CelMutableExpr mutatedRoot = mutateExpr(stableIdGenerator::renumberId, ast.expr(), newAst.expr(), exprIdToReplace); - CelSource.Builder newAstSource = CelSource.newBuilder(); + CelMutableSource newAstSource = CelMutableSource.newInstance(); if (!ast.source().getMacroCalls().isEmpty()) { newAstSource = combine(newAstSource, ast.source()); } @@ -512,8 +508,8 @@ private void replaceIdentName( } } - private CelSource.Builder mangleIdentsInMacroSource( - CelSource.Builder sourceBuilder, + private CelMutableSource mangleIdentsInMacroSource( + CelMutableSource sourceBuilder, CelMutableExpr mutatedComprehensionExpr, String originalIterVar, MangledComprehensionName mangledComprehensionName, @@ -524,7 +520,7 @@ private CelSource.Builder mangleIdentsInMacroSource( // First, normalize the macro source. // ex: [x].exists(x, [x].exists(x, x == 1)) -> [x].exists(x, [@c1].exists(x, @c0 == 1)). - CelSource.Builder newSource = + CelMutableSource newSource = normalizeMacroSource(sourceBuilder, -1, mutatedComprehensionExpr, (id) -> id); // Note that in the above example, the iteration variable is not replaced after normalization. @@ -534,8 +530,7 @@ private CelSource.Builder mangleIdentsInMacroSource( // variable actually exists in the main AST thus, this step isn't needed. // ex: [1].map(x, [2].filter(y, x == y). Here, the variable declaration `x` exists in the AST // but not `y`. - CelMutableExpr macroExpr = - CelMutableExprConverter.fromCelExpr(newSource.getMacroCalls().get(originalComprehensionId)); + CelMutableExpr macroExpr = newSource.getMacroCalls().get(originalComprehensionId); // By convention, the iteration variable is always the first argument of the // macro call expression. CelMutableExpr identToMangle = macroExpr.call().args().get(0); @@ -549,8 +544,7 @@ private CelSource.Builder mangleIdentsInMacroSource( identToMangle.id()); } - newSource.addMacroCalls( - originalComprehensionId, CelMutableExprConverter.fromMutableExpr(macroExpr)); + newSource.addMacroCalls(originalComprehensionId, macroExpr); return newSource; } @@ -595,16 +589,13 @@ private CelMutableExpr newBindMacroSourceExpr( bindMacroExpr.comprehension().result())); } - private static CelSource.Builder combine( - CelSource.Builder celSource1, CelSource.Builder celSource2) { - ImmutableMap.Builder macroMap = ImmutableMap.builder(); - macroMap.putAll(celSource1.getMacroCalls()); - macroMap.putAll(celSource2.getMacroCalls()); - - return CelSource.newBuilder() + private static CelMutableSource combine( + CelMutableSource celSource1, CelMutableSource celSource2) { + return CelMutableSource.newInstance() .addAllExtensions(celSource1.getExtensions()) .addAllExtensions(celSource2.getExtensions()) - .addAllMacroCalls(macroMap.buildOrThrow()); + .addAllMacroCalls(celSource1.getMacroCalls()) + .addAllMacroCalls(celSource2.getMacroCalls()); } /** @@ -614,40 +605,37 @@ private static CelSource.Builder combine( */ private CelMutableAst stabilizeAst(CelMutableAst mutableAst, long seedExprId) { CelMutableExpr mutableExpr = mutableAst.expr(); - CelSource.Builder source = mutableAst.source(); + CelMutableSource source = mutableAst.source(); StableIdGenerator stableIdGenerator = CelExprIdGeneratorFactory.newStableIdGenerator(seedExprId); CelMutableExpr mutatedExpr = renumberExprIds(stableIdGenerator::nextExprId, mutableExpr); - CelSource.Builder sourceBuilder = - CelSource.newBuilder().addAllExtensions(source.getExtensions()); + CelMutableSource sourceBuilder = + CelMutableSource.newInstance().addAllExtensions(source.getExtensions()); // Update the macro call IDs and their call IDs - for (Entry macroCall : source.getMacroCalls().entrySet()) { + for (Entry macroCall : source.getMacroCalls().entrySet()) { long macroId = macroCall.getKey(); long newCallId = stableIdGenerator.renumberId(macroId); - CelMutableExpr existingMacroCallExpr = - CelMutableExprConverter.fromCelExpr(macroCall.getValue()); + CelMutableExpr existingMacroCallExpr = CelMutableExpr.newInstance(macroCall.getValue()); CelMutableExpr newCall = renumberExprIds(stableIdGenerator::renumberId, existingMacroCallExpr); - sourceBuilder.addMacroCalls(newCallId, CelMutableExprConverter.fromMutableExpr(newCall)); + sourceBuilder.addMacroCalls(newCallId, newCall); } return CelMutableAst.of(mutatedExpr, sourceBuilder); } - private CelSource.Builder normalizeMacroSource( - CelSource.Builder celSource, + private CelMutableSource normalizeMacroSource( + CelMutableSource source, long exprIdToReplace, CelMutableExpr mutatedRoot, ExprIdGenerator idGenerator) { // Remove the macro metadata that no longer exists in the AST due to being replaced. - celSource.clearMacroCall(exprIdToReplace); - CelSource.Builder sourceBuilder = - CelSource.newBuilder().addAllExtensions(celSource.getExtensions()); - if (celSource.getMacroCalls().isEmpty()) { - return sourceBuilder; + source.clearMacroCall(exprIdToReplace); + if (source.getMacroCalls().isEmpty()) { + return source; } ImmutableMap allExprs = @@ -668,8 +656,10 @@ private CelSource.Builder normalizeMacroSource( "Expected expressions to be the same for id: " + expr1.id()); })); + CelMutableSource newMacroSource = + CelMutableSource.newInstance().addAllExtensions(source.getExtensions()); // Update the macro call IDs and their call references - for (Entry existingMacroCall : celSource.getMacroCalls().entrySet()) { + for (Entry existingMacroCall : source.getMacroCalls().entrySet()) { long macroId = existingMacroCall.getKey(); long callId = idGenerator.generate(macroId); @@ -678,7 +668,7 @@ private CelSource.Builder normalizeMacroSource( } CelMutableExpr existingMacroCallExpr = - CelMutableExprConverter.fromCelExpr(existingMacroCall.getValue()); + CelMutableExpr.newInstance(existingMacroCall.getValue()); CelMutableExpr newMacroCallExpr = renumberExprIds(idGenerator, existingMacroCallExpr); CelNavigableMutableExpr callNav = CelNavigableMutableExpr.fromExpr(newMacroCallExpr); @@ -711,13 +701,12 @@ private CelSource.Builder normalizeMacroSource( } } - sourceBuilder.addMacroCalls( - callId, CelMutableExprConverter.fromMutableExpr(newMacroCallExpr)); + newMacroSource.addMacroCalls(callId, newMacroCallExpr); } // Replace comprehension nodes with a NOT_SET reference to reduce AST size. - for (Entry macroCall : sourceBuilder.getMacroCalls().entrySet()) { - CelMutableExpr macroCallExpr = CelMutableExprConverter.fromCelExpr(macroCall.getValue()); + for (Entry macroCall : newMacroSource.getMacroCalls().entrySet()) { + CelMutableExpr macroCallExpr = macroCall.getValue(); CelNavigableMutableExpr.fromExpr(macroCallExpr) .allNodes() .filter(node -> node.getKind().equals(Kind.COMPREHENSION)) @@ -730,7 +719,7 @@ private CelSource.Builder normalizeMacroSource( macroCallExpr, CelMutableExpr.ofNotSet(node.id()), node.id()); - macroCall.setValue(CelMutableExprConverter.fromMutableExpr(mutatedNode)); + macroCall.setValue(mutatedNode); }); // Prune any NOT_SET (comprehension) nodes that no longer exist in the main AST @@ -748,11 +737,10 @@ private CelSource.Builder normalizeMacroSource( .collect(toCollection(ArrayList::new)); CelMutableCall call = macroCallExpr.call(); call.setArgs(newCallArgs); - macroCall.setValue(CelMutableExprConverter.fromMutableExpr(macroCallExpr)); }); } - return sourceBuilder; + return newMacroSource; } /** @@ -813,21 +801,14 @@ private CelMutableExpr renumberExprIds(ExprIdGenerator idGenerator, CelMutableEx return mutableAst.visit(root); } - private static long getMaxId(CelExpr newExpr) { - return CelNavigableExpr.fromExpr(newExpr) - .allNodes() - .mapToLong(CelNavigableExpr::id) - .max() - .orElseThrow(NoSuchElementException::new); - } - private static long getMaxId(CelMutableAst mutableAst) { return getMaxId(CelNavigableMutableAst.fromAst(mutableAst)); } private static long getMaxId(CelNavigableMutableAst navAst) { long maxId = navAst.getRoot().maxId(); - for (Entry macroCall : navAst.getAst().source().getMacroCalls().entrySet()) { + for (Entry macroCall : + navAst.getAst().source().getMacroCalls().entrySet()) { maxId = max(maxId, getMaxId(macroCall.getValue())); } diff --git a/optimizer/src/main/java/dev/cel/optimizer/BUILD.bazel b/optimizer/src/main/java/dev/cel/optimizer/BUILD.bazel index 9ddbf2f8a..fcd85ce72 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/BUILD.bazel +++ b/optimizer/src/main/java/dev/cel/optimizer/BUILD.bazel @@ -85,11 +85,12 @@ java_library( deps = [ "//:auto_value", "//common", + "//common:mutable_ast", + "//common:mutable_source", "//common/annotations", "//common/ast", "//common/ast:expr_factory", - "//common/ast:mutable_ast", - "//common/navigation", + "//common/ast:mutable_expr", "//common/navigation:common", "//common/navigation:mutable_navigation", "//common/types:type_providers", diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel b/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel index 409421e08..2b0cc563b 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel @@ -18,9 +18,10 @@ java_library( "//bundle:cel", "//common", "//common:compiler_common", + "//common:mutable_ast", "//common/ast", "//common/ast:expr_util", - "//common/ast:mutable_ast", + "//common/ast:mutable_expr", "//common/navigation:mutable_navigation", "//extensions:optional_library", "//optimizer:ast_optimizer", @@ -45,8 +46,10 @@ java_library( "//checker:checker_legacy_environment", "//common", "//common:compiler_common", + "//common:mutable_ast", + "//common:mutable_source", "//common/ast", - "//common/ast:mutable_ast", + "//common/ast:mutable_expr", "//common/navigation", "//common/navigation:common", "//common/navigation:mutable_navigation", diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java b/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java index fd17df9d6..cd7e7fcd0 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java @@ -20,11 +20,11 @@ import com.google.common.collect.ImmutableList; import dev.cel.bundle.Cel; import dev.cel.common.CelAbstractSyntaxTree; +import dev.cel.common.CelMutableAst; import dev.cel.common.CelValidationException; import dev.cel.common.ast.CelConstant; import dev.cel.common.ast.CelExpr.ExprKind.Kind; import dev.cel.common.ast.CelExprUtil; -import dev.cel.common.ast.CelMutableAst; import dev.cel.common.ast.CelMutableExpr; import dev.cel.common.ast.CelMutableExpr.CelMutableCall; import dev.cel.common.ast.CelMutableExpr.CelMutableCreateList; diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java index 311ce34de..7057eb4ba 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java @@ -33,6 +33,8 @@ import dev.cel.checker.Standard; import dev.cel.common.CelAbstractSyntaxTree; import dev.cel.common.CelFunctionDecl; +import dev.cel.common.CelMutableAst; +import dev.cel.common.CelMutableSource; import dev.cel.common.CelOverloadDecl; import dev.cel.common.CelSource; import dev.cel.common.CelSource.Extension; @@ -43,7 +45,6 @@ import dev.cel.common.ast.CelExpr; import dev.cel.common.ast.CelExpr.CelCall; import dev.cel.common.ast.CelExpr.ExprKind.Kind; -import dev.cel.common.ast.CelMutableAst; import dev.cel.common.ast.CelMutableExpr; import dev.cel.common.ast.CelMutableExprConverter; import dev.cel.common.navigation.CelNavigableExpr; @@ -151,7 +152,7 @@ private OptimizationResult optimizeUsingCelBlock(CelAbstractSyntaxTree ast, Cel MANGLED_COMPREHENSION_IDENTIFIER_PREFIX, MANGLED_COMPREHENSION_RESULT_PREFIX); astToModify = mangledComprehensionAst.mutableAst(); - CelSource.Builder sourceToModify = astToModify.source(); + CelMutableSource sourceToModify = astToModify.source(); int blockIdentifierIndex = 0; int iterCount; @@ -177,9 +178,7 @@ private OptimizationResult optimizeUsingCelBlock(CelAbstractSyntaxTree ast, Cel navAst, CelNavigableMutableAst.fromAst( CelMutableAst.of( - CelMutableExpr.ofIdent(blockIdentifier), - CelSource.newBuilder() - .addAllMacroCalls(navAst.getAst().source().getMacroCalls()))), + CelMutableExpr.ofIdent(blockIdentifier), navAst.getAst().source())), cseCandidate.id()); // Retain the existing macro calls in case if the block identifiers are replacing a subtree @@ -354,7 +353,7 @@ private OptimizationResult optimizeUsingCelBind(CelAbstractSyntaxTree ast) { MANGLED_COMPREHENSION_IDENTIFIER_PREFIX, MANGLED_COMPREHENSION_RESULT_PREFIX) .mutableAst(); - CelSource.Builder sourceToModify = astToModify.source(); + CelMutableSource sourceToModify = astToModify.source(); int bindIdentifierIndex = 0; int iterCount; diff --git a/optimizer/src/test/java/dev/cel/optimizer/AstMutatorTest.java b/optimizer/src/test/java/dev/cel/optimizer/AstMutatorTest.java index 8947ad34a..b3c6313da 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/AstMutatorTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/AstMutatorTest.java @@ -25,6 +25,7 @@ import dev.cel.bundle.CelFactory; import dev.cel.common.CelAbstractSyntaxTree; import dev.cel.common.CelFunctionDecl; +import dev.cel.common.CelMutableAst; import dev.cel.common.CelOptions; import dev.cel.common.CelOverloadDecl; import dev.cel.common.CelSource; @@ -33,7 +34,6 @@ import dev.cel.common.ast.CelConstant; import dev.cel.common.ast.CelExpr; import dev.cel.common.ast.CelExpr.ExprKind.Kind; -import dev.cel.common.ast.CelMutableAst; import dev.cel.common.ast.CelMutableExpr; import dev.cel.common.ast.CelMutableExpr.CelMutableCall; import dev.cel.common.ast.CelMutableExpr.CelMutableCreateList; diff --git a/optimizer/src/test/java/dev/cel/optimizer/BUILD.bazel b/optimizer/src/test/java/dev/cel/optimizer/BUILD.bazel index 4d751e4f9..83ccd8a3c 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/BUILD.bazel +++ b/optimizer/src/test/java/dev/cel/optimizer/BUILD.bazel @@ -11,9 +11,10 @@ java_library( "//bundle:cel", "//common", "//common:compiler_common", + "//common:mutable_ast", "//common:options", "//common/ast", - "//common/ast:mutable_ast", + "//common/ast:mutable_expr", "//common/navigation", "//common/navigation:mutable_navigation", "//common/resources/testdata/proto3:test_all_types_java_proto", diff --git a/optimizer/src/test/java/dev/cel/optimizer/optimizers/BUILD.bazel b/optimizer/src/test/java/dev/cel/optimizer/optimizers/BUILD.bazel index 17389a5a5..e1ac3bd52 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/optimizers/BUILD.bazel +++ b/optimizer/src/test/java/dev/cel/optimizer/optimizers/BUILD.bazel @@ -12,9 +12,9 @@ java_library( "//bundle:cel", "//common", "//common:compiler_common", + "//common:mutable_ast", "//common:options", "//common/ast", - "//common/ast:mutable_ast", "//common/navigation:mutable_navigation", "//common/resources/testdata/proto3:test_all_types_java_proto", "//common/types", diff --git a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java index a174238d9..8d657cd0a 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java @@ -29,6 +29,7 @@ import dev.cel.bundle.CelFactory; import dev.cel.common.CelAbstractSyntaxTree; import dev.cel.common.CelFunctionDecl; +import dev.cel.common.CelMutableAst; import dev.cel.common.CelOptions; import dev.cel.common.CelOverloadDecl; import dev.cel.common.CelSource.Extension; @@ -39,7 +40,6 @@ import dev.cel.common.ast.CelConstant; import dev.cel.common.ast.CelExpr; import dev.cel.common.ast.CelExpr.ExprKind.Kind; -import dev.cel.common.ast.CelMutableAst; import dev.cel.common.navigation.CelNavigableMutableAst; import dev.cel.common.navigation.CelNavigableMutableExpr; import dev.cel.common.types.ListType; From 93acd07d536a055283583303ea281e4c13219ce6 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Wed, 24 Apr 2024 11:27:25 -0700 Subject: [PATCH 100/486] Drop expr suffix from CelExpr static constructors PiperOrigin-RevId: 627794357 --- .../test/java/dev/cel/bundle/CelImplTest.java | 2 +- .../main/java/dev/cel/common/ast/CelExpr.java | 19 +- .../dev/cel/common/ast/CelExprConverter.java | 18 +- .../common/ast/CelExprV1Alpha1Converter.java | 18 +- .../common/ast/CelMutableExprConverter.java | 14 +- .../cel/common/ast/CelExprConverterTest.java | 99 +++++---- .../java/dev/cel/common/ast/CelExprTest.java | 42 ++-- .../ast/CelExprV1Alpha1ConverterTest.java | 99 +++++---- .../cel/common/ast/CelExprVisitorTest.java | 16 +- .../ast/CelMutableExprConverterTest.java | 90 ++++----- .../navigation/CelNavigableAstTest.java | 2 +- .../navigation/CelNavigableExprTest.java | 6 +- .../CelNavigableExprVisitorTest.java | 189 +++++++++--------- .../dev/cel/optimizer/AstMutatorTest.java | 4 +- .../cel/optimizer/CelOptimizerImplTest.java | 2 +- .../SubexpressionOptimizerTest.java | 5 +- 16 files changed, 304 insertions(+), 321 deletions(-) diff --git a/bundle/src/test/java/dev/cel/bundle/CelImplTest.java b/bundle/src/test/java/dev/cel/bundle/CelImplTest.java index 3beeb3af9..1eded3ce9 100644 --- a/bundle/src/test/java/dev/cel/bundle/CelImplTest.java +++ b/bundle/src/test/java/dev/cel/bundle/CelImplTest.java @@ -488,7 +488,7 @@ public void compile_withOptionalTypes() throws Exception { CelCreateList createList = ast.getExpr().createList(); assertThat(createList.optionalIndices()).containsExactly(0); - assertThat(createList.elements()).containsExactly(CelExpr.ofIdentExpr(2, "a")); + assertThat(createList.elements()).containsExactly(CelExpr.ofIdent(2, "a")); } @Test diff --git a/common/src/main/java/dev/cel/common/ast/CelExpr.java b/common/src/main/java/dev/cel/common/ast/CelExpr.java index 2ea228268..c0651ccb3 100644 --- a/common/src/main/java/dev/cel/common/ast/CelExpr.java +++ b/common/src/main/java/dev/cel/common/ast/CelExpr.java @@ -983,14 +983,14 @@ public static CelExpr ofNotSet(long id) { .build(); } - public static CelExpr ofConstantExpr(long id, CelConstant celConstant) { + public static CelExpr ofConstant(long id, CelConstant celConstant) { return newBuilder() .setId(id) .setExprKind(AutoOneOf_CelExpr_ExprKind.constant(celConstant)) .build(); } - public static CelExpr ofIdentExpr(long id, String identName) { + public static CelExpr ofIdent(long id, String identName) { return newBuilder() .setId(id) .setExprKind( @@ -998,8 +998,7 @@ public static CelExpr ofIdentExpr(long id, String identName) { .build(); } - public static CelExpr ofSelectExpr( - long id, CelExpr operandExpr, String field, boolean isTestOnly) { + public static CelExpr ofSelect(long id, CelExpr operandExpr, String field, boolean isTestOnly) { return newBuilder() .setId(id) .setExprKind( @@ -1012,7 +1011,7 @@ public static CelExpr ofSelectExpr( .build(); } - public static CelExpr ofCallExpr( + public static CelExpr ofCall( long id, Optional targetExpr, String function, ImmutableList arguments) { CelCall.Builder celCallBuilder = CelCall.newBuilder().setFunction(function).addArgs(arguments); @@ -1023,7 +1022,7 @@ public static CelExpr ofCallExpr( .build(); } - public static CelExpr ofCreateListExpr( + public static CelExpr ofCreateList( long id, ImmutableList elements, ImmutableList optionalIndices) { return newBuilder() .setId(id) @@ -1036,7 +1035,7 @@ public static CelExpr ofCreateListExpr( .build(); } - public static CelExpr ofCreateStructExpr( + public static CelExpr ofCreateStruct( long id, String messageName, ImmutableList entries) { return newBuilder() .setId(id) @@ -1049,7 +1048,7 @@ public static CelExpr ofCreateStructExpr( .build(); } - public static CelExpr ofCreateMapExpr(long id, ImmutableList entries) { + public static CelExpr ofCreateMap(long id, ImmutableList entries) { return newBuilder() .setId(id) .setExprKind( @@ -1058,7 +1057,7 @@ public static CelExpr ofCreateMapExpr(long id, ImmutableList .build(); } - public static CelCreateStruct.Entry ofCreateStructEntryExpr( + public static CelCreateStruct.Entry ofCreateStructEntry( long id, String fieldKey, CelExpr value, boolean isOptionalEntry) { return CelCreateStruct.Entry.newBuilder() .setId(id) @@ -1068,7 +1067,7 @@ public static CelCreateStruct.Entry ofCreateStructEntryExpr( .build(); } - public static CelCreateMap.Entry ofCreateMapEntryExpr( + public static CelCreateMap.Entry ofCreateMapEntry( long id, CelExpr mapKey, CelExpr value, boolean isOptionalEntry) { return CelCreateMap.Entry.newBuilder() .setId(id) diff --git a/common/src/main/java/dev/cel/common/ast/CelExprConverter.java b/common/src/main/java/dev/cel/common/ast/CelExprConverter.java index a17350cc2..b2d8489a3 100644 --- a/common/src/main/java/dev/cel/common/ast/CelExprConverter.java +++ b/common/src/main/java/dev/cel/common/ast/CelExprConverter.java @@ -102,26 +102,26 @@ public static Expr fromCelExpr(CelExpr celExpr) { public static CelExpr fromExpr(Expr expr) { switch (expr.getExprKindCase()) { case CONST_EXPR: - return CelExpr.ofConstantExpr(expr.getId(), exprConstantToCelConstant(expr.getConstExpr())); + return CelExpr.ofConstant(expr.getId(), exprConstantToCelConstant(expr.getConstExpr())); case IDENT_EXPR: - return CelExpr.ofIdentExpr(expr.getId(), expr.getIdentExpr().getName()); + return CelExpr.ofIdent(expr.getId(), expr.getIdentExpr().getName()); case SELECT_EXPR: Select selectExpr = expr.getSelectExpr(); - return CelExpr.ofSelectExpr( + return CelExpr.ofSelect( expr.getId(), fromExpr(selectExpr.getOperand()), selectExpr.getField(), selectExpr.getTestOnly()); case CALL_EXPR: Call callExpr = expr.getCallExpr(); - return CelExpr.ofCallExpr( + return CelExpr.ofCall( expr.getId(), callExpr.hasTarget() ? Optional.of(fromExpr(callExpr.getTarget())) : Optional.empty(), callExpr.getFunction(), fromExprList(callExpr.getArgsList())); case LIST_EXPR: CreateList createListExpr = expr.getListExpr(); - return CelExpr.ofCreateListExpr( + return CelExpr.ofCreateList( expr.getId(), fromExprList(createListExpr.getElementsList()), ImmutableList.copyOf(createListExpr.getOptionalIndicesList())); @@ -209,14 +209,14 @@ private static CelExpr exprStructToCelStruct(long id, CreateStruct structExpr) { "Unexpected struct key kind case: " + structExprEntry.getKeyKindCase()); } entries.add( - CelExpr.ofCreateStructEntryExpr( + CelExpr.ofCreateStructEntry( structExprEntry.getId(), structExprEntry.getFieldKey(), fromExpr(structExprEntry.getValue()), structExprEntry.getOptionalEntry())); } - return CelExpr.ofCreateStructExpr(id, structExpr.getMessageName(), entries.build()); + return CelExpr.ofCreateStruct(id, structExpr.getMessageName(), entries.build()); } else { ImmutableList.Builder entries = ImmutableList.builder(); for (Entry mapExprEntry : structExpr.getEntriesList()) { @@ -225,14 +225,14 @@ private static CelExpr exprStructToCelStruct(long id, CreateStruct structExpr) { "Unexpected map key kind case: " + mapExprEntry.getKeyKindCase()); } entries.add( - CelExpr.ofCreateMapEntryExpr( + CelExpr.ofCreateMapEntry( mapExprEntry.getId(), fromExpr(mapExprEntry.getMapKey()), fromExpr(mapExprEntry.getValue()), mapExprEntry.getOptionalEntry())); } - return CelExpr.ofCreateMapExpr(id, entries.build()); + return CelExpr.ofCreateMap(id, entries.build()); } } diff --git a/common/src/main/java/dev/cel/common/ast/CelExprV1Alpha1Converter.java b/common/src/main/java/dev/cel/common/ast/CelExprV1Alpha1Converter.java index 377910c04..b22daf514 100644 --- a/common/src/main/java/dev/cel/common/ast/CelExprV1Alpha1Converter.java +++ b/common/src/main/java/dev/cel/common/ast/CelExprV1Alpha1Converter.java @@ -102,26 +102,26 @@ public static Expr fromCelExpr(CelExpr celExpr) { public static CelExpr fromExpr(Expr expr) { switch (expr.getExprKindCase()) { case CONST_EXPR: - return CelExpr.ofConstantExpr(expr.getId(), exprConstantToCelConstant(expr.getConstExpr())); + return CelExpr.ofConstant(expr.getId(), exprConstantToCelConstant(expr.getConstExpr())); case IDENT_EXPR: - return CelExpr.ofIdentExpr(expr.getId(), expr.getIdentExpr().getName()); + return CelExpr.ofIdent(expr.getId(), expr.getIdentExpr().getName()); case SELECT_EXPR: Select selectExpr = expr.getSelectExpr(); - return CelExpr.ofSelectExpr( + return CelExpr.ofSelect( expr.getId(), fromExpr(selectExpr.getOperand()), selectExpr.getField(), selectExpr.getTestOnly()); case CALL_EXPR: Call callExpr = expr.getCallExpr(); - return CelExpr.ofCallExpr( + return CelExpr.ofCall( expr.getId(), callExpr.hasTarget() ? Optional.of(fromExpr(callExpr.getTarget())) : Optional.empty(), callExpr.getFunction(), fromExprList(callExpr.getArgsList())); case LIST_EXPR: CreateList createListExpr = expr.getListExpr(); - return CelExpr.ofCreateListExpr( + return CelExpr.ofCreateList( expr.getId(), fromExprList(createListExpr.getElementsList()), ImmutableList.copyOf(createListExpr.getOptionalIndicesList())); @@ -209,14 +209,14 @@ private static CelExpr exprStructToCelStruct(long id, CreateStruct structExpr) { "Unexpected struct key kind case: " + structExprEntry.getKeyKindCase()); } entries.add( - CelExpr.ofCreateStructEntryExpr( + CelExpr.ofCreateStructEntry( structExprEntry.getId(), structExprEntry.getFieldKey(), fromExpr(structExprEntry.getValue()), structExprEntry.getOptionalEntry())); } - return CelExpr.ofCreateStructExpr(id, structExpr.getMessageName(), entries.build()); + return CelExpr.ofCreateStruct(id, structExpr.getMessageName(), entries.build()); } else { ImmutableList.Builder entries = ImmutableList.builder(); for (Entry mapExprEntry : structExpr.getEntriesList()) { @@ -225,14 +225,14 @@ private static CelExpr exprStructToCelStruct(long id, CreateStruct structExpr) { "Unexpected map key kind case: " + mapExprEntry.getKeyKindCase()); } entries.add( - CelExpr.ofCreateMapEntryExpr( + CelExpr.ofCreateMapEntry( mapExprEntry.getId(), fromExpr(mapExprEntry.getMapKey()), fromExpr(mapExprEntry.getValue()), mapExprEntry.getOptionalEntry())); } - return CelExpr.ofCreateMapExpr(id, entries.build()); + return CelExpr.ofCreateMap(id, entries.build()); } } diff --git a/common/src/main/java/dev/cel/common/ast/CelMutableExprConverter.java b/common/src/main/java/dev/cel/common/ast/CelMutableExprConverter.java index 2e6ffdadd..1f72f0132 100644 --- a/common/src/main/java/dev/cel/common/ast/CelMutableExprConverter.java +++ b/common/src/main/java/dev/cel/common/ast/CelMutableExprConverter.java @@ -138,13 +138,13 @@ public static CelExpr fromMutableExpr(CelMutableExpr mutableExpr) { long id = mutableExpr.id(); switch (mutableExpr.getKind()) { case CONSTANT: - return CelExpr.ofConstantExpr(id, mutableExpr.constant()); + return CelExpr.ofConstant(id, mutableExpr.constant()); case IDENT: - return CelExpr.ofIdentExpr(id, mutableExpr.ident().name()); + return CelExpr.ofIdent(id, mutableExpr.ident().name()); case SELECT: CelMutableSelect select = mutableExpr.select(); CelExpr operand = fromMutableExpr(select.operand()); - return CelExpr.ofSelectExpr(id, operand, select.field(), select.testOnly()); + return CelExpr.ofSelect(id, operand, select.field(), select.testOnly()); case CALL: CelMutableCall mutableCall = mutableExpr.call(); ImmutableList args = @@ -153,10 +153,10 @@ public static CelExpr fromMutableExpr(CelMutableExpr mutableExpr) { .collect(toImmutableList()); Optional targetExpr = mutableCall.target().map(CelMutableExprConverter::fromMutableExpr); - return CelExpr.ofCallExpr(id, targetExpr, mutableCall.function(), args); + return CelExpr.ofCall(id, targetExpr, mutableCall.function(), args); case CREATE_LIST: CelMutableCreateList mutableCreateList = mutableExpr.createList(); - return CelExpr.ofCreateListExpr( + return CelExpr.ofCreateList( id, fromMutableExprList(mutableCreateList.elements()), ImmutableList.copyOf(mutableCreateList.optionalIndices())); @@ -204,7 +204,7 @@ private static CelCreateStruct fromMutableStructToCelStruct( List entries = new ArrayList<>(); for (CelMutableCreateStruct.Entry mutableStructEntry : mutableCreateStruct.entries()) { entries.add( - CelExpr.ofCreateStructEntryExpr( + CelExpr.ofCreateStructEntry( mutableStructEntry.id(), mutableStructEntry.fieldKey(), fromMutableExpr(mutableStructEntry.value()), @@ -221,7 +221,7 @@ private static CelCreateMap fromMutableMapToCelMap(CelMutableCreateMap mutableCr List entries = new ArrayList<>(); for (CelMutableCreateMap.Entry mutableMapEntry : mutableCreateMap.entries()) { entries.add( - CelExpr.ofCreateMapEntryExpr( + CelExpr.ofCreateMapEntry( mutableMapEntry.id(), fromMutableExpr(mutableMapEntry.key()), fromMutableExpr(mutableMapEntry.value()), diff --git a/common/src/test/java/dev/cel/common/ast/CelExprConverterTest.java b/common/src/test/java/dev/cel/common/ast/CelExprConverterTest.java index 55820c3a3..424031dd4 100644 --- a/common/src/test/java/dev/cel/common/ast/CelExprConverterTest.java +++ b/common/src/test/java/dev/cel/common/ast/CelExprConverterTest.java @@ -43,50 +43,50 @@ public class CelExprConverterTest { private enum ConstantTestCase { NOT_SET( Expr.newBuilder().setId(1).setConstExpr(Constant.getDefaultInstance()).build(), - CelExpr.ofConstantExpr(1, CelConstant.ofNotSet())), + CelExpr.ofConstant(1, CelConstant.ofNotSet())), NULL( Expr.newBuilder() .setId(1) .setConstExpr(Constant.newBuilder().setNullValue(NullValue.NULL_VALUE).build()) .build(), - CelExpr.ofConstantExpr(1, CelConstant.ofValue(NullValue.NULL_VALUE))), + CelExpr.ofConstant(1, CelConstant.ofValue(NullValue.NULL_VALUE))), BOOLEAN( Expr.newBuilder() .setId(1) .setConstExpr(Constant.newBuilder().setBoolValue(true).build()) .build(), - CelExpr.ofConstantExpr(1, CelConstant.ofValue(true))), + CelExpr.ofConstant(1, CelConstant.ofValue(true))), INT64( Expr.newBuilder() .setId(1) .setConstExpr(Constant.newBuilder().setInt64Value(10).build()) .build(), - CelExpr.ofConstantExpr(1, CelConstant.ofValue(10))), + CelExpr.ofConstant(1, CelConstant.ofValue(10))), UINT64( Expr.newBuilder() .setId(1) .setConstExpr(Constant.newBuilder().setUint64Value(15).build()) .build(), - CelExpr.ofConstantExpr(1, CelConstant.ofValue(UnsignedLong.valueOf(15)))), + CelExpr.ofConstant(1, CelConstant.ofValue(UnsignedLong.valueOf(15)))), DOUBLE( Expr.newBuilder() .setId(1) .setConstExpr(Constant.newBuilder().setDoubleValue(1.5).build()) .build(), - CelExpr.ofConstantExpr(1, CelConstant.ofValue(1.5))), + CelExpr.ofConstant(1, CelConstant.ofValue(1.5))), STRING( Expr.newBuilder() .setId(1) .setConstExpr(Constant.newBuilder().setStringValue("Test").build()) .build(), - CelExpr.ofConstantExpr(1, CelConstant.ofValue("Test"))), + CelExpr.ofConstant(1, CelConstant.ofValue("Test"))), BYTES( Expr.newBuilder() .setId(1) .setConstExpr( Constant.newBuilder().setBytesValue(ByteString.copyFromUtf8("TEST")).build()) .build(), - CelExpr.ofConstantExpr(1, CelConstant.ofValue(ByteString.copyFromUtf8("TEST")))); + CelExpr.ofConstant(1, CelConstant.ofValue(ByteString.copyFromUtf8("TEST")))); final Expr protoExpr; final CelExpr celExpr; @@ -122,7 +122,7 @@ public void convertExprIdent_toCelIdent() { CelExpr celExpr = CelExprConverter.fromExpr(expr); - assertThat(celExpr).isEqualTo(CelExpr.ofIdentExpr(2, "Test")); + assertThat(celExpr).isEqualTo(CelExpr.ofIdent(2, "Test")); } @Test @@ -146,8 +146,8 @@ public void convertExprSelect_toCelSelect(boolean isTestOnly) { assertThat(celExpr) .isEqualTo( - CelExpr.ofSelectExpr( - 3, CelExpr.ofConstantExpr(4, CelConstant.ofValue(true)), "field", isTestOnly)); + CelExpr.ofSelect( + 3, CelExpr.ofConstant(4, CelConstant.ofValue(true)), "field", isTestOnly)); } @Test @@ -167,11 +167,11 @@ public void convertExprCall_toCelCall() { assertThat(celExpr) .isEqualTo( - CelExpr.ofCallExpr( + CelExpr.ofCall( 1, - Optional.of(CelExpr.ofConstantExpr(2, CelConstant.ofValue(10))), + Optional.of(CelExpr.ofConstant(2, CelConstant.ofValue(10))), "func", - ImmutableList.of(CelExpr.ofConstantExpr(3, CelConstant.ofValue(20))))); + ImmutableList.of(CelExpr.ofConstant(3, CelConstant.ofValue(20))))); } @Test @@ -191,11 +191,11 @@ public void convertExprList_toCelList() { assertThat(celExpr) .isEqualTo( - CelExpr.ofCreateListExpr( + CelExpr.ofCreateList( 1, ImmutableList.of( - CelExpr.ofConstantExpr(2, CelConstant.ofValue(10)), - CelExpr.ofConstantExpr(3, CelConstant.ofValue(15))), + CelExpr.ofConstant(2, CelConstant.ofValue(10)), + CelExpr.ofConstant(3, CelConstant.ofValue(15))), ImmutableList.of(1))); } @@ -221,12 +221,12 @@ public void convertExprStructExpr_toCelStruct() { assertThat(celExpr) .isEqualTo( - CelExpr.ofCreateStructExpr( + CelExpr.ofCreateStruct( 1, "messageName", ImmutableList.of( - CelExpr.ofCreateStructEntryExpr( - 2, "fieldKey", CelExpr.ofConstantExpr(3, CelConstant.ofValue(10)), true)))); + CelExpr.ofCreateStructEntry( + 2, "fieldKey", CelExpr.ofConstant(3, CelConstant.ofValue(10)), true)))); } @Test @@ -299,13 +299,13 @@ public void convertExprStructExpr_toCelMap() { assertThat(celExpr) .isEqualTo( - CelExpr.ofCreateMapExpr( + CelExpr.ofCreateMap( 1, ImmutableList.of( - CelExpr.ofCreateMapEntryExpr( + CelExpr.ofCreateMapEntry( 2, - CelExpr.ofConstantExpr(3, CelConstant.ofValue(15)), - CelExpr.ofConstantExpr(4, CelConstant.ofValue(10)), + CelExpr.ofConstant(3, CelConstant.ofValue(15)), + CelExpr.ofConstant(4, CelConstant.ofValue(10)), true)))); } @@ -341,12 +341,12 @@ public void convertExprComprehensionExpr_toCelComprehension() { CelExpr.ofComprehension( 1, "iterVar", - CelExpr.ofConstantExpr(2, CelConstant.ofValue(10)), + CelExpr.ofConstant(2, CelConstant.ofValue(10)), "accuVar", - CelExpr.ofConstantExpr(3, CelConstant.ofValue(20)), - CelExpr.ofCallExpr(4, Optional.empty(), "testCondition", ImmutableList.of()), - CelExpr.ofCallExpr(5, Optional.empty(), "testStep", ImmutableList.of()), - CelExpr.ofConstantExpr(6, CelConstant.ofValue(30)))); + CelExpr.ofConstant(3, CelConstant.ofValue(20)), + CelExpr.ofCall(4, Optional.empty(), "testCondition", ImmutableList.of()), + CelExpr.ofCall(5, Optional.empty(), "testStep", ImmutableList.of()), + CelExpr.ofConstant(6, CelConstant.ofValue(30)))); } @Test @@ -390,7 +390,7 @@ public void convertCelNotSet_toExprNotSet() { @Test public void convertCelIdent_toExprIdent() { - CelExpr celExpr = CelExpr.ofIdentExpr(2, "Test"); + CelExpr celExpr = CelExpr.ofIdent(2, "Test"); Expr expr = CelExprConverter.fromCelExpr(celExpr); @@ -407,8 +407,7 @@ public void convertCelIdent_toExprIdent() { @TestParameters("{isTestOnly: false}") public void convertCelSelect_toExprSelect(boolean isTestOnly) { CelExpr celExpr = - CelExpr.ofSelectExpr( - 3, CelExpr.ofConstantExpr(4, CelConstant.ofValue(true)), "field", isTestOnly); + CelExpr.ofSelect(3, CelExpr.ofConstant(4, CelConstant.ofValue(true)), "field", isTestOnly); Expr expr = CelExprConverter.fromCelExpr(celExpr); @@ -430,11 +429,11 @@ public void convertCelSelect_toExprSelect(boolean isTestOnly) { @Test public void convertCelCall_toExprCall() { CelExpr celExpr = - CelExpr.ofCallExpr( + CelExpr.ofCall( 1, - Optional.of(CelExpr.ofConstantExpr(2, CelConstant.ofValue(10))), + Optional.of(CelExpr.ofConstant(2, CelConstant.ofValue(10))), "func", - ImmutableList.of(CelExpr.ofConstantExpr(3, CelConstant.ofValue(20)))); + ImmutableList.of(CelExpr.ofConstant(3, CelConstant.ofValue(20)))); Expr expr = CelExprConverter.fromCelExpr(celExpr); @@ -454,11 +453,11 @@ public void convertCelCall_toExprCall() { @Test public void convertCelList_toExprList() { CelExpr celExpr = - CelExpr.ofCreateListExpr( + CelExpr.ofCreateList( 1, ImmutableList.of( - CelExpr.ofConstantExpr(2, CelConstant.ofValue(10)), - CelExpr.ofConstantExpr(3, CelConstant.ofValue(15))), + CelExpr.ofConstant(2, CelConstant.ofValue(10)), + CelExpr.ofConstant(3, CelConstant.ofValue(15))), ImmutableList.of(1)); Expr expr = CelExprConverter.fromCelExpr(celExpr); @@ -479,12 +478,12 @@ public void convertCelList_toExprList() { @Test public void convertCelStructExpr_toExprStruct_withFieldKey() { CelExpr celExpr = - CelExpr.ofCreateStructExpr( + CelExpr.ofCreateStruct( 1, "messageName", ImmutableList.of( - CelExpr.ofCreateStructEntryExpr( - 2, "fieldKey", CelExpr.ofConstantExpr(3, CelConstant.ofValue(10)), true))); + CelExpr.ofCreateStructEntry( + 2, "fieldKey", CelExpr.ofConstant(3, CelConstant.ofValue(10)), true))); Expr expr = CelExprConverter.fromCelExpr(celExpr); @@ -509,13 +508,13 @@ public void convertCelStructExpr_toExprStruct_withFieldKey() { @Test public void convertCelMapExpr_toExprStruct() { CelExpr celExpr = - CelExpr.ofCreateMapExpr( + CelExpr.ofCreateMap( 1, ImmutableList.of( - CelExpr.ofCreateMapEntryExpr( + CelExpr.ofCreateMapEntry( 2, - CelExpr.ofConstantExpr(3, CelConstant.ofValue(15)), - CelExpr.ofConstantExpr(4, CelConstant.ofValue(10)), + CelExpr.ofConstant(3, CelConstant.ofValue(15)), + CelExpr.ofConstant(4, CelConstant.ofValue(10)), true))); Expr expr = CelExprConverter.fromCelExpr(celExpr); @@ -543,12 +542,12 @@ public void convertCelComprehensionExpr_toExprComprehension() { CelExpr.ofComprehension( 1, "iterVar", - CelExpr.ofConstantExpr(2, CelConstant.ofValue(10)), + CelExpr.ofConstant(2, CelConstant.ofValue(10)), "accuVar", - CelExpr.ofConstantExpr(3, CelConstant.ofValue(20)), - CelExpr.ofCallExpr(4, Optional.empty(), "testCondition", ImmutableList.of()), - CelExpr.ofCallExpr(5, Optional.empty(), "testStep", ImmutableList.of()), - CelExpr.ofConstantExpr(6, CelConstant.ofValue(30))); + CelExpr.ofConstant(3, CelConstant.ofValue(20)), + CelExpr.ofCall(4, Optional.empty(), "testCondition", ImmutableList.of()), + CelExpr.ofCall(5, Optional.empty(), "testStep", ImmutableList.of()), + CelExpr.ofConstant(6, CelConstant.ofValue(30))); Expr expr = CelExprConverter.fromCelExpr(celExpr); diff --git a/common/src/test/java/dev/cel/common/ast/CelExprTest.java b/common/src/test/java/dev/cel/common/ast/CelExprTest.java index 2e252e459..c9663978c 100644 --- a/common/src/test/java/dev/cel/common/ast/CelExprTest.java +++ b/common/src/test/java/dev/cel/common/ast/CelExprTest.java @@ -141,7 +141,7 @@ public void celExprBuilder_setCall_clearTarget() { CelCall celCall = CelCall.newBuilder() .setFunction("function") - .setTarget(CelExpr.ofConstantExpr(1, CelConstant.ofValue("test"))) + .setTarget(CelExpr.ofConstant(1, CelConstant.ofValue("test"))) .build(); CelExpr celExpr = CelExpr.newBuilder().setCall(celCall.toBuilder().clearTarget().build()).build(); @@ -156,11 +156,11 @@ public void callBuilder_getArgs() { CelCall celCall = CelCall.newBuilder() .setFunction("function") - .addArgs(CelExpr.ofConstantExpr(1, CelConstant.ofValue("test"))) + .addArgs(CelExpr.ofConstant(1, CelConstant.ofValue("test"))) .build(); assertThat(celCall.toBuilder().getArgs()) - .containsExactly(CelExpr.ofConstantExpr(1, CelConstant.ofValue("test"))); + .containsExactly(CelExpr.ofConstant(1, CelConstant.ofValue("test"))); } @Test @@ -169,15 +169,15 @@ public void celExprBuilder_setCall_setArgByIndex() { CelCall.newBuilder() .setFunction("function") .addArgs( - CelExpr.ofConstantExpr(5, CelConstant.ofValue("hello")), - CelExpr.ofConstantExpr(6, CelConstant.ofValue(5))) + CelExpr.ofConstant(5, CelConstant.ofValue("hello")), + CelExpr.ofConstant(6, CelConstant.ofValue(5))) .build(); CelExpr celExpr = CelExpr.newBuilder() .setCall( celCall.toBuilder() - .setArg(1, CelExpr.ofConstantExpr(7, CelConstant.ofValue("world"))) + .setArg(1, CelExpr.ofConstant(7, CelConstant.ofValue("world"))) .build()) .build(); @@ -186,8 +186,8 @@ public void celExprBuilder_setCall_setArgByIndex() { CelCall.newBuilder() .setFunction("function") .addArgs( - CelExpr.ofConstantExpr(5, CelConstant.ofValue("hello")), - CelExpr.ofConstantExpr(7, CelConstant.ofValue("world"))) + CelExpr.ofConstant(5, CelConstant.ofValue("hello")), + CelExpr.ofConstant(7, CelConstant.ofValue("world"))) .build()); } @@ -206,7 +206,7 @@ public void celExprBuilder_setSelect() { public void celExprBuilder_setCreateList() { CelCreateList celCreateList = CelCreateList.newBuilder() - .addElements(CelExpr.ofConstantExpr(1, CelConstant.ofValue(2))) + .addElements(CelExpr.ofConstant(1, CelConstant.ofValue(2))) .build(); CelExpr celExpr = CelExpr.newBuilder().setCreateList(celCreateList).build(); @@ -218,11 +218,11 @@ public void celExprBuilder_setCreateList() { public void createListBuilder_getArgs() { CelCreateList celCreateList = CelCreateList.newBuilder() - .addElements(CelExpr.ofConstantExpr(1, CelConstant.ofValue(2))) + .addElements(CelExpr.ofConstant(1, CelConstant.ofValue(2))) .build(); assertThat(celCreateList.toBuilder().getElements()) - .containsExactly(CelExpr.ofConstantExpr(1, CelConstant.ofValue(2))); + .containsExactly(CelExpr.ofConstant(1, CelConstant.ofValue(2))); } @Test @@ -230,15 +230,15 @@ public void celExprBuilder_setCreateList_setElementByIndex() { CelCreateList celCreateList = CelCreateList.newBuilder() .addElements( - CelExpr.ofConstantExpr(5, CelConstant.ofValue("hello")), - CelExpr.ofConstantExpr(6, CelConstant.ofValue(5))) + CelExpr.ofConstant(5, CelConstant.ofValue("hello")), + CelExpr.ofConstant(6, CelConstant.ofValue(5))) .build(); CelExpr celExpr = CelExpr.newBuilder() .setCreateList( celCreateList.toBuilder() - .setElement(1, CelExpr.ofConstantExpr(7, CelConstant.ofValue("world"))) + .setElement(1, CelExpr.ofConstant(7, CelConstant.ofValue("world"))) .build()) .build(); @@ -246,8 +246,8 @@ public void celExprBuilder_setCreateList_setElementByIndex() { .isEqualTo( CelCreateList.newBuilder() .addElements( - CelExpr.ofConstantExpr(5, CelConstant.ofValue("hello")), - CelExpr.ofConstantExpr(7, CelConstant.ofValue("world"))) + CelExpr.ofConstant(5, CelConstant.ofValue("hello")), + CelExpr.ofConstant(7, CelConstant.ofValue("world"))) .build()); } @@ -298,13 +298,13 @@ public void celExprBuilder_setCreateStruct_setEntryByIndex() { CelCreateStruct.Entry.newBuilder() .setId(2) .setValue( - CelExpr.ofConstantExpr(5, CelConstant.ofValue("hello")).toBuilder().build()) + CelExpr.ofConstant(5, CelConstant.ofValue("hello")).toBuilder().build()) .setFieldKey("field_key") .build(), CelCreateStruct.Entry.newBuilder() .setId(3) .setValue( - CelExpr.ofConstantExpr(6, CelConstant.ofValue(100)).toBuilder().build()) + CelExpr.ofConstant(6, CelConstant.ofValue(100)).toBuilder().build()) .setFieldKey("field_key") .build()) .build(); @@ -318,7 +318,7 @@ public void celExprBuilder_setCreateStruct_setEntryByIndex() { CelCreateStruct.Entry.newBuilder() .setId(4) .setValue( - CelExpr.ofConstantExpr(6, CelConstant.ofValue("world")).toBuilder() + CelExpr.ofConstant(6, CelConstant.ofValue("world")).toBuilder() .build()) .setFieldKey("field_key") .build()) @@ -332,14 +332,14 @@ public void celExprBuilder_setCreateStruct_setEntryByIndex() { CelCreateStruct.Entry.newBuilder() .setId(2) .setValue( - CelExpr.ofConstantExpr(5, CelConstant.ofValue("hello")).toBuilder() + CelExpr.ofConstant(5, CelConstant.ofValue("hello")).toBuilder() .build()) .setFieldKey("field_key") .build(), CelCreateStruct.Entry.newBuilder() .setId(4) .setValue( - CelExpr.ofConstantExpr(6, CelConstant.ofValue("world")).toBuilder() + CelExpr.ofConstant(6, CelConstant.ofValue("world")).toBuilder() .build()) .setFieldKey("field_key") .build()) diff --git a/common/src/test/java/dev/cel/common/ast/CelExprV1Alpha1ConverterTest.java b/common/src/test/java/dev/cel/common/ast/CelExprV1Alpha1ConverterTest.java index 283fecafa..8a5461a11 100644 --- a/common/src/test/java/dev/cel/common/ast/CelExprV1Alpha1ConverterTest.java +++ b/common/src/test/java/dev/cel/common/ast/CelExprV1Alpha1ConverterTest.java @@ -43,50 +43,50 @@ public class CelExprV1Alpha1ConverterTest { private enum ConstantTestCase { NOT_SET( Expr.newBuilder().setId(1).setConstExpr(Constant.getDefaultInstance()).build(), - CelExpr.ofConstantExpr(1, CelConstant.ofNotSet())), + CelExpr.ofConstant(1, CelConstant.ofNotSet())), NULL( Expr.newBuilder() .setId(1) .setConstExpr(Constant.newBuilder().setNullValue(NullValue.NULL_VALUE).build()) .build(), - CelExpr.ofConstantExpr(1, CelConstant.ofValue(NullValue.NULL_VALUE))), + CelExpr.ofConstant(1, CelConstant.ofValue(NullValue.NULL_VALUE))), BOOLEAN( Expr.newBuilder() .setId(1) .setConstExpr(Constant.newBuilder().setBoolValue(true).build()) .build(), - CelExpr.ofConstantExpr(1, CelConstant.ofValue(true))), + CelExpr.ofConstant(1, CelConstant.ofValue(true))), INT64( Expr.newBuilder() .setId(1) .setConstExpr(Constant.newBuilder().setInt64Value(10).build()) .build(), - CelExpr.ofConstantExpr(1, CelConstant.ofValue(10))), + CelExpr.ofConstant(1, CelConstant.ofValue(10))), UINT64( Expr.newBuilder() .setId(1) .setConstExpr(Constant.newBuilder().setUint64Value(15).build()) .build(), - CelExpr.ofConstantExpr(1, CelConstant.ofValue(UnsignedLong.valueOf(15)))), + CelExpr.ofConstant(1, CelConstant.ofValue(UnsignedLong.valueOf(15)))), DOUBLE( Expr.newBuilder() .setId(1) .setConstExpr(Constant.newBuilder().setDoubleValue(1.5).build()) .build(), - CelExpr.ofConstantExpr(1, CelConstant.ofValue(1.5))), + CelExpr.ofConstant(1, CelConstant.ofValue(1.5))), STRING( Expr.newBuilder() .setId(1) .setConstExpr(Constant.newBuilder().setStringValue("Test").build()) .build(), - CelExpr.ofConstantExpr(1, CelConstant.ofValue("Test"))), + CelExpr.ofConstant(1, CelConstant.ofValue("Test"))), BYTES( Expr.newBuilder() .setId(1) .setConstExpr( Constant.newBuilder().setBytesValue(ByteString.copyFromUtf8("TEST")).build()) .build(), - CelExpr.ofConstantExpr(1, CelConstant.ofValue(ByteString.copyFromUtf8("TEST")))); + CelExpr.ofConstant(1, CelConstant.ofValue(ByteString.copyFromUtf8("TEST")))); final Expr protoExpr; final CelExpr celExpr; @@ -122,7 +122,7 @@ public void convertExprIdent_toCelIdent() { CelExpr celExpr = CelExprV1Alpha1Converter.fromExpr(expr); - assertThat(celExpr).isEqualTo(CelExpr.ofIdentExpr(2, "Test")); + assertThat(celExpr).isEqualTo(CelExpr.ofIdent(2, "Test")); } @Test @@ -146,8 +146,8 @@ public void convertExprSelect_toCelSelect(boolean isTestOnly) { assertThat(celExpr) .isEqualTo( - CelExpr.ofSelectExpr( - 3, CelExpr.ofConstantExpr(4, CelConstant.ofValue(true)), "field", isTestOnly)); + CelExpr.ofSelect( + 3, CelExpr.ofConstant(4, CelConstant.ofValue(true)), "field", isTestOnly)); } @Test @@ -167,11 +167,11 @@ public void convertExprCall_toCelCall() { assertThat(celExpr) .isEqualTo( - CelExpr.ofCallExpr( + CelExpr.ofCall( 1, - Optional.of(CelExpr.ofConstantExpr(2, CelConstant.ofValue(10))), + Optional.of(CelExpr.ofConstant(2, CelConstant.ofValue(10))), "func", - ImmutableList.of(CelExpr.ofConstantExpr(3, CelConstant.ofValue(20))))); + ImmutableList.of(CelExpr.ofConstant(3, CelConstant.ofValue(20))))); } @Test @@ -191,11 +191,11 @@ public void convertExprList_toCelList() { assertThat(celExpr) .isEqualTo( - CelExpr.ofCreateListExpr( + CelExpr.ofCreateList( 1, ImmutableList.of( - CelExpr.ofConstantExpr(2, CelConstant.ofValue(10)), - CelExpr.ofConstantExpr(3, CelConstant.ofValue(15))), + CelExpr.ofConstant(2, CelConstant.ofValue(10)), + CelExpr.ofConstant(3, CelConstant.ofValue(15))), ImmutableList.of(1))); } @@ -221,12 +221,12 @@ public void convertExprStructExpr_toCelStruct() { assertThat(celExpr) .isEqualTo( - CelExpr.ofCreateStructExpr( + CelExpr.ofCreateStruct( 1, "messageName", ImmutableList.of( - CelExpr.ofCreateStructEntryExpr( - 2, "fieldKey", CelExpr.ofConstantExpr(3, CelConstant.ofValue(10)), true)))); + CelExpr.ofCreateStructEntry( + 2, "fieldKey", CelExpr.ofConstant(3, CelConstant.ofValue(10)), true)))); } @Test @@ -299,13 +299,13 @@ public void convertExprStructExpr_toCelMap() { assertThat(celExpr) .isEqualTo( - CelExpr.ofCreateMapExpr( + CelExpr.ofCreateMap( 1, ImmutableList.of( - CelExpr.ofCreateMapEntryExpr( + CelExpr.ofCreateMapEntry( 2, - CelExpr.ofConstantExpr(3, CelConstant.ofValue(15)), - CelExpr.ofConstantExpr(4, CelConstant.ofValue(10)), + CelExpr.ofConstant(3, CelConstant.ofValue(15)), + CelExpr.ofConstant(4, CelConstant.ofValue(10)), true)))); } @@ -341,12 +341,12 @@ public void convertExprComprehensionExpr_toCelComprehension() { CelExpr.ofComprehension( 1, "iterVar", - CelExpr.ofConstantExpr(2, CelConstant.ofValue(10)), + CelExpr.ofConstant(2, CelConstant.ofValue(10)), "accuVar", - CelExpr.ofConstantExpr(3, CelConstant.ofValue(20)), - CelExpr.ofCallExpr(4, Optional.empty(), "testCondition", ImmutableList.of()), - CelExpr.ofCallExpr(5, Optional.empty(), "testStep", ImmutableList.of()), - CelExpr.ofConstantExpr(6, CelConstant.ofValue(30)))); + CelExpr.ofConstant(3, CelConstant.ofValue(20)), + CelExpr.ofCall(4, Optional.empty(), "testCondition", ImmutableList.of()), + CelExpr.ofCall(5, Optional.empty(), "testStep", ImmutableList.of()), + CelExpr.ofConstant(6, CelConstant.ofValue(30)))); } @Test @@ -390,7 +390,7 @@ public void convertCelNotSet_toExprNotSet() { @Test public void convertCelIdent_toExprIdent() { - CelExpr celExpr = CelExpr.ofIdentExpr(2, "Test"); + CelExpr celExpr = CelExpr.ofIdent(2, "Test"); Expr expr = CelExprV1Alpha1Converter.fromCelExpr(celExpr); @@ -407,8 +407,7 @@ public void convertCelIdent_toExprIdent() { @TestParameters("{isTestOnly: false}") public void convertCelSelect_toExprSelect(boolean isTestOnly) { CelExpr celExpr = - CelExpr.ofSelectExpr( - 3, CelExpr.ofConstantExpr(4, CelConstant.ofValue(true)), "field", isTestOnly); + CelExpr.ofSelect(3, CelExpr.ofConstant(4, CelConstant.ofValue(true)), "field", isTestOnly); Expr expr = CelExprV1Alpha1Converter.fromCelExpr(celExpr); @@ -430,11 +429,11 @@ public void convertCelSelect_toExprSelect(boolean isTestOnly) { @Test public void convertCelCall_toExprCall() { CelExpr celExpr = - CelExpr.ofCallExpr( + CelExpr.ofCall( 1, - Optional.of(CelExpr.ofConstantExpr(2, CelConstant.ofValue(10))), + Optional.of(CelExpr.ofConstant(2, CelConstant.ofValue(10))), "func", - ImmutableList.of(CelExpr.ofConstantExpr(3, CelConstant.ofValue(20)))); + ImmutableList.of(CelExpr.ofConstant(3, CelConstant.ofValue(20)))); Expr expr = CelExprV1Alpha1Converter.fromCelExpr(celExpr); @@ -454,11 +453,11 @@ public void convertCelCall_toExprCall() { @Test public void convertCelList_toExprList() { CelExpr celExpr = - CelExpr.ofCreateListExpr( + CelExpr.ofCreateList( 1, ImmutableList.of( - CelExpr.ofConstantExpr(2, CelConstant.ofValue(10)), - CelExpr.ofConstantExpr(3, CelConstant.ofValue(15))), + CelExpr.ofConstant(2, CelConstant.ofValue(10)), + CelExpr.ofConstant(3, CelConstant.ofValue(15))), ImmutableList.of(1)); Expr expr = CelExprV1Alpha1Converter.fromCelExpr(celExpr); @@ -479,12 +478,12 @@ public void convertCelList_toExprList() { @Test public void convertCelStructExpr_toExprStruct_withFieldKey() { CelExpr celExpr = - CelExpr.ofCreateStructExpr( + CelExpr.ofCreateStruct( 1, "messageName", ImmutableList.of( - CelExpr.ofCreateStructEntryExpr( - 2, "fieldKey", CelExpr.ofConstantExpr(3, CelConstant.ofValue(10)), true))); + CelExpr.ofCreateStructEntry( + 2, "fieldKey", CelExpr.ofConstant(3, CelConstant.ofValue(10)), true))); Expr expr = CelExprV1Alpha1Converter.fromCelExpr(celExpr); @@ -509,13 +508,13 @@ public void convertCelStructExpr_toExprStruct_withFieldKey() { @Test public void convertCelMapExpr_toExprStruct() { CelExpr celExpr = - CelExpr.ofCreateMapExpr( + CelExpr.ofCreateMap( 1, ImmutableList.of( - CelExpr.ofCreateMapEntryExpr( + CelExpr.ofCreateMapEntry( 2, - CelExpr.ofConstantExpr(3, CelConstant.ofValue(15)), - CelExpr.ofConstantExpr(4, CelConstant.ofValue(10)), + CelExpr.ofConstant(3, CelConstant.ofValue(15)), + CelExpr.ofConstant(4, CelConstant.ofValue(10)), true))); Expr expr = CelExprV1Alpha1Converter.fromCelExpr(celExpr); @@ -543,12 +542,12 @@ public void convertCelComprehensionExpr_toExprComprehension() { CelExpr.ofComprehension( 1, "iterVar", - CelExpr.ofConstantExpr(2, CelConstant.ofValue(10)), + CelExpr.ofConstant(2, CelConstant.ofValue(10)), "accuVar", - CelExpr.ofConstantExpr(3, CelConstant.ofValue(20)), - CelExpr.ofCallExpr(4, Optional.empty(), "testCondition", ImmutableList.of()), - CelExpr.ofCallExpr(5, Optional.empty(), "testStep", ImmutableList.of()), - CelExpr.ofConstantExpr(6, CelConstant.ofValue(30))); + CelExpr.ofConstant(3, CelConstant.ofValue(20)), + CelExpr.ofCall(4, Optional.empty(), "testCondition", ImmutableList.of()), + CelExpr.ofCall(5, Optional.empty(), "testStep", ImmutableList.of()), + CelExpr.ofConstant(6, CelConstant.ofValue(30))); Expr expr = CelExprV1Alpha1Converter.fromCelExpr(celExpr); diff --git a/common/src/test/java/dev/cel/common/ast/CelExprVisitorTest.java b/common/src/test/java/dev/cel/common/ast/CelExprVisitorTest.java index 1926eb31e..5cfcef44e 100644 --- a/common/src/test/java/dev/cel/common/ast/CelExprVisitorTest.java +++ b/common/src/test/java/dev/cel/common/ast/CelExprVisitorTest.java @@ -237,10 +237,10 @@ public void visitCall() throws Exception { .setCall( CelCall.newBuilder() .setFunction("contains") - .setTarget(CelExpr.ofConstantExpr(1, CelConstant.ofValue("hi"))) - .addArgs(CelExpr.ofConstantExpr(3, stringVal)) + .setTarget(CelExpr.ofConstant(1, CelConstant.ofValue("hi"))) + .addArgs(CelExpr.ofConstant(3, stringVal)) .build()) - .addArguments(CelExpr.ofConstantExpr(3, stringVal)) + .addArguments(CelExpr.ofConstant(3, stringVal)) .build()); } @@ -267,7 +267,7 @@ public void visitCreateStruct_fieldkey() throws Exception { Entry.newBuilder() .setId(2) .setFieldKey("single_int64") - .setValue(CelExpr.ofConstantExpr(3, longConstant)) + .setValue(CelExpr.ofConstant(3, longConstant)) .build()) .setMessageName("TestAllTypes") .build()) @@ -291,8 +291,8 @@ public void visitCreateMap() throws Exception { .addEntries( CelCreateMap.Entry.newBuilder() .setId(2) - .setKey(CelExpr.ofConstantExpr(3, CelConstant.ofValue("a"))) - .setValue(CelExpr.ofConstantExpr(4, CelConstant.ofValue("b"))) + .setKey(CelExpr.ofConstant(3, CelConstant.ofValue("a"))) + .setValue(CelExpr.ofConstant(4, CelConstant.ofValue("b"))) .build()) .build()) .build()); @@ -333,8 +333,8 @@ public void visitComprehension() throws Exception { CelComprehension comprehension = visitedReference.comprehension().get(); ImmutableList iterRangeElements = ImmutableList.of( - CelExpr.ofConstantExpr(2, CelConstant.ofValue(1)), - CelExpr.ofConstantExpr(3, CelConstant.ofValue(1))); + CelExpr.ofConstant(2, CelConstant.ofValue(1)), + CelExpr.ofConstant(3, CelConstant.ofValue(1))); assertThat(comprehension.iterVar()).isEqualTo("x"); assertThat(comprehension.iterRange().createList().elements()).isEqualTo(iterRangeElements); diff --git a/common/src/test/java/dev/cel/common/ast/CelMutableExprConverterTest.java b/common/src/test/java/dev/cel/common/ast/CelMutableExprConverterTest.java index 44a020a0e..06e8ff41e 100644 --- a/common/src/test/java/dev/cel/common/ast/CelMutableExprConverterTest.java +++ b/common/src/test/java/dev/cel/common/ast/CelMutableExprConverterTest.java @@ -40,28 +40,28 @@ public class CelMutableExprConverterTest { private enum ConstantTestCase { NOT_SET( CelMutableExpr.ofConstant(1, CelConstant.ofNotSet()), - CelExpr.ofConstantExpr(1, CelConstant.ofNotSet())), + CelExpr.ofConstant(1, CelConstant.ofNotSet())), NULL( CelMutableExpr.ofConstant(1, CelConstant.ofValue(NullValue.NULL_VALUE)), - CelExpr.ofConstantExpr(1, CelConstant.ofValue(NullValue.NULL_VALUE))), + CelExpr.ofConstant(1, CelConstant.ofValue(NullValue.NULL_VALUE))), BOOLEAN( CelMutableExpr.ofConstant(1, CelConstant.ofValue(true)), - CelExpr.ofConstantExpr(1, CelConstant.ofValue(true))), + CelExpr.ofConstant(1, CelConstant.ofValue(true))), INT64( CelMutableExpr.ofConstant(1, CelConstant.ofValue(10)), - CelExpr.ofConstantExpr(1, CelConstant.ofValue(10))), + CelExpr.ofConstant(1, CelConstant.ofValue(10))), UINT64( CelMutableExpr.ofConstant(1, CelConstant.ofValue(UnsignedLong.valueOf(15))), - CelExpr.ofConstantExpr(1, CelConstant.ofValue(UnsignedLong.valueOf(15)))), + CelExpr.ofConstant(1, CelConstant.ofValue(UnsignedLong.valueOf(15)))), DOUBLE( CelMutableExpr.ofConstant(1, CelConstant.ofValue(1.5)), - CelExpr.ofConstantExpr(1, CelConstant.ofValue(1.5))), + CelExpr.ofConstant(1, CelConstant.ofValue(1.5))), STRING( CelMutableExpr.ofConstant(1, CelConstant.ofValue("Test")), - CelExpr.ofConstantExpr(1, CelConstant.ofValue("Test"))), + CelExpr.ofConstant(1, CelConstant.ofValue("Test"))), BYTES( CelMutableExpr.ofConstant(1, CelConstant.ofValue(ByteString.copyFromUtf8("TEST"))), - CelExpr.ofConstantExpr(1, CelConstant.ofValue(ByteString.copyFromUtf8("TEST")))); + CelExpr.ofConstant(1, CelConstant.ofValue(ByteString.copyFromUtf8("TEST")))); final CelMutableExpr mutableExpr; final CelExpr celExpr; @@ -107,12 +107,12 @@ public void convertMutableIdent_toCelIdent() { CelExpr celExpr = CelMutableExprConverter.fromMutableExpr(mutableExpr); - assertThat(celExpr).isEqualTo(CelExpr.ofIdentExpr(1L, "x")); + assertThat(celExpr).isEqualTo(CelExpr.ofIdent(1L, "x")); } @Test public void convertCelIdent_toMutableIdent() { - CelExpr celExpr = CelExpr.ofIdentExpr(1L, "x"); + CelExpr celExpr = CelExpr.ofIdent(1L, "x"); CelMutableExpr mutableExpr = CelMutableExprConverter.fromCelExpr(celExpr); @@ -130,15 +130,13 @@ public void convertMutableSelect_toCelSelect() { CelExpr celExpr = CelMutableExprConverter.fromMutableExpr(mutableExpr); assertThat(celExpr) - .isEqualTo( - CelExpr.ofSelectExpr( - 1L, CelExpr.ofIdentExpr(2L, "x"), "field", /* isTestOnly= */ true)); + .isEqualTo(CelExpr.ofSelect(1L, CelExpr.ofIdent(2L, "x"), "field", /* isTestOnly= */ true)); } @Test public void convertCelSelect_toMutableSelect() { CelExpr celExpr = - CelExpr.ofSelectExpr(1L, CelExpr.ofIdentExpr(2L, "x"), "field", /* isTestOnly= */ true); + CelExpr.ofSelect(1L, CelExpr.ofIdent(2L, "x"), "field", /* isTestOnly= */ true); CelMutableExpr mutableExpr = CelMutableExprConverter.fromCelExpr(celExpr); @@ -169,8 +167,8 @@ public void convertMutableCall_toCelCall() { .setCall( CelCall.newBuilder() .setFunction("function") - .setTarget(CelExpr.ofConstantExpr(2L, CelConstant.ofValue("target"))) - .addArgs(CelExpr.ofConstantExpr(3L, CelConstant.ofValue("arg"))) + .setTarget(CelExpr.ofConstant(2L, CelConstant.ofValue("target"))) + .addArgs(CelExpr.ofConstant(3L, CelConstant.ofValue("arg"))) .build()) .build()); } @@ -183,8 +181,8 @@ public void convertCelCall_toMutableCall() { .setCall( CelCall.newBuilder() .setFunction("function") - .setTarget(CelExpr.ofConstantExpr(2L, CelConstant.ofValue("target"))) - .addArgs(CelExpr.ofConstantExpr(3L, CelConstant.ofValue("arg"))) + .setTarget(CelExpr.ofConstant(2L, CelConstant.ofValue("target"))) + .addArgs(CelExpr.ofConstant(3L, CelConstant.ofValue("arg"))) .build()) .build(); @@ -215,22 +213,22 @@ public void convertMutableCreateList_toCelCreateList() { assertThat(celExpr) .isEqualTo( - CelExpr.ofCreateListExpr( + CelExpr.ofCreateList( 1L, ImmutableList.of( - CelExpr.ofConstantExpr(2L, CelConstant.ofValue("element1")), - CelExpr.ofConstantExpr(3L, CelConstant.ofValue("element2"))), + CelExpr.ofConstant(2L, CelConstant.ofValue("element1")), + CelExpr.ofConstant(3L, CelConstant.ofValue("element2"))), ImmutableList.of(0, 1))); } @Test public void convertCelCreateList_toMutableCreateList() { CelExpr celExpr = - CelExpr.ofCreateListExpr( + CelExpr.ofCreateList( 1L, ImmutableList.of( - CelExpr.ofConstantExpr(2L, CelConstant.ofValue("element1")), - CelExpr.ofConstantExpr(3L, CelConstant.ofValue("element2"))), + CelExpr.ofConstant(2L, CelConstant.ofValue("element1")), + CelExpr.ofConstant(3L, CelConstant.ofValue("element2"))), ImmutableList.of(0, 1)); CelMutableExpr mutableExpr = CelMutableExprConverter.fromCelExpr(celExpr); @@ -264,14 +262,14 @@ public void convertMutableCreateStruct_toCelCreateStruct() { assertThat(celExpr) .isEqualTo( - CelExpr.ofCreateStructExpr( + CelExpr.ofCreateStruct( 8L, "message", ImmutableList.of( CelCreateStruct.Entry.newBuilder() .setId(9L) .setFieldKey("field") - .setValue(CelExpr.ofConstantExpr(10L, CelConstant.ofValue("value"))) + .setValue(CelExpr.ofConstant(10L, CelConstant.ofValue("value"))) .setOptionalEntry(true) .build()))); } @@ -279,14 +277,14 @@ public void convertMutableCreateStruct_toCelCreateStruct() { @Test public void convertCelCreateStruct_toMutableCreateStruct() { CelExpr celExpr = - CelExpr.ofCreateStructExpr( + CelExpr.ofCreateStruct( 8L, "message", ImmutableList.of( CelCreateStruct.Entry.newBuilder() .setId(9L) .setFieldKey("field") - .setValue(CelExpr.ofConstantExpr(10L, CelConstant.ofValue("value"))) + .setValue(CelExpr.ofConstant(10L, CelConstant.ofValue("value"))) .setOptionalEntry(true) .build())); @@ -323,26 +321,26 @@ public void convertMutableCreateMap_toCelCreateMap() { assertThat(celExpr) .isEqualTo( - CelExpr.ofCreateMapExpr( + CelExpr.ofCreateMap( 9L, ImmutableList.of( - CelExpr.ofCreateMapEntryExpr( + CelExpr.ofCreateMapEntry( 10L, - CelExpr.ofConstantExpr(11L, CelConstant.ofValue("key")), - CelExpr.ofConstantExpr(12L, CelConstant.ofValue("value")), + CelExpr.ofConstant(11L, CelConstant.ofValue("key")), + CelExpr.ofConstant(12L, CelConstant.ofValue("value")), true)))); } @Test public void convertCelCreateMap_toMutableCreateMap() { CelExpr celExpr = - CelExpr.ofCreateMapExpr( + CelExpr.ofCreateMap( 9L, ImmutableList.of( - CelExpr.ofCreateMapEntryExpr( + CelExpr.ofCreateMapEntry( 10L, - CelExpr.ofConstantExpr(11L, CelConstant.ofValue("key")), - CelExpr.ofConstantExpr(12L, CelConstant.ofValue("value")), + CelExpr.ofConstant(11L, CelConstant.ofValue("key")), + CelExpr.ofConstant(12L, CelConstant.ofValue("value")), true))); CelMutableExpr mutableExpr = CelMutableExprConverter.fromCelExpr(celExpr); @@ -388,14 +386,14 @@ public void convertMutableComprehension_toCelComprehension() { .setId(2L) .setCreateList( CelCreateList.newBuilder() - .addElements(CelExpr.ofConstantExpr(3L, CelConstant.ofValue(true))) + .addElements(CelExpr.ofConstant(3L, CelConstant.ofValue(true))) .build()) .build(), "accuVar", - CelExpr.ofConstantExpr(4L, CelConstant.ofValue(true)), - CelExpr.ofConstantExpr(5L, CelConstant.ofValue(true)), - CelExpr.ofConstantExpr(6L, CelConstant.ofValue(true)), - CelExpr.ofIdentExpr(7L, "__result__"))); + CelExpr.ofConstant(4L, CelConstant.ofValue(true)), + CelExpr.ofConstant(5L, CelConstant.ofValue(true)), + CelExpr.ofConstant(6L, CelConstant.ofValue(true)), + CelExpr.ofIdent(7L, "__result__"))); } @Test @@ -408,14 +406,14 @@ public void convertCelComprehension_toMutableComprehension() { .setId(2L) .setCreateList( CelCreateList.newBuilder() - .addElements(CelExpr.ofConstantExpr(3L, CelConstant.ofValue(true))) + .addElements(CelExpr.ofConstant(3L, CelConstant.ofValue(true))) .build()) .build(), "accuVar", - CelExpr.ofConstantExpr(4L, CelConstant.ofValue(true)), - CelExpr.ofConstantExpr(5L, CelConstant.ofValue(true)), - CelExpr.ofConstantExpr(6L, CelConstant.ofValue(true)), - CelExpr.ofIdentExpr(7L, "__result__")); + CelExpr.ofConstant(4L, CelConstant.ofValue(true)), + CelExpr.ofConstant(5L, CelConstant.ofValue(true)), + CelExpr.ofConstant(6L, CelConstant.ofValue(true)), + CelExpr.ofIdent(7L, "__result__")); CelMutableExpr mutableExpr = CelMutableExprConverter.fromCelExpr(celExpr); diff --git a/common/src/test/java/dev/cel/common/navigation/CelNavigableAstTest.java b/common/src/test/java/dev/cel/common/navigation/CelNavigableAstTest.java index 40f772810..6fa4cd203 100644 --- a/common/src/test/java/dev/cel/common/navigation/CelNavigableAstTest.java +++ b/common/src/test/java/dev/cel/common/navigation/CelNavigableAstTest.java @@ -37,7 +37,7 @@ public void construct_success() throws Exception { assertThat(navigableAst.getAst()).isEqualTo(ast); assertThat(navigableAst.getRoot().expr()) - .isEqualTo(CelExpr.ofConstantExpr(1, CelConstant.ofValue("Hello World"))); + .isEqualTo(CelExpr.ofConstant(1, CelConstant.ofValue("Hello World"))); assertThat(navigableAst.getRoot().parent()).isEmpty(); assertThat(navigableAst.getRoot().depth()).isEqualTo(0); } diff --git a/common/src/test/java/dev/cel/common/navigation/CelNavigableExprTest.java b/common/src/test/java/dev/cel/common/navigation/CelNavigableExprTest.java index 261524df0..69b244708 100644 --- a/common/src/test/java/dev/cel/common/navigation/CelNavigableExprTest.java +++ b/common/src/test/java/dev/cel/common/navigation/CelNavigableExprTest.java @@ -27,7 +27,7 @@ public class CelNavigableExprTest { @Test public void construct_withoutParent_success() { - CelExpr constExpr = CelExpr.ofConstantExpr(1, CelConstant.ofValue("test")); + CelExpr constExpr = CelExpr.ofConstant(1, CelConstant.ofValue("test")); CelNavigableExpr navigableExpr = CelNavigableExpr.builder().setExpr(constExpr).setDepth(2).build(); @@ -38,8 +38,8 @@ public void construct_withoutParent_success() { @Test public void construct_withParent_success() { - CelExpr constExpr = CelExpr.ofConstantExpr(1, CelConstant.ofValue("test")); - CelExpr identExpr = CelExpr.ofIdentExpr(2, "a"); + CelExpr constExpr = CelExpr.ofConstant(1, CelConstant.ofValue("test")); + CelExpr identExpr = CelExpr.ofIdent(2, "a"); CelNavigableExpr parentExpr = CelNavigableExpr.builder().setExpr(identExpr).setDepth(1).build(); CelNavigableExpr navigableExpr = CelNavigableExpr.builder().setExpr(constExpr).setDepth(2).setParent(parentExpr).build(); diff --git a/common/src/test/java/dev/cel/common/navigation/CelNavigableExprVisitorTest.java b/common/src/test/java/dev/cel/common/navigation/CelNavigableExprVisitorTest.java index 4af7a7e83..18c71cb28 100644 --- a/common/src/test/java/dev/cel/common/navigation/CelNavigableExprVisitorTest.java +++ b/common/src/test/java/dev/cel/common/navigation/CelNavigableExprVisitorTest.java @@ -85,26 +85,26 @@ public void add_allNodes_allNodesReturned() throws Exception { navigableAst.getRoot().allNodes().map(CelNavigableExpr::expr).collect(toImmutableList()); CelExpr childAddCall = - CelExpr.ofCallExpr( + CelExpr.ofCall( 2, Optional.empty(), Operator.ADD.getFunction(), ImmutableList.of( - CelExpr.ofConstantExpr(1, CelConstant.ofValue(1)), // 1 + a - CelExpr.ofIdentExpr(3, "a"))); + CelExpr.ofConstant(1, CelConstant.ofValue(1)), // 1 + a + CelExpr.ofIdent(3, "a"))); CelExpr rootAddCall = - CelExpr.ofCallExpr( + CelExpr.ofCall( 4, Optional.empty(), Operator.ADD.getFunction(), - ImmutableList.of(childAddCall, CelExpr.ofConstantExpr(5, CelConstant.ofValue(2)))); + ImmutableList.of(childAddCall, CelExpr.ofConstant(5, CelConstant.ofValue(2)))); assertThat(allNodes) .containsExactly( rootAddCall, childAddCall, - CelExpr.ofConstantExpr(1, CelConstant.ofValue(1)), - CelExpr.ofIdentExpr(3, "a"), - CelExpr.ofConstantExpr(5, CelConstant.ofValue(2))); + CelExpr.ofConstant(1, CelConstant.ofValue(1)), + CelExpr.ofIdent(3, "a"), + CelExpr.ofConstant(5, CelConstant.ofValue(2))); } @Test @@ -310,10 +310,8 @@ public void add_filterConstants_allNodesReturned() throws Exception { .collect(toImmutableList()); assertThat(allConstants).hasSize(2); - assertThat(allConstants.get(0).expr()) - .isEqualTo(CelExpr.ofConstantExpr(1, CelConstant.ofValue(1))); - assertThat(allConstants.get(1).expr()) - .isEqualTo(CelExpr.ofConstantExpr(5, CelConstant.ofValue(2))); + assertThat(allConstants.get(0).expr()).isEqualTo(CelExpr.ofConstant(1, CelConstant.ofValue(1))); + assertThat(allConstants.get(1).expr()).isEqualTo(CelExpr.ofConstant(5, CelConstant.ofValue(2))); } @Test @@ -339,20 +337,19 @@ public void add_filterConstants_parentsPopulated() throws Exception { CelExpr rootAddCall = allConstants.get(1).parent().get().expr(); // childAddCall + 2 assertThat(childAddCall) .isEqualTo( - CelExpr.ofCallExpr( + CelExpr.ofCall( 2, Optional.empty(), Operator.ADD.getFunction(), ImmutableList.of( - CelExpr.ofConstantExpr(1, CelConstant.ofValue(1)), - CelExpr.ofIdentExpr(3, "a")))); + CelExpr.ofConstant(1, CelConstant.ofValue(1)), CelExpr.ofIdent(3, "a")))); assertThat(rootAddCall) .isEqualTo( - CelExpr.ofCallExpr( + CelExpr.ofCall( 4, Optional.empty(), Operator.ADD.getFunction(), - ImmutableList.of(childAddCall, CelExpr.ofConstantExpr(5, CelConstant.ofValue(2))))); + ImmutableList.of(childAddCall, CelExpr.ofConstant(5, CelConstant.ofValue(2))))); } @Test @@ -374,8 +371,7 @@ public void add_filterConstants_singleChildReturned() throws Exception { .collect(toImmutableList()); assertThat(allConstants).hasSize(1); - assertThat(allConstants.get(0).expr()) - .isEqualTo(CelExpr.ofConstantExpr(5, CelConstant.ofValue(2))); + assertThat(allConstants.get(0).expr()).isEqualTo(CelExpr.ofConstant(5, CelConstant.ofValue(2))); } @Test @@ -427,7 +423,7 @@ public void add_childrenOfMiddleBranch_success() throws Exception { // Assert that the children of add call in the middle branch are const(1) and ident("a") assertThat(children).hasSize(2); - assertThat(children.get(0).expr()).isEqualTo(CelExpr.ofConstantExpr(1, CelConstant.ofValue(1))); + assertThat(children.get(0).expr()).isEqualTo(CelExpr.ofConstant(1, CelConstant.ofValue(1))); assertThat(children.get(1).expr()).isEqualTo(ident.expr()); } @@ -498,9 +494,9 @@ public void message_allNodesReturned() throws Exception { ImmutableList allNodes = navigableAst.getRoot().allNodes().map(CelNavigableExpr::expr).collect(toImmutableList()); - CelExpr operand = CelExpr.ofIdentExpr(1, "msg"); + CelExpr operand = CelExpr.ofIdent(1, "msg"); assertThat(allNodes) - .containsExactly(operand, CelExpr.ofSelectExpr(2, operand, "single_int64", false)); + .containsExactly(operand, CelExpr.ofSelect(2, operand, "single_int64", false)); } @Test @@ -522,9 +518,9 @@ public void nestedMessage_filterSelect_allNodesReturned() throws Exception { .collect(toImmutableList()); CelExpr innerSelect = - CelExpr.ofSelectExpr( - 2, CelExpr.ofIdentExpr(1, "msg"), "standalone_message", false); // msg.standalone - CelExpr outerSelect = CelExpr.ofSelectExpr(3, innerSelect, "bb", false); // innerSelect.bb + CelExpr.ofSelect( + 2, CelExpr.ofIdent(1, "msg"), "standalone_message", false); // msg.standalone + CelExpr outerSelect = CelExpr.ofSelect(3, innerSelect, "bb", false); // innerSelect.bb assertThat(allSelects).containsExactly(innerSelect, outerSelect); } @@ -552,9 +548,9 @@ public void nestedMessage_filterSelect_singleChildReturned() throws Exception { assertThat(allSelects).hasSize(1); CelExpr innerSelect = - CelExpr.ofSelectExpr( - 4, CelExpr.ofIdentExpr(3, "msg"), "standalone_message", false); // msg.standalone - CelExpr outerSelect = CelExpr.ofSelectExpr(5, innerSelect, "bb", false); // innerSelect.bb + CelExpr.ofSelect( + 4, CelExpr.ofIdent(3, "msg"), "standalone_message", false); // msg.standalone + CelExpr outerSelect = CelExpr.ofSelect(5, innerSelect, "bb", false); // innerSelect.bb assertThat(allSelects.get(0).expr()).isEqualTo(outerSelect); } @@ -575,8 +571,8 @@ public void presenceTest_allNodesReturned() throws Exception { assertThat(allNodes).hasSize(2); assertThat(allNodes) .containsExactly( - CelExpr.ofIdentExpr(2, "msg"), - CelExpr.ofSelectExpr(4, CelExpr.ofIdentExpr(2, "msg"), "standalone_message", true)); + CelExpr.ofIdent(2, "msg"), + CelExpr.ofSelect(4, CelExpr.ofIdent(2, "msg"), "standalone_message", true)); } @Test @@ -592,15 +588,15 @@ public void messageConstruction_allNodesReturned() throws Exception { ImmutableList allNodes = navigableAst.getRoot().allNodes().map(CelNavigableExpr::expr).collect(toImmutableList()); - CelExpr constExpr = CelExpr.ofConstantExpr(3, CelConstant.ofValue(1)); + CelExpr constExpr = CelExpr.ofConstant(3, CelConstant.ofValue(1)); assertThat(allNodes) .containsExactly( constExpr, - CelExpr.ofCreateStructExpr( + CelExpr.ofCreateStruct( 1, "TestAllTypes", ImmutableList.of( - CelExpr.ofCreateStructEntryExpr(2, "single_int64", constExpr, false)))); + CelExpr.ofCreateStructEntry(2, "single_int64", constExpr, false)))); } @Test @@ -623,15 +619,12 @@ public void messageConstruction_filterCreateStruct_allNodesReturned() throws Exc assertThat(allNodes).hasSize(1); assertThat(allNodes.get(0).expr()) .isEqualTo( - CelExpr.ofCreateStructExpr( + CelExpr.ofCreateStruct( 1, "TestAllTypes", ImmutableList.of( - CelExpr.ofCreateStructEntryExpr( - 2, - "single_int64", - CelExpr.ofConstantExpr(3, CelConstant.ofValue(1)), - false)))); + CelExpr.ofCreateStructEntry( + 2, "single_int64", CelExpr.ofConstant(3, CelConstant.ofValue(1)), false)))); } @Test @@ -705,16 +698,14 @@ public void mapConstruction_allNodesReturned() throws Exception { navigableAst.getRoot().allNodes().map(CelNavigableExpr::expr).collect(toImmutableList()); assertThat(allNodes).hasSize(3); - CelExpr mapKeyExpr = CelExpr.ofConstantExpr(3, CelConstant.ofValue("key")); - CelExpr mapValueExpr = CelExpr.ofConstantExpr(4, CelConstant.ofValue(2)); + CelExpr mapKeyExpr = CelExpr.ofConstant(3, CelConstant.ofValue("key")); + CelExpr mapValueExpr = CelExpr.ofConstant(4, CelConstant.ofValue(2)); assertThat(allNodes) .containsExactly( mapKeyExpr, mapValueExpr, - CelExpr.ofCreateMapExpr( - 1, - ImmutableList.of( - CelExpr.ofCreateMapEntryExpr(2, mapKeyExpr, mapValueExpr, false)))); + CelExpr.ofCreateMap( + 1, ImmutableList.of(CelExpr.ofCreateMapEntry(2, mapKeyExpr, mapValueExpr, false)))); } @Test @@ -731,14 +722,12 @@ public void mapConstruction_filterCreateMap_allNodesReturned() throws Exception .collect(toImmutableList()); assertThat(allNodes).hasSize(1); - CelExpr mapKeyExpr = CelExpr.ofConstantExpr(3, CelConstant.ofValue("key")); - CelExpr mapValueExpr = CelExpr.ofConstantExpr(4, CelConstant.ofValue(2)); + CelExpr mapKeyExpr = CelExpr.ofConstant(3, CelConstant.ofValue("key")); + CelExpr mapValueExpr = CelExpr.ofConstant(4, CelConstant.ofValue(2)); assertThat(allNodes.get(0).expr()) .isEqualTo( - CelExpr.ofCreateMapExpr( - 1, - ImmutableList.of( - CelExpr.ofCreateMapEntryExpr(2, mapKeyExpr, mapValueExpr, false)))); + CelExpr.ofCreateMap( + 1, ImmutableList.of(CelExpr.ofCreateMapEntry(2, mapKeyExpr, mapValueExpr, false)))); } @Test @@ -815,7 +804,7 @@ public void emptyMapConstruction_allNodesReturned() throws Exception { navigableAst.getRoot().allNodes().collect(toImmutableList()); assertThat(allNodes).hasSize(1); - assertThat(allNodes.get(0).expr()).isEqualTo(CelExpr.ofCreateMapExpr(1, ImmutableList.of())); + assertThat(allNodes.get(0).expr()).isEqualTo(CelExpr.ofCreateMap(1, ImmutableList.of())); } @Test @@ -834,32 +823,32 @@ public void comprehension_preOrder_allNodesReturned() throws Exception { .map(CelNavigableExpr::expr) .collect(toImmutableList()); - CelExpr iterRangeConstExpr = CelExpr.ofConstantExpr(2, CelConstant.ofValue(true)); + CelExpr iterRangeConstExpr = CelExpr.ofConstant(2, CelConstant.ofValue(true)); CelExpr iterRange = - CelExpr.ofCreateListExpr(1, ImmutableList.of(iterRangeConstExpr), ImmutableList.of()); - CelExpr accuInit = CelExpr.ofConstantExpr(6, CelConstant.ofValue(false)); - CelExpr loopConditionIdentExpr = CelExpr.ofIdentExpr(7, "__result__"); + CelExpr.ofCreateList(1, ImmutableList.of(iterRangeConstExpr), ImmutableList.of()); + CelExpr accuInit = CelExpr.ofConstant(6, CelConstant.ofValue(false)); + CelExpr loopConditionIdentExpr = CelExpr.ofIdent(7, "__result__"); CelExpr loopConditionCallExpr = - CelExpr.ofCallExpr( + CelExpr.ofCall( 8, Optional.empty(), Operator.LOGICAL_NOT.getFunction(), ImmutableList.of(loopConditionIdentExpr)); CelExpr loopCondition = - CelExpr.ofCallExpr( + CelExpr.ofCall( 9, Optional.empty(), Operator.NOT_STRICTLY_FALSE.getFunction(), ImmutableList.of(loopConditionCallExpr)); - CelExpr loopStepResultExpr = CelExpr.ofIdentExpr(10, "__result__"); - CelExpr loopStepVarExpr = CelExpr.ofIdentExpr(5, "i"); + CelExpr loopStepResultExpr = CelExpr.ofIdent(10, "__result__"); + CelExpr loopStepVarExpr = CelExpr.ofIdent(5, "i"); CelExpr loopStep = - CelExpr.ofCallExpr( + CelExpr.ofCall( 11, Optional.empty(), Operator.LOGICAL_OR.getFunction(), ImmutableList.of(loopStepResultExpr, loopStepVarExpr)); - CelExpr result = CelExpr.ofIdentExpr(12, "__result__"); + CelExpr result = CelExpr.ofIdent(12, "__result__"); CelExpr comprehension = CelExpr.ofComprehension( 13, "i", iterRange, "__result__", accuInit, loopCondition, loopStep, result); @@ -896,32 +885,32 @@ public void comprehension_postOrder_allNodesReturned() throws Exception { .map(CelNavigableExpr::expr) .collect(toImmutableList()); - CelExpr iterRangeConstExpr = CelExpr.ofConstantExpr(2, CelConstant.ofValue(true)); + CelExpr iterRangeConstExpr = CelExpr.ofConstant(2, CelConstant.ofValue(true)); CelExpr iterRange = - CelExpr.ofCreateListExpr(1, ImmutableList.of(iterRangeConstExpr), ImmutableList.of()); - CelExpr accuInit = CelExpr.ofConstantExpr(6, CelConstant.ofValue(false)); - CelExpr loopConditionIdentExpr = CelExpr.ofIdentExpr(7, "__result__"); + CelExpr.ofCreateList(1, ImmutableList.of(iterRangeConstExpr), ImmutableList.of()); + CelExpr accuInit = CelExpr.ofConstant(6, CelConstant.ofValue(false)); + CelExpr loopConditionIdentExpr = CelExpr.ofIdent(7, "__result__"); CelExpr loopConditionCallExpr = - CelExpr.ofCallExpr( + CelExpr.ofCall( 8, Optional.empty(), Operator.LOGICAL_NOT.getFunction(), ImmutableList.of(loopConditionIdentExpr)); CelExpr loopCondition = - CelExpr.ofCallExpr( + CelExpr.ofCall( 9, Optional.empty(), Operator.NOT_STRICTLY_FALSE.getFunction(), ImmutableList.of(loopConditionCallExpr)); - CelExpr loopStepResultExpr = CelExpr.ofIdentExpr(10, "__result__"); - CelExpr loopStepVarExpr = CelExpr.ofIdentExpr(5, "i"); + CelExpr loopStepResultExpr = CelExpr.ofIdent(10, "__result__"); + CelExpr loopStepVarExpr = CelExpr.ofIdent(5, "i"); CelExpr loopStep = - CelExpr.ofCallExpr( + CelExpr.ofCall( 11, Optional.empty(), Operator.LOGICAL_OR.getFunction(), ImmutableList.of(loopStepResultExpr, loopStepVarExpr)); - CelExpr result = CelExpr.ofIdentExpr(12, "__result__"); + CelExpr result = CelExpr.ofIdent(12, "__result__"); CelExpr comprehension = CelExpr.ofComprehension( 13, "i", iterRange, "__result__", accuInit, loopCondition, loopStep, result); @@ -1029,32 +1018,32 @@ public void comprehension_allNodes_parentsPopulated() throws Exception { ImmutableList allNodes = navigableAst.getRoot().allNodes(TraversalOrder.PRE_ORDER).collect(toImmutableList()); - CelExpr iterRangeConstExpr = CelExpr.ofConstantExpr(2, CelConstant.ofValue(true)); + CelExpr iterRangeConstExpr = CelExpr.ofConstant(2, CelConstant.ofValue(true)); CelExpr iterRange = - CelExpr.ofCreateListExpr(1, ImmutableList.of(iterRangeConstExpr), ImmutableList.of()); - CelExpr accuInit = CelExpr.ofConstantExpr(6, CelConstant.ofValue(false)); - CelExpr loopConditionIdentExpr = CelExpr.ofIdentExpr(7, "__result__"); + CelExpr.ofCreateList(1, ImmutableList.of(iterRangeConstExpr), ImmutableList.of()); + CelExpr accuInit = CelExpr.ofConstant(6, CelConstant.ofValue(false)); + CelExpr loopConditionIdentExpr = CelExpr.ofIdent(7, "__result__"); CelExpr loopConditionCallExpr = - CelExpr.ofCallExpr( + CelExpr.ofCall( 8, Optional.empty(), Operator.LOGICAL_NOT.getFunction(), ImmutableList.of(loopConditionIdentExpr)); CelExpr loopCondition = - CelExpr.ofCallExpr( + CelExpr.ofCall( 9, Optional.empty(), Operator.NOT_STRICTLY_FALSE.getFunction(), ImmutableList.of(loopConditionCallExpr)); - CelExpr loopStepResultExpr = CelExpr.ofIdentExpr(10, "__result__"); - CelExpr loopStepVarExpr = CelExpr.ofIdentExpr(5, "i"); + CelExpr loopStepResultExpr = CelExpr.ofIdent(10, "__result__"); + CelExpr loopStepVarExpr = CelExpr.ofIdent(5, "i"); CelExpr loopStep = - CelExpr.ofCallExpr( + CelExpr.ofCall( 11, Optional.empty(), Operator.LOGICAL_OR.getFunction(), ImmutableList.of(loopStepResultExpr, loopStepVarExpr)); - CelExpr result = CelExpr.ofIdentExpr(12, "__result__"); + CelExpr result = CelExpr.ofIdent(12, "__result__"); CelExpr comprehension = CelExpr.ofComprehension( 13, "i", iterRange, "__result__", accuInit, loopCondition, loopStep, result); @@ -1093,32 +1082,32 @@ public void comprehension_filterComprehension_allNodesReturned() throws Exceptio .filter(x -> x.getKind().equals(Kind.COMPREHENSION)) .collect(toImmutableList()); - CelExpr iterRangeConstExpr = CelExpr.ofConstantExpr(2, CelConstant.ofValue(true)); + CelExpr iterRangeConstExpr = CelExpr.ofConstant(2, CelConstant.ofValue(true)); CelExpr iterRange = - CelExpr.ofCreateListExpr(1, ImmutableList.of(iterRangeConstExpr), ImmutableList.of()); - CelExpr accuInit = CelExpr.ofConstantExpr(6, CelConstant.ofValue(false)); - CelExpr loopConditionIdentExpr = CelExpr.ofIdentExpr(7, "__result__"); + CelExpr.ofCreateList(1, ImmutableList.of(iterRangeConstExpr), ImmutableList.of()); + CelExpr accuInit = CelExpr.ofConstant(6, CelConstant.ofValue(false)); + CelExpr loopConditionIdentExpr = CelExpr.ofIdent(7, "__result__"); CelExpr loopConditionCallExpr = - CelExpr.ofCallExpr( + CelExpr.ofCall( 8, Optional.empty(), Operator.LOGICAL_NOT.getFunction(), ImmutableList.of(loopConditionIdentExpr)); CelExpr loopCondition = - CelExpr.ofCallExpr( + CelExpr.ofCall( 9, Optional.empty(), Operator.NOT_STRICTLY_FALSE.getFunction(), ImmutableList.of(loopConditionCallExpr)); - CelExpr loopStepResultExpr = CelExpr.ofIdentExpr(10, "__result__"); - CelExpr loopStepVarExpr = CelExpr.ofIdentExpr(5, "i"); + CelExpr loopStepResultExpr = CelExpr.ofIdent(10, "__result__"); + CelExpr loopStepVarExpr = CelExpr.ofIdent(5, "i"); CelExpr loopStep = - CelExpr.ofCallExpr( + CelExpr.ofCall( 11, Optional.empty(), Operator.LOGICAL_OR.getFunction(), ImmutableList.of(loopStepResultExpr, loopStepVarExpr)); - CelExpr result = CelExpr.ofIdentExpr(12, "__result__"); + CelExpr result = CelExpr.ofIdent(12, "__result__"); CelExpr comprehension = CelExpr.ofComprehension( 13, "i", iterRange, "__result__", accuInit, loopCondition, loopStep, result); @@ -1150,12 +1139,12 @@ public void callExpr_preOrder() throws Exception { .map(CelNavigableExpr::expr) .collect(toImmutableList()); - CelExpr targetExpr = CelExpr.ofConstantExpr(1, CelConstant.ofValue("hello")); - CelExpr intArgExpr = CelExpr.ofConstantExpr(3, CelConstant.ofValue(5)); - CelExpr uintArgExpr = CelExpr.ofConstantExpr(4, CelConstant.ofValue(UnsignedLong.valueOf(6))); + CelExpr targetExpr = CelExpr.ofConstant(1, CelConstant.ofValue("hello")); + CelExpr intArgExpr = CelExpr.ofConstant(3, CelConstant.ofValue(5)); + CelExpr uintArgExpr = CelExpr.ofConstant(4, CelConstant.ofValue(UnsignedLong.valueOf(6))); assertThat(allNodes) .containsExactly( - CelExpr.ofCallExpr( + CelExpr.ofCall( 2, Optional.of(targetExpr), "test", ImmutableList.of(intArgExpr, uintArgExpr)), targetExpr, intArgExpr, @@ -1187,15 +1176,15 @@ public void callExpr_postOrder() throws Exception { .map(CelNavigableExpr::expr) .collect(toImmutableList()); - CelExpr targetExpr = CelExpr.ofConstantExpr(1, CelConstant.ofValue("hello")); - CelExpr intArgExpr = CelExpr.ofConstantExpr(3, CelConstant.ofValue(5)); - CelExpr uintArgExpr = CelExpr.ofConstantExpr(4, CelConstant.ofValue(UnsignedLong.valueOf(6))); + CelExpr targetExpr = CelExpr.ofConstant(1, CelConstant.ofValue("hello")); + CelExpr intArgExpr = CelExpr.ofConstant(3, CelConstant.ofValue(5)); + CelExpr uintArgExpr = CelExpr.ofConstant(4, CelConstant.ofValue(UnsignedLong.valueOf(6))); assertThat(allNodes) .containsExactly( targetExpr, intArgExpr, uintArgExpr, - CelExpr.ofCallExpr( + CelExpr.ofCall( 2, Optional.of(targetExpr), "test", ImmutableList.of(intArgExpr, uintArgExpr))) .inOrder(); } diff --git a/optimizer/src/test/java/dev/cel/optimizer/AstMutatorTest.java b/optimizer/src/test/java/dev/cel/optimizer/AstMutatorTest.java index b3c6313da..e199ea6e2 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/AstMutatorTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/AstMutatorTest.java @@ -82,7 +82,7 @@ public void replaceSubtree_replaceConst() throws Exception { AST_MUTATOR.replaceSubtree(mutableAst, newBooleanConst, mutableAst.expr().id()); assertThat(result.toParsedAst().getExpr()) - .isEqualTo(CelExpr.ofConstantExpr(3, CelConstant.ofValue(true))); + .isEqualTo(CelExpr.ofConstant(3, CelConstant.ofValue(true))); } @Test @@ -519,7 +519,7 @@ public void globalCallExpr_replaceRoot() throws Exception { CelMutableAst result = AST_MUTATOR.replaceSubtree(mutableAst, newExpr, mutableAst.expr().id()); assertThat(result.toParsedAst().getExpr()) - .isEqualTo(CelExpr.ofConstantExpr(7, CelConstant.ofValue(10))); + .isEqualTo(CelExpr.ofConstant(7, CelConstant.ofValue(10))); } @Test diff --git a/optimizer/src/test/java/dev/cel/optimizer/CelOptimizerImplTest.java b/optimizer/src/test/java/dev/cel/optimizer/CelOptimizerImplTest.java index 570233dd6..cb0bff6c6 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/CelOptimizerImplTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/CelOptimizerImplTest.java @@ -115,7 +115,7 @@ public void optimizedAst_failsToTypeCheck_throwsException() { (navigableAst, cel) -> OptimizationResult.create( CelAbstractSyntaxTree.newParsedAst( - CelExpr.ofIdentExpr(1, "undeclared_ident"), + CelExpr.ofIdent(1, "undeclared_ident"), CelSource.newBuilder().build()))) .build(); diff --git a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java index 8d657cd0a..f4cec706d 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java @@ -218,13 +218,12 @@ public void cse_applyConstFoldingAfter() throws Exception { assertThat(optimizedAst.getExpr()) .isEqualTo( - CelExpr.ofCallExpr( + CelExpr.ofCall( 1L, Optional.empty(), Operator.ADD.getFunction(), ImmutableList.of( - CelExpr.ofConstantExpr(2L, CelConstant.ofValue(6L)), - CelExpr.ofIdentExpr(3L, "x")))); + CelExpr.ofConstant(2L, CelConstant.ofValue(6L)), CelExpr.ofIdent(3L, "x")))); assertThat(CEL_UNPARSER.unparse(optimizedAst)).isEqualTo("6 + x"); } From 2a8fd2fea3a8067365374ec3108d509ddeba136a Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Fri, 26 Apr 2024 16:56:33 -0700 Subject: [PATCH 101/486] Fix timestamp and duration conversion for JSON PiperOrigin-RevId: 628545489 --- .../main/java/dev/cel/common/internal/BUILD.bazel | 1 + .../java/dev/cel/common/internal/ProtoAdapter.java | 11 +++++++++++ runtime/src/test/resources/jsonConversions.baseline | 12 ++++++++++++ .../java/dev/cel/testing/BaseInterpreterTest.java | 10 ++++++++++ 4 files changed, 34 insertions(+) create mode 100644 runtime/src/test/resources/jsonConversions.baseline diff --git a/common/src/main/java/dev/cel/common/internal/BUILD.bazel b/common/src/main/java/dev/cel/common/internal/BUILD.bazel index e373f442b..b76338cef 100644 --- a/common/src/main/java/dev/cel/common/internal/BUILD.bazel +++ b/common/src/main/java/dev/cel/common/internal/BUILD.bazel @@ -128,6 +128,7 @@ java_library( "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", + "@maven//:com_google_protobuf_protobuf_java_util", "@maven//:org_jspecify_jspecify", ], ) diff --git a/common/src/main/java/dev/cel/common/internal/ProtoAdapter.java b/common/src/main/java/dev/cel/common/internal/ProtoAdapter.java index 6e291c626..194e8260d 100644 --- a/common/src/main/java/dev/cel/common/internal/ProtoAdapter.java +++ b/common/src/main/java/dev/cel/common/internal/ProtoAdapter.java @@ -50,6 +50,8 @@ import com.google.protobuf.UInt32Value; import com.google.protobuf.UInt64Value; import com.google.protobuf.Value; +import com.google.protobuf.util.Durations; +import com.google.protobuf.util.Timestamps; import dev.cel.common.CelErrorCode; import dev.cel.common.CelRuntimeException; import dev.cel.common.annotations.Internal; @@ -475,6 +477,15 @@ public Optional adaptValueToProto(Object value, String protoTypeName) { return json.setListValue(listValue).build(); } } + if (value instanceof Timestamp) { + // CEL follows the proto3 to JSON conversion which formats as an RFC 3339 encoded JSON string. + String ts = Timestamps.toString((Timestamp) value); + return json.setStringValue(ts).build(); + } + if (value instanceof Duration) { + String duration = Durations.toString((Duration) value); + return json.setStringValue(duration).build(); + } return null; } diff --git a/runtime/src/test/resources/jsonConversions.baseline b/runtime/src/test/resources/jsonConversions.baseline new file mode 100644 index 000000000..3c674b1c4 --- /dev/null +++ b/runtime/src/test/resources/jsonConversions.baseline @@ -0,0 +1,12 @@ +Source: google.protobuf.Struct { fields: {'timestamp': ts, 'duration': du } } +declare ts { + value google.protobuf.Timestamp +} +declare du { + value google.protobuf.Duration +} +=====> +bindings: {ts=seconds: 100 +, du=nanos: 200000000 +} +result: {timestamp=1970-01-01T00:01:40Z, duration=0.200s} diff --git a/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java b/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java index 0addafaf9..17e6bc26c 100644 --- a/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java +++ b/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java @@ -1725,6 +1725,16 @@ public void jsonValueTypes() throws Exception { runTest(Activation.of("x", xStruct)); } + @Test + public void jsonConversions() throws Exception { + declareVariable("ts", CelTypes.TIMESTAMP); + declareVariable("du", CelTypes.DURATION); + source = "google.protobuf.Struct { fields: {'timestamp': ts, 'duration': du } }"; + runTest( + Activation.copyOf( + ImmutableMap.of("ts", Timestamps.fromSeconds(100), "du", Durations.fromMillis(200)))); + } + @Test public void typeComparisons() throws Exception { container = TestAllTypes.getDescriptor().getFile().getPackage(); From 9af1bed57ceb21832b630801d0aff04aaae8139a Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Tue, 30 Apr 2024 10:28:19 -0700 Subject: [PATCH 102/486] Remove modifier create from CelCreateList, CelCreateMap and CelCreateStruct PiperOrigin-RevId: 629456238 --- .../test/java/dev/cel/bundle/CelImplTest.java | 4 +- .../java/dev/cel/checker/ExprChecker.java | 37 ++- .../main/java/dev/cel/common/ast/CelExpr.java | 225 ++++++++++-------- .../dev/cel/common/ast/CelExprConverter.java | 20 +- .../dev/cel/common/ast/CelExprFactory.java | 32 +-- .../dev/cel/common/ast/CelExprFormatter.java | 34 ++- .../common/ast/CelExprV1Alpha1Converter.java | 20 +- .../dev/cel/common/ast/CelExprVisitor.java | 28 +-- .../dev/cel/common/ast/CelMutableExpr.java | 24 +- .../common/ast/CelMutableExprConverter.java | 41 ++-- .../navigation/CelNavigableExprVisitor.java | 6 +- .../navigation/ExprPropertyCalculator.java | 6 +- .../java/dev/cel/common/ast/CelExprTest.java | 124 +++++----- .../cel/common/ast/CelExprVisitorTest.java | 41 ++-- .../ast/CelMutableExprConverterTest.java | 24 +- .../cel/common/ast/CelMutableExprTest.java | 6 +- .../CelNavigableExprVisitorTest.java | 8 +- .../dev/cel/extensions/CelMathExtensions.java | 8 +- .../java/dev/cel/optimizer/AstMutator.java | 5 +- .../dev/cel/optimizer/MutableExprVisitor.java | 6 +- .../optimizers/ConstantFoldingOptimizer.java | 20 +- .../optimizers/SubexpressionOptimizer.java | 2 +- .../dev/cel/parser/CelMacroExprFactory.java | 26 +- .../dev/cel/parser/CelUnparserVisitor.java | 16 +- .../src/main/java/dev/cel/parser/Parser.java | 33 ++- .../cel/parser/CelMacroExprFactoryTest.java | 14 +- .../dev/cel/parser/CelUnparserImplTest.java | 12 +- .../dev/cel/runtime/DefaultInterpreter.java | 30 ++- .../java/dev/cel/runtime/CelRuntimeTest.java | 4 +- .../HomogeneousLiteralValidator.java | 12 +- 30 files changed, 431 insertions(+), 437 deletions(-) diff --git a/bundle/src/test/java/dev/cel/bundle/CelImplTest.java b/bundle/src/test/java/dev/cel/bundle/CelImplTest.java index 1eded3ce9..de36d93b9 100644 --- a/bundle/src/test/java/dev/cel/bundle/CelImplTest.java +++ b/bundle/src/test/java/dev/cel/bundle/CelImplTest.java @@ -68,7 +68,7 @@ import dev.cel.common.CelValidationResult; import dev.cel.common.CelVarDecl; import dev.cel.common.ast.CelExpr; -import dev.cel.common.ast.CelExpr.CelCreateList; +import dev.cel.common.ast.CelExpr.CelList; import dev.cel.common.testing.RepeatedTestProvider; import dev.cel.common.types.CelKind; import dev.cel.common.types.CelType; @@ -486,7 +486,7 @@ public void compile_withOptionalTypes() throws Exception { CelAbstractSyntaxTree ast = cel.compile("[?a]").getAst(); - CelCreateList createList = ast.getExpr().createList(); + CelList createList = ast.getExpr().createList(); assertThat(createList.optionalIndices()).containsExactly(0); assertThat(createList.elements()).containsExactly(CelExpr.ofIdent(2, "a")); } diff --git a/checker/src/main/java/dev/cel/checker/ExprChecker.java b/checker/src/main/java/dev/cel/checker/ExprChecker.java index cbebcd238..777dd8119 100644 --- a/checker/src/main/java/dev/cel/checker/ExprChecker.java +++ b/checker/src/main/java/dev/cel/checker/ExprChecker.java @@ -180,11 +180,11 @@ public CelExpr visit(CelExpr expr) { return visit(expr, expr.select()); case CALL: return visit(expr, expr.call()); - case CREATE_LIST: + case LIST: return visit(expr, expr.createList()); - case CREATE_STRUCT: + case STRUCT: return visit(expr, expr.createStruct()); - case CREATE_MAP: + case MAP: return visit(expr, expr.createMap()); case COMPREHENSION: return visit(expr, expr.comprehension()); @@ -355,7 +355,7 @@ private CelExpr visit(CelExpr expr, CelExpr.CelCall call) { } @CheckReturnValue - private CelExpr visit(CelExpr expr, CelExpr.CelCreateStruct createStruct) { + private CelExpr visit(CelExpr expr, CelExpr.CelStruct createStruct) { // Determine the type of the message. CelType messageType = SimpleType.ERROR; CelIdentDecl decl = env.lookupIdent(getPosition(expr), inContainer, createStruct.messageName()); @@ -383,9 +383,9 @@ private CelExpr visit(CelExpr expr, CelExpr.CelCreateStruct createStruct) { } // Check the field initializers. - ImmutableList entriesList = createStruct.entries(); + ImmutableList entriesList = createStruct.entries(); for (int i = 0; i < entriesList.size(); i++) { - CelExpr.CelCreateStruct.Entry entry = entriesList.get(i); + CelExpr.CelStruct.Entry entry = entriesList.get(i); CelExpr visitedValueExpr = visit(entry.value()); if (namespacedDeclarations && !visitedValueExpr.equals(entry.value())) { // Subtree has been rewritten. Replace the struct value. @@ -414,12 +414,12 @@ private CelExpr visit(CelExpr expr, CelExpr.CelCreateStruct createStruct) { } @CheckReturnValue - private CelExpr visit(CelExpr expr, CelExpr.CelCreateMap createMap) { + private CelExpr visit(CelExpr expr, CelExpr.CelMap createMap) { CelType mapKeyType = null; CelType mapValueType = null; - ImmutableList entriesList = createMap.entries(); + ImmutableList entriesList = createMap.entries(); for (int i = 0; i < entriesList.size(); i++) { - CelExpr.CelCreateMap.Entry entry = entriesList.get(i); + CelExpr.CelMap.Entry entry = entriesList.get(i); CelExpr visitedMapKeyExpr = visit(entry.key()); if (namespacedDeclarations && !visitedMapKeyExpr.equals(entry.key())) { // Subtree has been rewritten. Replace the map key. @@ -455,7 +455,7 @@ private CelExpr visit(CelExpr expr, CelExpr.CelCreateMap createMap) { } @CheckReturnValue - private CelExpr visit(CelExpr expr, CelExpr.CelCreateList createList) { + private CelExpr visit(CelExpr expr, CelExpr.CelList createList) { CelType elemsType = null; ImmutableList elementsList = createList.elements(); HashSet optionalIndices = new HashSet<>(createList.optionalIndices()); @@ -797,7 +797,7 @@ private int getPosition(CelExpr expr) { return pos == null ? 0 : pos; } - private int getPosition(CelExpr.CelCreateStruct.Entry entry) { + private int getPosition(CelExpr.CelStruct.Entry entry) { Integer pos = positionMap.get(entry.id()); return pos == null ? 0 : pos; } @@ -848,30 +848,29 @@ private static CelExpr replaceCallSubtree(CelExpr expr, CelExpr target) { } private static CelExpr replaceListElementSubtree(CelExpr expr, CelExpr element, int index) { - CelExpr.CelCreateList newList = - expr.createList().toBuilder().setElement(index, element).build(); + CelExpr.CelList newList = expr.createList().toBuilder().setElement(index, element).build(); return expr.toBuilder().setCreateList(newList).build(); } private static CelExpr replaceStructEntryValueSubtree(CelExpr expr, CelExpr newValue, int index) { - CelExpr.CelCreateStruct createStruct = expr.createStruct(); - CelExpr.CelCreateStruct.Entry newEntry = + CelExpr.CelStruct createStruct = expr.createStruct(); + CelExpr.CelStruct.Entry newEntry = createStruct.entries().get(index).toBuilder().setValue(newValue).build(); createStruct = createStruct.toBuilder().setEntry(index, newEntry).build(); return expr.toBuilder().setCreateStruct(createStruct).build(); } private static CelExpr replaceMapEntryKeySubtree(CelExpr expr, CelExpr newKey, int index) { - CelExpr.CelCreateMap createMap = expr.createMap(); - CelExpr.CelCreateMap.Entry newEntry = + CelExpr.CelMap createMap = expr.createMap(); + CelExpr.CelMap.Entry newEntry = createMap.entries().get(index).toBuilder().setKey(newKey).build(); createMap = createMap.toBuilder().setEntry(index, newEntry).build(); return expr.toBuilder().setCreateMap(createMap).build(); } private static CelExpr replaceMapEntryValueSubtree(CelExpr expr, CelExpr newValue, int index) { - CelExpr.CelCreateMap createMap = expr.createMap(); - CelExpr.CelCreateMap.Entry newEntry = + CelExpr.CelMap createMap = expr.createMap(); + CelExpr.CelMap.Entry newEntry = createMap.entries().get(index).toBuilder().setValue(newValue).build(); createMap = createMap.toBuilder().setEntry(index, newEntry).build(); return expr.toBuilder().setCreateMap(createMap).build(); diff --git a/common/src/main/java/dev/cel/common/ast/CelExpr.java b/common/src/main/java/dev/cel/common/ast/CelExpr.java index c0651ccb3..d85348175 100644 --- a/common/src/main/java/dev/cel/common/ast/CelExpr.java +++ b/common/src/main/java/dev/cel/common/ast/CelExpr.java @@ -23,7 +23,7 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.errorprone.annotations.CheckReturnValue; import com.google.errorprone.annotations.Immutable; -import dev.cel.common.annotations.Internal; +import com.google.errorprone.annotations.InlineMe; import dev.cel.common.ast.CelExpr.ExprKind.Kind; import java.util.ArrayList; import java.util.Arrays; @@ -36,7 +36,6 @@ *

This is the native type equivalent of Expr message in syntax.proto. */ @AutoValue -@Internal @Immutable @SuppressWarnings("unchecked") // Class ensures only the super type is used public abstract class CelExpr implements Expression { @@ -95,20 +94,20 @@ public CelCall call() { /** * {@inheritDoc} * - * @throws UnsupportedOperationException if expression is not {@link Kind#CREATE_LIST}. + * @throws UnsupportedOperationException if expression is not {@link Kind#LIST}. */ @Override - public CelCreateList createList() { + public CelList createList() { return exprKind().createList(); } /** * {@inheritDoc} * - * @throws UnsupportedOperationException if expression is not {@link Kind#CREATE_STRUCT}. + * @throws UnsupportedOperationException if expression is not {@link Kind#STRUCT}. */ @Override - public CelCreateStruct createStruct() { + public CelStruct createStruct() { return exprKind().createStruct(); } @@ -118,7 +117,7 @@ public CelCreateStruct createStruct() { * @throws UnsupportedOperationException if expression is not {@link Kind#createMap}. */ @Override - public CelCreateMap createMap() { + public CelMap createMap() { return exprKind().createMap(); } @@ -174,32 +173,32 @@ public CelCall callOrDefault() { /** * Gets the underlying createList expression or a default instance of one if expression is not - * {@link Kind#CREATE_LIST}. + * {@link Kind#LIST}. */ - public CelCreateList createListOrDefault() { - return exprKind().getKind().equals(ExprKind.Kind.CREATE_LIST) + public CelList createListOrDefault() { + return exprKind().getKind().equals(ExprKind.Kind.LIST) ? exprKind().createList() - : CelCreateList.newBuilder().build(); + : CelList.newBuilder().build(); } /** * Gets the underlying createStruct expression or a default instance of one if expression is not - * {@link Kind#CREATE_STRUCT}. + * {@link Kind#STRUCT}. */ - public CelCreateStruct createStructOrDefault() { - return exprKind().getKind().equals(ExprKind.Kind.CREATE_STRUCT) + public CelStruct createStructOrDefault() { + return exprKind().getKind().equals(ExprKind.Kind.STRUCT) ? exprKind().createStruct() - : CelCreateStruct.newBuilder().build(); + : CelStruct.newBuilder().build(); } /** * Gets the underlying createMap expression or a default instance of one if expression is not - * {@link Kind#CREATE_MAP}. + * {@link Kind#MAP}. */ - public CelCreateMap createMapOrDefault() { - return exprKind().getKind().equals(ExprKind.Kind.CREATE_MAP) + public CelMap createMapOrDefault() { + return exprKind().getKind().equals(ExprKind.Kind.MAP) ? exprKind().createMap() - : CelCreateMap.newBuilder().build(); + : CelMap.newBuilder().build(); } /** @@ -263,18 +262,18 @@ public CelCall call() { /** * Gets the underlying createList expression. * - * @throws UnsupportedOperationException if expression is not {@link Kind#CREATE_LIST}. + * @throws UnsupportedOperationException if expression is not {@link Kind#LIST}. */ - public CelCreateList createList() { + public CelList createList() { return exprKind().createList(); } /** * Gets the underlying createStruct expression. * - * @throws UnsupportedOperationException if expression is not {@link Kind#CREATE_STRUCT}. + * @throws UnsupportedOperationException if expression is not {@link Kind#STRUCT}. */ - public CelCreateStruct createStruct() { + public CelStruct createStruct() { return exprKind().createStruct(); } @@ -283,7 +282,7 @@ public CelCreateStruct createStruct() { * * @throws UnsupportedOperationException if expression is not {@link Kind#createMap}. */ - public CelCreateMap createMap() { + public CelMap createMap() { return exprKind().createMap(); } @@ -317,18 +316,18 @@ public Builder setSelect(CelSelect select) { } @CanIgnoreReturnValue - public Builder setCreateList(CelCreateList createList) { - return setExprKind(AutoOneOf_CelExpr_ExprKind.createList(createList)); + public Builder setCreateList(CelList createList) { + return setExprKind(AutoOneOf_CelExpr_ExprKind.list(createList)); } @CanIgnoreReturnValue - public Builder setCreateStruct(CelCreateStruct createStruct) { - return setExprKind(AutoOneOf_CelExpr_ExprKind.createStruct(createStruct)); + public Builder setCreateStruct(CelStruct createStruct) { + return setExprKind(AutoOneOf_CelExpr_ExprKind.struct(createStruct)); } @CanIgnoreReturnValue - public Builder setCreateMap(CelCreateMap createMap) { - return setExprKind(AutoOneOf_CelExpr_ExprKind.createMap(createMap)); + public Builder setCreateMap(CelMap createMap) { + return setExprKind(AutoOneOf_CelExpr_ExprKind.map(createMap)); } @CanIgnoreReturnValue @@ -360,9 +359,9 @@ public enum Kind { IDENT, SELECT, CALL, - CREATE_LIST, - CREATE_STRUCT, - CREATE_MAP, + LIST, + STRUCT, + MAP, COMPREHENSION, } @@ -378,11 +377,38 @@ public enum Kind { public abstract CelCall call(); - public abstract CelCreateList createList(); + public abstract CelList list(); - public abstract CelCreateStruct createStruct(); + /** + * @deprecated Use {@link #list()} instead. + */ + @Deprecated + @InlineMe(replacement = "this.list()") + public final CelList createList() { + return list(); + } + + public abstract CelStruct struct(); - public abstract CelCreateMap createMap(); + /** + * @deprecated Use {@link #struct()} instead. + */ + @Deprecated + @InlineMe(replacement = "this.struct()") + public final CelStruct createStruct() { + return struct(); + } + + public abstract CelMap map(); + + /** + * @deprecated Use {@link #map()} instead. + */ + @Deprecated + @InlineMe(replacement = "this.map()") + public final CelMap createMap() { + return map(); + } public abstract CelComprehension comprehension(); } @@ -565,14 +591,14 @@ public static Builder newBuilder() { /** A list creation expression. See {@link Expression.CreateList} */ @AutoValue @Immutable - public abstract static class CelCreateList implements Expression.CreateList { + public abstract static class CelList implements Expression.CreateList { @Override public abstract ImmutableList elements(); @Override public abstract ImmutableList optionalIndices(); - /** Builder for CelCreateList. */ + /** Builder for CelList. */ @AutoValue.Builder public abstract static class Builder { private List mutableElements = new ArrayList<>(); @@ -631,10 +657,10 @@ public Builder addOptionalIndices(Iterable indices) { } // Not public due to overridden build logic. - abstract CelCreateList autoBuild(); + abstract CelList autoBuild(); @CheckReturnValue - public CelCreateList build() { + public CelList build() { setElements(ImmutableList.copyOf(mutableElements)); return autoBuild(); } @@ -650,73 +676,70 @@ public Builder toBuilder() { } public static Builder newBuilder() { - return new AutoValue_CelExpr_CelCreateList.Builder(); + return new AutoValue_CelExpr_CelList.Builder(); } } /** A message creation expression. See {@link Expression.CreateStruct} */ @AutoValue @Immutable - public abstract static class CelCreateStruct - implements Expression.CreateStruct { + public abstract static class CelStruct implements Expression.CreateStruct { @Override public abstract String messageName(); @Override - public abstract ImmutableList entries(); + public abstract ImmutableList entries(); - /** Builder for CelCreateStruct. */ + /** Builder for CelStruct. */ @AutoValue.Builder public abstract static class Builder { - private List mutableEntries = new ArrayList<>(); + private List mutableEntries = new ArrayList<>(); // Not public. This only exists to make AutoValue.Builder work. - abstract ImmutableList entries(); + abstract ImmutableList entries(); @CanIgnoreReturnValue public abstract Builder setMessageName(String value); // Not public. This only exists to make AutoValue.Builder work. @CanIgnoreReturnValue - abstract Builder setEntries(ImmutableList entries); + abstract Builder setEntries(ImmutableList entries); /** Returns an immutable copy of the current mutable entries present in the builder. */ - public ImmutableList getEntries() { + public ImmutableList getEntries() { return ImmutableList.copyOf(mutableEntries); } /** Returns an immutable copy of the builders from the current mutable entries. */ - public ImmutableList getEntriesBuilders() { - return mutableEntries.stream() - .map(CelCreateStruct.Entry::toBuilder) - .collect(toImmutableList()); + public ImmutableList getEntriesBuilders() { + return mutableEntries.stream().map(CelStruct.Entry::toBuilder).collect(toImmutableList()); } @CanIgnoreReturnValue - public Builder setEntry(int index, CelCreateStruct.Entry entry) { + public Builder setEntry(int index, CelStruct.Entry entry) { checkNotNull(entry); mutableEntries.set(index, entry); return this; } @CanIgnoreReturnValue - public Builder addEntries(CelCreateStruct.Entry... entries) { + public Builder addEntries(CelStruct.Entry... entries) { checkNotNull(entries); return addEntries(Arrays.asList(entries)); } @CanIgnoreReturnValue - public Builder addEntries(Iterable entries) { + public Builder addEntries(Iterable entries) { checkNotNull(entries); entries.forEach(mutableEntries::add); return this; } // Not public due to overridden build logic. - abstract CelCreateStruct autoBuild(); + abstract CelStruct autoBuild(); @CheckReturnValue - public CelCreateStruct build() { + public CelStruct build() { setEntries(ImmutableList.copyOf(mutableEntries)); return autoBuild(); } @@ -732,7 +755,7 @@ public Builder toBuilder() { } public static Builder newBuilder() { - return new AutoValue_CelExpr_CelCreateStruct.Builder().setMessageName(""); + return new AutoValue_CelExpr_CelStruct.Builder().setMessageName(""); } /** Represents an entry of the struct */ @@ -752,7 +775,7 @@ public abstract static class Entry implements Expression.CreateStruct.Entry { + public abstract static class CelMap implements Expression.CreateMap { /** The entries in the creation expression. */ @Override - public abstract ImmutableList entries(); + public abstract ImmutableList entries(); - /** Builder for CelCreateMap. */ + /** Builder for CelMap. */ @AutoValue.Builder public abstract static class Builder { - private List mutableEntries = new ArrayList<>(); + private List mutableEntries = new ArrayList<>(); // Not public. This only exists to make AutoValue.Builder work. - abstract ImmutableList entries(); + abstract ImmutableList entries(); // Not public. This only exists to make AutoValue.Builder work. @CanIgnoreReturnValue - abstract Builder setEntries(ImmutableList entries); + abstract Builder setEntries(ImmutableList entries); /** Returns an immutable copy of the current mutable entries present in the builder. */ - public ImmutableList getEntries() { + public ImmutableList getEntries() { return ImmutableList.copyOf(mutableEntries); } /** Returns an immutable copy of the builders from the current mutable entries. */ - public ImmutableList getEntriesBuilders() { - return mutableEntries.stream() - .map(CelCreateMap.Entry::toBuilder) - .collect(toImmutableList()); + public ImmutableList getEntriesBuilders() { + return mutableEntries.stream().map(CelMap.Entry::toBuilder).collect(toImmutableList()); } @CanIgnoreReturnValue - public Builder setEntry(int index, CelCreateMap.Entry entry) { + public Builder setEntry(int index, CelMap.Entry entry) { checkNotNull(entry); mutableEntries.set(index, entry); return this; } @CanIgnoreReturnValue - public Builder addEntries(CelCreateMap.Entry... entries) { + public Builder addEntries(CelMap.Entry... entries) { checkNotNull(entries); return addEntries(Arrays.asList(entries)); } @CanIgnoreReturnValue - public Builder addEntries(Iterable entries) { + public Builder addEntries(Iterable entries) { checkNotNull(entries); entries.forEach(mutableEntries::add); return this; } // Not public due to overridden build logic. - abstract CelCreateMap autoBuild(); + abstract CelMap autoBuild(); @CheckReturnValue - public CelCreateMap build() { + public CelMap build() { setEntries(ImmutableList.copyOf(mutableEntries)); return autoBuild(); } @@ -855,7 +874,7 @@ public Builder toBuilder() { } public static Builder newBuilder() { - return new AutoValue_CelExpr_CelCreateMap.Builder(); + return new AutoValue_CelExpr_CelMap.Builder(); } /** Represents an entry of the map. */ @@ -875,7 +894,7 @@ public abstract static class Entry implements Expression.CreateMap.Entry entries) { + long id, String messageName, ImmutableList entries) { return newBuilder() .setId(id) .setExprKind( - AutoOneOf_CelExpr_ExprKind.createStruct( - CelCreateStruct.newBuilder() - .setMessageName(messageName) - .addEntries(entries) - .build())) + AutoOneOf_CelExpr_ExprKind.struct( + CelStruct.newBuilder().setMessageName(messageName).addEntries(entries).build())) .build(); } - public static CelExpr ofCreateMap(long id, ImmutableList entries) { + public static CelExpr ofCreateMap(long id, ImmutableList entries) { return newBuilder() .setId(id) .setExprKind( - AutoOneOf_CelExpr_ExprKind.createMap( - CelCreateMap.newBuilder().addEntries(entries).build())) + AutoOneOf_CelExpr_ExprKind.map(CelMap.newBuilder().addEntries(entries).build())) .build(); } - public static CelCreateStruct.Entry ofCreateStructEntry( + public static CelStruct.Entry ofCreateStructEntry( long id, String fieldKey, CelExpr value, boolean isOptionalEntry) { - return CelCreateStruct.Entry.newBuilder() + return CelStruct.Entry.newBuilder() .setId(id) .setFieldKey(fieldKey) .setValue(value) @@ -1067,9 +1082,9 @@ public static CelCreateStruct.Entry ofCreateStructEntry( .build(); } - public static CelCreateMap.Entry ofCreateMapEntry( + public static CelMap.Entry ofCreateMapEntry( long id, CelExpr mapKey, CelExpr value, boolean isOptionalEntry) { - return CelCreateMap.Entry.newBuilder() + return CelMap.Entry.newBuilder() .setId(id) .setKey(mapKey) .setValue(value) diff --git a/common/src/main/java/dev/cel/common/ast/CelExprConverter.java b/common/src/main/java/dev/cel/common/ast/CelExprConverter.java index b2d8489a3..cc7942415 100644 --- a/common/src/main/java/dev/cel/common/ast/CelExprConverter.java +++ b/common/src/main/java/dev/cel/common/ast/CelExprConverter.java @@ -68,16 +68,16 @@ public static Expr fromCelExpr(CelExpr celExpr) { .addAllArgs(fromCelExprList(celCall.args())); celCall.target().ifPresent(target -> callBuilder.setTarget(fromCelExpr(target))); return expr.setCallExpr(callBuilder).build(); - case CREATE_LIST: - CelExpr.CelCreateList celCreateList = celExprKind.createList(); + case LIST: + CelExpr.CelList celCreateList = celExprKind.list(); return expr.setListExpr( CreateList.newBuilder() .addAllElements(fromCelExprList(celCreateList.elements())) .addAllOptionalIndices(celCreateList.optionalIndices())) .build(); - case CREATE_STRUCT: + case STRUCT: return expr.setStructExpr(celStructToExprStruct(celExprKind.createStruct())).build(); - case CREATE_MAP: + case MAP: return expr.setStructExpr(celMapToExprStruct(celExprKind.createMap())).build(); case COMPREHENSION: CelExpr.CelComprehension celComprehension = celExprKind.comprehension(); @@ -202,7 +202,7 @@ public static CelConstant exprConstantToCelConstant(Constant constExpr) { private static CelExpr exprStructToCelStruct(long id, CreateStruct structExpr) { if (!structExpr.getMessageName().isEmpty()) { - ImmutableList.Builder entries = ImmutableList.builder(); + ImmutableList.Builder entries = ImmutableList.builder(); for (Entry structExprEntry : structExpr.getEntriesList()) { if (!structExprEntry.getKeyKindCase().equals(KeyKindCase.FIELD_KEY)) { throw new IllegalArgumentException( @@ -218,7 +218,7 @@ private static CelExpr exprStructToCelStruct(long id, CreateStruct structExpr) { return CelExpr.ofCreateStruct(id, structExpr.getMessageName(), entries.build()); } else { - ImmutableList.Builder entries = ImmutableList.builder(); + ImmutableList.Builder entries = ImmutableList.builder(); for (Entry mapExprEntry : structExpr.getEntriesList()) { if (!mapExprEntry.getKeyKindCase().equals(KeyKindCase.MAP_KEY)) { throw new IllegalArgumentException( @@ -270,9 +270,9 @@ public static Constant celConstantToExprConstant(CelConstant celConstant) { throw new IllegalStateException("unsupported constant case: " + celConstant.getKind()); } - private static CreateStruct celStructToExprStruct(CelExpr.CelCreateStruct celCreateStruct) { + private static CreateStruct celStructToExprStruct(CelExpr.CelStruct celCreateStruct) { ImmutableList.Builder entries = ImmutableList.builder(); - for (CelExpr.CelCreateStruct.Entry celStructExprEntry : celCreateStruct.entries()) { + for (CelExpr.CelStruct.Entry celStructExprEntry : celCreateStruct.entries()) { entries.add( CreateStruct.Entry.newBuilder() .setId(celStructExprEntry.id()) @@ -288,9 +288,9 @@ private static CreateStruct celStructToExprStruct(CelExpr.CelCreateStruct celCre .build(); } - private static CreateStruct celMapToExprStruct(CelExpr.CelCreateMap celCreateMap) { + private static CreateStruct celMapToExprStruct(CelExpr.CelMap celCreateMap) { ImmutableList.Builder entries = ImmutableList.builder(); - for (CelExpr.CelCreateMap.Entry celMapEntry : celCreateMap.entries()) { + for (CelExpr.CelMap.Entry celMapEntry : celCreateMap.entries()) { CreateStruct.Entry exprMapEntry = CreateStruct.Entry.newBuilder() .setId(celMapEntry.id()) diff --git a/common/src/main/java/dev/cel/common/ast/CelExprFactory.java b/common/src/main/java/dev/cel/common/ast/CelExprFactory.java index 385e72fee..6e8a08619 100644 --- a/common/src/main/java/dev/cel/common/ast/CelExprFactory.java +++ b/common/src/main/java/dev/cel/common/ast/CelExprFactory.java @@ -96,28 +96,26 @@ public final CelExpr newList(CelExpr... elements) { public final CelExpr newList(Iterable elements) { return CelExpr.newBuilder() .setId(nextExprId()) - .setCreateList(CelExpr.CelCreateList.newBuilder().addElements(elements).build()) + .setCreateList(CelExpr.CelList.newBuilder().addElements(elements).build()) .build(); } /** Creates a new map {@link CelExpr} comprised of the entries. */ - public final CelExpr newMap(CelExpr.CelCreateMap.Entry... entries) { + public final CelExpr newMap(CelExpr.CelMap.Entry... entries) { return newMap(Arrays.asList(entries)); } /** Creates a new map {@link CelExpr} comprised of the entries. */ - public final CelExpr newMap(Iterable entries) { + public final CelExpr newMap(Iterable entries) { return CelExpr.newBuilder() .setId(nextExprId()) - .setCreateMap(CelExpr.CelCreateMap.newBuilder().addEntries(entries).build()) + .setCreateMap(CelExpr.CelMap.newBuilder().addEntries(entries).build()) .build(); } - /** - * Creates a new map {@link CelExpr.CelCreateStruct.Entry} comprised of the given key and value. - */ - public final CelExpr.CelCreateMap.Entry newMapEntry(CelExpr key, CelExpr value) { - return CelExpr.CelCreateMap.Entry.newBuilder() + /** Creates a new map {@link CelExpr.CelStruct.Entry} comprised of the given key and value. */ + public final CelExpr.CelMap.Entry newMapEntry(CelExpr key, CelExpr value) { + return CelExpr.CelMap.Entry.newBuilder() .setId(nextExprId()) .setKey(key) .setValue(value) @@ -125,30 +123,26 @@ public final CelExpr.CelCreateMap.Entry newMapEntry(CelExpr key, CelExpr value) } /** Creates a new message {@link CelExpr} of the given type comprised of the given fields. */ - public final CelExpr newMessage(String typeName, CelExpr.CelCreateStruct.Entry... fields) { + public final CelExpr newMessage(String typeName, CelExpr.CelStruct.Entry... fields) { return newMessage(typeName, Arrays.asList(fields)); } /** Creates a new message {@link CelExpr} of the given type comprised of the given fields. */ - public final CelExpr newMessage(String typeName, Iterable fields) { + public final CelExpr newMessage(String typeName, Iterable fields) { checkArgument(!isNullOrEmpty(typeName)); return CelExpr.newBuilder() .setId(nextExprId()) .setCreateStruct( - CelExpr.CelCreateStruct.newBuilder() - .setMessageName(typeName) - .addEntries(fields) - .build()) + CelExpr.CelStruct.newBuilder().setMessageName(typeName).addEntries(fields).build()) .build(); } /** - * Creates a new message {@link CelExpr.CelCreateStruct.Entry} comprised of the given field and - * value. + * Creates a new message {@link CelExpr.CelStruct.Entry} comprised of the given field and value. */ - public final CelExpr.CelCreateStruct.Entry newMessageField(String field, CelExpr value) { + public final CelExpr.CelStruct.Entry newMessageField(String field, CelExpr value) { checkArgument(!isNullOrEmpty(field)); - return CelExpr.CelCreateStruct.Entry.newBuilder() + return CelExpr.CelStruct.Entry.newBuilder() .setId(nextExprId()) .setFieldKey(field) .setValue(value) diff --git a/common/src/main/java/dev/cel/common/ast/CelExprFormatter.java b/common/src/main/java/dev/cel/common/ast/CelExprFormatter.java index 32e0233d0..e6783e359 100644 --- a/common/src/main/java/dev/cel/common/ast/CelExprFormatter.java +++ b/common/src/main/java/dev/cel/common/ast/CelExprFormatter.java @@ -32,8 +32,24 @@ static String format(CelExpr celExpr) { } private void formatExpr(CelExpr celExpr) { - append(String.format("%s [%d] {", celExpr.exprKind().getKind(), celExpr.id())); CelExpr.ExprKind.Kind exprKind = celExpr.exprKind().getKind(); + String kindFormattedText; + // Temporarily retain existing formatted expr kinds until callers are migrated + switch (exprKind) { + case LIST: + kindFormattedText = "CREATE_LIST"; + break; + case STRUCT: + kindFormattedText = "CREATE_STRUCT"; + break; + case MAP: + kindFormattedText = "CREATE_MAP"; + break; + default: + kindFormattedText = exprKind.toString(); + break; + } + append(String.format("%s [%d] {", kindFormattedText, celExpr.id())); if (!EXCLUDED_NEWLINE_KINDS.contains(exprKind)) { appendNewline(); } @@ -51,13 +67,13 @@ private void formatExpr(CelExpr celExpr) { case CALL: appendCall(celExpr.call()); break; - case CREATE_LIST: + case LIST: appendCreateList(celExpr.createList()); break; - case CREATE_STRUCT: + case STRUCT: appendCreateStruct(celExpr.createStruct()); break; - case CREATE_MAP: + case MAP: appendCreateMap(celExpr.createMap()); break; case COMPREHENSION: @@ -152,7 +168,7 @@ private void appendCall(CelExpr.CelCall celCall) { outdent(); } - private void appendCreateList(CelExpr.CelCreateList celCreateList) { + private void appendCreateList(CelExpr.CelList celCreateList) { indent(); append("elements: {"); indent(); @@ -177,12 +193,12 @@ private void appendCreateList(CelExpr.CelCreateList celCreateList) { outdent(); } - private void appendCreateStruct(CelExpr.CelCreateStruct celCreateStruct) { + private void appendCreateStruct(CelExpr.CelStruct celCreateStruct) { indent(); appendWithNewline("name: " + celCreateStruct.messageName()); append("entries: {"); indent(); - for (CelExpr.CelCreateStruct.Entry entry : celCreateStruct.entries()) { + for (CelExpr.CelStruct.Entry entry : celCreateStruct.entries()) { appendNewline(); appendWithNewline(String.format("ENTRY [%d] {", entry.id())); indent(); @@ -205,10 +221,10 @@ private void appendCreateStruct(CelExpr.CelCreateStruct celCreateStruct) { outdent(); } - private void appendCreateMap(CelExpr.CelCreateMap celCreateMap) { + private void appendCreateMap(CelExpr.CelMap celCreateMap) { indent(); boolean firstLine = true; - for (CelExpr.CelCreateMap.Entry entry : celCreateMap.entries()) { + for (CelExpr.CelMap.Entry entry : celCreateMap.entries()) { if (!firstLine) { appendNewline(); } else { diff --git a/common/src/main/java/dev/cel/common/ast/CelExprV1Alpha1Converter.java b/common/src/main/java/dev/cel/common/ast/CelExprV1Alpha1Converter.java index b22daf514..57b4a46eb 100644 --- a/common/src/main/java/dev/cel/common/ast/CelExprV1Alpha1Converter.java +++ b/common/src/main/java/dev/cel/common/ast/CelExprV1Alpha1Converter.java @@ -68,16 +68,16 @@ public static Expr fromCelExpr(CelExpr celExpr) { .addAllArgs(fromCelExprList(celCall.args())); celCall.target().ifPresent(target -> callBuilder.setTarget(fromCelExpr(target))); return expr.setCallExpr(callBuilder).build(); - case CREATE_LIST: - CelExpr.CelCreateList celCreateList = celExprKind.createList(); + case LIST: + CelExpr.CelList celCreateList = celExprKind.list(); return expr.setListExpr( CreateList.newBuilder() .addAllElements(fromCelExprList(celCreateList.elements())) .addAllOptionalIndices(celCreateList.optionalIndices())) .build(); - case CREATE_STRUCT: + case STRUCT: return expr.setStructExpr(celStructToExprStruct(celExprKind.createStruct())).build(); - case CREATE_MAP: + case MAP: return expr.setStructExpr(celMapToExprStruct(celExprKind.createMap())).build(); case COMPREHENSION: CelExpr.CelComprehension celComprehension = celExprKind.comprehension(); @@ -202,7 +202,7 @@ public static CelConstant exprConstantToCelConstant(Constant constExpr) { private static CelExpr exprStructToCelStruct(long id, CreateStruct structExpr) { if (!structExpr.getMessageName().isEmpty()) { - ImmutableList.Builder entries = ImmutableList.builder(); + ImmutableList.Builder entries = ImmutableList.builder(); for (Entry structExprEntry : structExpr.getEntriesList()) { if (!structExprEntry.getKeyKindCase().equals(KeyKindCase.FIELD_KEY)) { throw new IllegalArgumentException( @@ -218,7 +218,7 @@ private static CelExpr exprStructToCelStruct(long id, CreateStruct structExpr) { return CelExpr.ofCreateStruct(id, structExpr.getMessageName(), entries.build()); } else { - ImmutableList.Builder entries = ImmutableList.builder(); + ImmutableList.Builder entries = ImmutableList.builder(); for (Entry mapExprEntry : structExpr.getEntriesList()) { if (!mapExprEntry.getKeyKindCase().equals(KeyKindCase.MAP_KEY)) { throw new IllegalArgumentException( @@ -270,9 +270,9 @@ public static Constant celConstantToExprConstant(CelConstant celConstant) { throw new IllegalStateException("unsupported constant case: " + celConstant.getKind()); } - private static CreateStruct celStructToExprStruct(CelExpr.CelCreateStruct celCreateStruct) { + private static CreateStruct celStructToExprStruct(CelExpr.CelStruct celCreateStruct) { ImmutableList.Builder entries = ImmutableList.builder(); - for (CelExpr.CelCreateStruct.Entry celStructExprEntry : celCreateStruct.entries()) { + for (CelExpr.CelStruct.Entry celStructExprEntry : celCreateStruct.entries()) { entries.add( CreateStruct.Entry.newBuilder() .setId(celStructExprEntry.id()) @@ -288,9 +288,9 @@ private static CreateStruct celStructToExprStruct(CelExpr.CelCreateStruct celCre .build(); } - private static CreateStruct celMapToExprStruct(CelExpr.CelCreateMap celCreateMap) { + private static CreateStruct celMapToExprStruct(CelExpr.CelMap celCreateMap) { ImmutableList.Builder entries = ImmutableList.builder(); - for (CelExpr.CelCreateMap.Entry celMapEntry : celCreateMap.entries()) { + for (CelExpr.CelMap.Entry celMapEntry : celCreateMap.entries()) { CreateStruct.Entry exprMapEntry = CreateStruct.Entry.newBuilder() .setId(celMapEntry.id()) diff --git a/common/src/main/java/dev/cel/common/ast/CelExprVisitor.java b/common/src/main/java/dev/cel/common/ast/CelExprVisitor.java index ca0911364..e35b19aca 100644 --- a/common/src/main/java/dev/cel/common/ast/CelExprVisitor.java +++ b/common/src/main/java/dev/cel/common/ast/CelExprVisitor.java @@ -17,11 +17,11 @@ import dev.cel.common.CelAbstractSyntaxTree; import dev.cel.common.ast.CelExpr.CelCall; import dev.cel.common.ast.CelExpr.CelComprehension; -import dev.cel.common.ast.CelExpr.CelCreateList; -import dev.cel.common.ast.CelExpr.CelCreateMap; -import dev.cel.common.ast.CelExpr.CelCreateStruct; import dev.cel.common.ast.CelExpr.CelIdent; +import dev.cel.common.ast.CelExpr.CelList; +import dev.cel.common.ast.CelExpr.CelMap; import dev.cel.common.ast.CelExpr.CelSelect; +import dev.cel.common.ast.CelExpr.CelStruct; /** CEL expression visitor implementation using Cel native types. */ public class CelExprVisitor { @@ -60,13 +60,13 @@ public void visit(CelExpr expr) { case CALL: visit(expr, expr.call()); break; - case CREATE_LIST: + case LIST: visit(expr, expr.createList()); break; - case CREATE_STRUCT: + case STRUCT: visit(expr, expr.createStruct()); break; - case CREATE_MAP: + case MAP: visit(expr, expr.createMap()); break; case COMPREHENSION: @@ -107,23 +107,23 @@ protected void visit(CelExpr expr, CelCall call) { } } - /** Visit a {@code CelCreateStruct} expression. */ - protected void visit(CelExpr expr, CelCreateStruct createStruct) { - for (CelCreateStruct.Entry entry : createStruct.entries()) { + /** Visit a {@code CelStruct} expression. */ + protected void visit(CelExpr expr, CelStruct createStruct) { + for (CelStruct.Entry entry : createStruct.entries()) { visit(entry.value()); } } - /** Visit a {@code CelCreateMap} expression. */ - protected void visit(CelExpr expr, CelCreateMap createMap) { - for (CelCreateMap.Entry entry : createMap.entries()) { + /** Visit a {@code CelMap} expression. */ + protected void visit(CelExpr expr, CelMap createMap) { + for (CelMap.Entry entry : createMap.entries()) { visit(entry.key()); visit(entry.value()); } } - /** Visit a {@code CelCreateList} expression. */ - protected void visit(CelExpr expr, CelCreateList createList) { + /** Visit a {@code CelList} expression. */ + protected void visit(CelExpr expr, CelList createList) { for (CelExpr elem : createList.elements()) { visit(elem); } diff --git a/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java b/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java index ff2c83285..4e7990179 100644 --- a/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java +++ b/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java @@ -87,19 +87,19 @@ public CelMutableCall call() { @Override public CelMutableCreateList createList() { - checkExprKind(Kind.CREATE_LIST); + checkExprKind(Kind.LIST); return (CelMutableCreateList) exprValue; } @Override public CelMutableCreateStruct createStruct() { - checkExprKind(Kind.CREATE_STRUCT); + checkExprKind(Kind.STRUCT); return (CelMutableCreateStruct) exprValue; } @Override public CelMutableCreateMap createMap() { - checkExprKind(Kind.CREATE_MAP); + checkExprKind(Kind.MAP); return (CelMutableCreateMap) exprValue; } @@ -130,17 +130,17 @@ public void setCall(CelMutableCall call) { } public void setCreateList(CelMutableCreateList createList) { - this.exprKind = ExprKind.Kind.CREATE_LIST; + this.exprKind = ExprKind.Kind.LIST; this.exprValue = checkNotNull(createList); } public void setCreateStruct(CelMutableCreateStruct createStruct) { - this.exprKind = ExprKind.Kind.CREATE_STRUCT; + this.exprKind = ExprKind.Kind.STRUCT; this.exprValue = checkNotNull(createStruct); } public void setCreateMap(CelMutableCreateMap createMap) { - this.exprKind = ExprKind.Kind.CREATE_MAP; + this.exprKind = ExprKind.Kind.MAP; this.exprValue = checkNotNull(createMap); } @@ -1079,13 +1079,13 @@ private CelMutableExpr(CelMutableExpr other) { case CALL: this.exprValue = other.call().deepCopy(); break; - case CREATE_LIST: + case LIST: this.exprValue = other.createList().deepCopy(); break; - case CREATE_STRUCT: + case STRUCT: this.exprValue = other.createStruct().deepCopy(); break; - case CREATE_MAP: + case MAP: this.exprValue = other.createMap().deepCopy(); break; case COMPREHENSION: @@ -1108,11 +1108,11 @@ private Object exprValue() { return select(); case CALL: return call(); - case CREATE_LIST: + case LIST: return createList(); - case CREATE_STRUCT: + case STRUCT: return createStruct(); - case CREATE_MAP: + case MAP: return createMap(); case COMPREHENSION: return comprehension(); diff --git a/common/src/main/java/dev/cel/common/ast/CelMutableExprConverter.java b/common/src/main/java/dev/cel/common/ast/CelMutableExprConverter.java index 1f72f0132..cf5fc6b94 100644 --- a/common/src/main/java/dev/cel/common/ast/CelMutableExprConverter.java +++ b/common/src/main/java/dev/cel/common/ast/CelMutableExprConverter.java @@ -20,10 +20,10 @@ import com.google.common.collect.ImmutableList; import dev.cel.common.ast.CelExpr.CelCall; import dev.cel.common.ast.CelExpr.CelComprehension; -import dev.cel.common.ast.CelExpr.CelCreateList; -import dev.cel.common.ast.CelExpr.CelCreateMap; -import dev.cel.common.ast.CelExpr.CelCreateStruct; +import dev.cel.common.ast.CelExpr.CelList; +import dev.cel.common.ast.CelExpr.CelMap; import dev.cel.common.ast.CelExpr.CelSelect; +import dev.cel.common.ast.CelExpr.CelStruct; import dev.cel.common.ast.CelMutableExpr.CelMutableCall; import dev.cel.common.ast.CelMutableExpr.CelMutableComprehension; import dev.cel.common.ast.CelMutableExpr.CelMutableCreateList; @@ -65,16 +65,16 @@ public static CelMutableExpr fromCelExpr(CelExpr celExpr) { : CelMutableCall.create(celCall.function(), args); return CelMutableExpr.ofCall(celExpr.id(), mutableCall); - case CREATE_LIST: - CelCreateList createList = celExpr.createList(); + case LIST: + CelList createList = celExpr.createList(); return CelMutableExpr.ofCreateList( celExpr.id(), CelMutableCreateList.create( fromCelExprList(createList.elements()), createList.optionalIndices())); - case CREATE_STRUCT: + case STRUCT: return CelMutableExpr.ofCreateStruct( celExpr.id(), fromCelStructToMutableStruct(celExpr.createStruct())); - case CREATE_MAP: + case MAP: return CelMutableExpr.ofCreateMap( celExpr.id(), fromCelMapToMutableMap(celExpr.createMap())); case COMPREHENSION: @@ -105,10 +105,9 @@ private static List fromCelExprList(Iterable celExprLis return mutableExprList; } - private static CelMutableCreateStruct fromCelStructToMutableStruct( - CelCreateStruct celCreateStruct) { + private static CelMutableCreateStruct fromCelStructToMutableStruct(CelStruct celCreateStruct) { List entries = new ArrayList<>(); - for (CelCreateStruct.Entry celStructExprEntry : celCreateStruct.entries()) { + for (CelStruct.Entry celStructExprEntry : celCreateStruct.entries()) { entries.add( CelMutableCreateStruct.Entry.create( celStructExprEntry.id(), @@ -120,9 +119,9 @@ private static CelMutableCreateStruct fromCelStructToMutableStruct( return CelMutableCreateStruct.create(celCreateStruct.messageName(), entries); } - private static CelMutableCreateMap fromCelMapToMutableMap(CelCreateMap celCreateMap) { + private static CelMutableCreateMap fromCelMapToMutableMap(CelMap celCreateMap) { List entries = new ArrayList<>(); - for (CelCreateMap.Entry celMapExprEntry : celCreateMap.entries()) { + for (CelMap.Entry celMapExprEntry : celCreateMap.entries()) { entries.add( CelMutableCreateMap.Entry.create( celMapExprEntry.id(), @@ -154,19 +153,19 @@ public static CelExpr fromMutableExpr(CelMutableExpr mutableExpr) { Optional targetExpr = mutableCall.target().map(CelMutableExprConverter::fromMutableExpr); return CelExpr.ofCall(id, targetExpr, mutableCall.function(), args); - case CREATE_LIST: + case LIST: CelMutableCreateList mutableCreateList = mutableExpr.createList(); return CelExpr.ofCreateList( id, fromMutableExprList(mutableCreateList.elements()), ImmutableList.copyOf(mutableCreateList.optionalIndices())); - case CREATE_STRUCT: + case STRUCT: CelMutableCreateStruct mutableCreateStruct = mutableExpr.createStruct(); return CelExpr.newBuilder() .setId(id) .setCreateStruct(fromMutableStructToCelStruct(mutableCreateStruct)) .build(); - case CREATE_MAP: + case MAP: CelMutableCreateMap mutableCreateMap = mutableExpr.createMap(); return CelExpr.newBuilder() .setId(id) @@ -199,9 +198,9 @@ private static ImmutableList fromMutableExprList( return celExprList.build(); } - private static CelCreateStruct fromMutableStructToCelStruct( + private static CelStruct fromMutableStructToCelStruct( CelMutableCreateStruct mutableCreateStruct) { - List entries = new ArrayList<>(); + List entries = new ArrayList<>(); for (CelMutableCreateStruct.Entry mutableStructEntry : mutableCreateStruct.entries()) { entries.add( CelExpr.ofCreateStructEntry( @@ -211,14 +210,14 @@ private static CelCreateStruct fromMutableStructToCelStruct( mutableStructEntry.optionalEntry())); } - return CelCreateStruct.newBuilder() + return CelStruct.newBuilder() .setMessageName(mutableCreateStruct.messageName()) .addEntries(entries) .build(); } - private static CelCreateMap fromMutableMapToCelMap(CelMutableCreateMap mutableCreateMap) { - List entries = new ArrayList<>(); + private static CelMap fromMutableMapToCelMap(CelMutableCreateMap mutableCreateMap) { + List entries = new ArrayList<>(); for (CelMutableCreateMap.Entry mutableMapEntry : mutableCreateMap.entries()) { entries.add( CelExpr.ofCreateMapEntry( @@ -228,7 +227,7 @@ private static CelCreateMap fromMutableMapToCelMap(CelMutableCreateMap mutableCr mutableMapEntry.optionalEntry())); } - return CelCreateMap.newBuilder().addEntries(entries).build(); + return CelMap.newBuilder().addEntries(entries).build(); } private CelMutableExprConverter() {} diff --git a/common/src/main/java/dev/cel/common/navigation/CelNavigableExprVisitor.java b/common/src/main/java/dev/cel/common/navigation/CelNavigableExprVisitor.java index 73cfecd0b..06956d425 100644 --- a/common/src/main/java/dev/cel/common/navigation/CelNavigableExprVisitor.java +++ b/common/src/main/java/dev/cel/common/navigation/CelNavigableExprVisitor.java @@ -105,16 +105,16 @@ private void visit(T navigableExpr) { case CALL: visit(navigableExpr, navigableExpr.expr().call()); break; - case CREATE_LIST: + case LIST: visit(navigableExpr, navigableExpr.expr().createList()); break; case SELECT: visit(navigableExpr, navigableExpr.expr().select()); break; - case CREATE_STRUCT: + case STRUCT: visitStruct(navigableExpr, navigableExpr.expr().createStruct()); break; - case CREATE_MAP: + case MAP: visitMap(navigableExpr, navigableExpr.expr().createMap()); break; case COMPREHENSION: diff --git a/common/src/main/java/dev/cel/common/navigation/ExprPropertyCalculator.java b/common/src/main/java/dev/cel/common/navigation/ExprPropertyCalculator.java index 63097a1e3..f939f3b4b 100644 --- a/common/src/main/java/dev/cel/common/navigation/ExprPropertyCalculator.java +++ b/common/src/main/java/dev/cel/common/navigation/ExprPropertyCalculator.java @@ -54,16 +54,16 @@ private ExprProperty visit(E expr) { case CALL: visitedProperty = visit(expr.call()); break; - case CREATE_LIST: + case LIST: visitedProperty = visit(expr.createList()); break; case SELECT: visitedProperty = visit(expr.select()); break; - case CREATE_STRUCT: + case STRUCT: visitedProperty = visitStruct(expr.createStruct()); break; - case CREATE_MAP: + case MAP: visitedProperty = visitMap(expr.createMap()); break; case COMPREHENSION: diff --git a/common/src/test/java/dev/cel/common/ast/CelExprTest.java b/common/src/test/java/dev/cel/common/ast/CelExprTest.java index c9663978c..5df979e41 100644 --- a/common/src/test/java/dev/cel/common/ast/CelExprTest.java +++ b/common/src/test/java/dev/cel/common/ast/CelExprTest.java @@ -21,11 +21,11 @@ import com.google.testing.junit.testparameterinjector.TestParameterInjector; import dev.cel.common.ast.CelExpr.CelCall; import dev.cel.common.ast.CelExpr.CelComprehension; -import dev.cel.common.ast.CelExpr.CelCreateList; -import dev.cel.common.ast.CelExpr.CelCreateMap; -import dev.cel.common.ast.CelExpr.CelCreateStruct; import dev.cel.common.ast.CelExpr.CelIdent; +import dev.cel.common.ast.CelExpr.CelList; +import dev.cel.common.ast.CelExpr.CelMap; import dev.cel.common.ast.CelExpr.CelSelect; +import dev.cel.common.ast.CelExpr.CelStruct; import dev.cel.common.ast.CelExpr.ExprKind; import dev.cel.common.ast.CelExpr.ExprKind.Kind; import org.junit.Test; @@ -66,15 +66,11 @@ private enum BuilderExprKindTestCase { .build()) .build(), Kind.SELECT), - CREATE_MAP( - CelExpr.newBuilder().setCreateMap(CelCreateMap.newBuilder().build()).build(), - Kind.CREATE_MAP), + CREATE_MAP(CelExpr.newBuilder().setCreateMap(CelMap.newBuilder().build()).build(), Kind.MAP), CREATE_LIST( - CelExpr.newBuilder().setCreateList(CelCreateList.newBuilder().build()).build(), - Kind.CREATE_LIST), + CelExpr.newBuilder().setCreateList(CelList.newBuilder().build()).build(), Kind.LIST), CREATE_STRUCT( - CelExpr.newBuilder().setCreateStruct(CelCreateStruct.newBuilder().build()).build(), - Kind.CREATE_STRUCT), + CelExpr.newBuilder().setCreateStruct(CelStruct.newBuilder().build()).build(), Kind.STRUCT), COMPREHENSION( CelExpr.newBuilder() .setComprehension( @@ -204,10 +200,8 @@ public void celExprBuilder_setSelect() { @Test public void celExprBuilder_setCreateList() { - CelCreateList celCreateList = - CelCreateList.newBuilder() - .addElements(CelExpr.ofConstant(1, CelConstant.ofValue(2))) - .build(); + CelList celCreateList = + CelList.newBuilder().addElements(CelExpr.ofConstant(1, CelConstant.ofValue(2))).build(); CelExpr celExpr = CelExpr.newBuilder().setCreateList(celCreateList).build(); assertThat(celExpr.createList()).isEqualTo(celCreateList); @@ -216,10 +210,8 @@ public void celExprBuilder_setCreateList() { @Test public void createListBuilder_getArgs() { - CelCreateList celCreateList = - CelCreateList.newBuilder() - .addElements(CelExpr.ofConstant(1, CelConstant.ofValue(2))) - .build(); + CelList celCreateList = + CelList.newBuilder().addElements(CelExpr.ofConstant(1, CelConstant.ofValue(2))).build(); assertThat(celCreateList.toBuilder().getElements()) .containsExactly(CelExpr.ofConstant(1, CelConstant.ofValue(2))); @@ -227,8 +219,8 @@ public void createListBuilder_getArgs() { @Test public void celExprBuilder_setCreateList_setElementByIndex() { - CelCreateList celCreateList = - CelCreateList.newBuilder() + CelList celCreateList = + CelList.newBuilder() .addElements( CelExpr.ofConstant(5, CelConstant.ofValue("hello")), CelExpr.ofConstant(6, CelConstant.ofValue(5))) @@ -244,7 +236,7 @@ public void celExprBuilder_setCreateList_setElementByIndex() { assertThat(celExpr.createList()) .isEqualTo( - CelCreateList.newBuilder() + CelList.newBuilder() .addElements( CelExpr.ofConstant(5, CelConstant.ofValue("hello")), CelExpr.ofConstant(7, CelConstant.ofValue("world"))) @@ -253,10 +245,10 @@ public void celExprBuilder_setCreateList_setElementByIndex() { @Test public void celExprBuilder_setCreateStruct() { - CelCreateStruct celCreateStruct = - CelCreateStruct.newBuilder() + CelStruct celCreateStruct = + CelStruct.newBuilder() .addEntries( - CelCreateStruct.Entry.newBuilder() + CelStruct.Entry.newBuilder() .setId(1) .setValue(CelExpr.newBuilder().build()) .setFieldKey("field_key") @@ -271,10 +263,10 @@ public void celExprBuilder_setCreateStruct() { @Test public void createStructBuilder_getArgs() { - CelCreateStruct celCreateStruct = - CelCreateStruct.newBuilder() + CelStruct celCreateStruct = + CelStruct.newBuilder() .addEntries( - CelCreateStruct.Entry.newBuilder() + CelStruct.Entry.newBuilder() .setId(1) .setValue(CelExpr.newBuilder().build()) .setFieldKey("field_key") @@ -283,7 +275,7 @@ public void createStructBuilder_getArgs() { assertThat(celCreateStruct.toBuilder().getEntries()) .containsExactly( - CelCreateStruct.Entry.newBuilder() + CelStruct.Entry.newBuilder() .setId(1) .setValue(CelExpr.newBuilder().build()) .setFieldKey("field_key") @@ -292,19 +284,18 @@ public void createStructBuilder_getArgs() { @Test public void celExprBuilder_setCreateStruct_setEntryByIndex() { - CelCreateStruct celCreateStruct = - CelCreateStruct.newBuilder() + CelStruct celCreateStruct = + CelStruct.newBuilder() .addEntries( - CelCreateStruct.Entry.newBuilder() + CelStruct.Entry.newBuilder() .setId(2) .setValue( CelExpr.ofConstant(5, CelConstant.ofValue("hello")).toBuilder().build()) .setFieldKey("field_key") .build(), - CelCreateStruct.Entry.newBuilder() + CelStruct.Entry.newBuilder() .setId(3) - .setValue( - CelExpr.ofConstant(6, CelConstant.ofValue(100)).toBuilder().build()) + .setValue(CelExpr.ofConstant(6, CelConstant.ofValue(100)).toBuilder().build()) .setFieldKey("field_key") .build()) .build(); @@ -315,7 +306,7 @@ public void celExprBuilder_setCreateStruct_setEntryByIndex() { celCreateStruct.toBuilder() .setEntry( 1, - CelCreateStruct.Entry.newBuilder() + CelStruct.Entry.newBuilder() .setId(4) .setValue( CelExpr.ofConstant(6, CelConstant.ofValue("world")).toBuilder() @@ -327,20 +318,18 @@ public void celExprBuilder_setCreateStruct_setEntryByIndex() { assertThat(celExpr.createStruct()) .isEqualTo( - CelCreateStruct.newBuilder() + CelStruct.newBuilder() .addEntries( - CelCreateStruct.Entry.newBuilder() + CelStruct.Entry.newBuilder() .setId(2) .setValue( - CelExpr.ofConstant(5, CelConstant.ofValue("hello")).toBuilder() - .build()) + CelExpr.ofConstant(5, CelConstant.ofValue("hello")).toBuilder().build()) .setFieldKey("field_key") .build(), - CelCreateStruct.Entry.newBuilder() + CelStruct.Entry.newBuilder() .setId(4) .setValue( - CelExpr.ofConstant(6, CelConstant.ofValue("world")).toBuilder() - .build()) + CelExpr.ofConstant(6, CelConstant.ofValue("world")).toBuilder().build()) .setFieldKey("field_key") .build()) .build()); @@ -388,17 +377,17 @@ public void getUnderlyingExpression_unmatchedKind_throws( assertThrows(UnsupportedOperationException.class, testCase.expr::call); assertThrows(UnsupportedOperationException.class, () -> testCase.expr.toBuilder().call()); } - if (!testCase.expectedExprKind.equals(Kind.CREATE_LIST)) { + if (!testCase.expectedExprKind.equals(Kind.LIST)) { assertThrows(UnsupportedOperationException.class, testCase.expr::createList); assertThrows( UnsupportedOperationException.class, () -> testCase.expr.toBuilder().createList()); } - if (!testCase.expectedExprKind.equals(Kind.CREATE_STRUCT)) { + if (!testCase.expectedExprKind.equals(Kind.STRUCT)) { assertThrows(UnsupportedOperationException.class, testCase.expr::createStruct); assertThrows( UnsupportedOperationException.class, () -> testCase.expr.toBuilder().createStruct()); } - if (!testCase.expectedExprKind.equals(Kind.CREATE_MAP)) { + if (!testCase.expectedExprKind.equals(Kind.MAP)) { assertThrows(UnsupportedOperationException.class, testCase.expr::createMap); assertThrows( UnsupportedOperationException.class, () -> testCase.expr.toBuilder().createMap()); @@ -425,15 +414,14 @@ public void getDefault_unmatchedKind_returnsDefaultInstance( if (!testCase.expectedExprKind.equals(Kind.CALL)) { assertThat(testCase.expr.callOrDefault()).isEqualTo(CelCall.newBuilder().build()); } - if (!testCase.expectedExprKind.equals(Kind.CREATE_LIST)) { - assertThat(testCase.expr.createListOrDefault()).isEqualTo(CelCreateList.newBuilder().build()); + if (!testCase.expectedExprKind.equals(Kind.LIST)) { + assertThat(testCase.expr.createListOrDefault()).isEqualTo(CelList.newBuilder().build()); } - if (!testCase.expectedExprKind.equals(Kind.CREATE_STRUCT)) { - assertThat(testCase.expr.createStructOrDefault()) - .isEqualTo(CelCreateStruct.newBuilder().build()); + if (!testCase.expectedExprKind.equals(Kind.STRUCT)) { + assertThat(testCase.expr.createStructOrDefault()).isEqualTo(CelStruct.newBuilder().build()); } - if (!testCase.expectedExprKind.equals(Kind.CREATE_MAP)) { - assertThat(testCase.expr.createMapOrDefault()).isEqualTo(CelCreateMap.newBuilder().build()); + if (!testCase.expectedExprKind.equals(Kind.MAP)) { + assertThat(testCase.expr.createMapOrDefault()).isEqualTo(CelMap.newBuilder().build()); } if (!testCase.expectedExprKind.equals(Kind.COMPREHENSION)) { assertThat(testCase.expr.comprehensionOrDefault()) @@ -460,13 +448,13 @@ public void getDefault_matchedKind_returnsUnderlyingExpression( case CALL: assertThat(testCase.expr.callOrDefault()).isEqualTo(testCase.expr.call()); break; - case CREATE_LIST: + case LIST: assertThat(testCase.expr.createListOrDefault()).isEqualTo(testCase.expr.createList()); break; - case CREATE_STRUCT: + case STRUCT: assertThat(testCase.expr.createStructOrDefault()).isEqualTo(testCase.expr.createStruct()); break; - case CREATE_MAP: + case MAP: assertThat(testCase.expr.createMapOrDefault()).isEqualTo(testCase.expr.createMap()); break; case COMPREHENSION: @@ -477,22 +465,19 @@ public void getDefault_matchedKind_returnsUnderlyingExpression( @Test public void celCreateMapEntry_keyOrValueNotSet_throws() { - assertThrows(IllegalStateException.class, () -> CelCreateMap.Entry.newBuilder().build()); + assertThrows(IllegalStateException.class, () -> CelMap.Entry.newBuilder().build()); assertThrows( IllegalStateException.class, - () -> CelCreateMap.Entry.newBuilder().setKey(CelExpr.ofNotSet(1)).build()); + () -> CelMap.Entry.newBuilder().setKey(CelExpr.ofNotSet(1)).build()); assertThrows( IllegalStateException.class, - () -> CelCreateMap.Entry.newBuilder().setValue(CelExpr.ofNotSet(1)).build()); + () -> CelMap.Entry.newBuilder().setValue(CelExpr.ofNotSet(1)).build()); } @Test public void celCreateMapEntry_default() { - CelCreateMap.Entry entry = - CelCreateMap.Entry.newBuilder() - .setKey(CelExpr.ofNotSet(1)) - .setValue(CelExpr.ofNotSet(2)) - .build(); + CelMap.Entry entry = + CelMap.Entry.newBuilder().setKey(CelExpr.ofNotSet(1)).setValue(CelExpr.ofNotSet(2)).build(); assertThat(entry.id()).isEqualTo(0); assertThat(entry.optionalEntry()).isFalse(); @@ -500,22 +485,19 @@ public void celCreateMapEntry_default() { @Test public void celCreateStructEntry_fieldKeyOrValueNotSet_throws() { - assertThrows(IllegalStateException.class, () -> CelCreateStruct.Entry.newBuilder().build()); + assertThrows(IllegalStateException.class, () -> CelStruct.Entry.newBuilder().build()); assertThrows( IllegalStateException.class, - () -> CelCreateStruct.Entry.newBuilder().setFieldKey("fieldKey").build()); + () -> CelStruct.Entry.newBuilder().setFieldKey("fieldKey").build()); assertThrows( IllegalStateException.class, - () -> CelCreateStruct.Entry.newBuilder().setValue(CelExpr.ofNotSet(1)).build()); + () -> CelStruct.Entry.newBuilder().setValue(CelExpr.ofNotSet(1)).build()); } @Test public void celCreateStructEntry_default() { - CelCreateStruct.Entry entry = - CelCreateStruct.Entry.newBuilder() - .setFieldKey("fieldKey") - .setValue(CelExpr.ofNotSet(1)) - .build(); + CelStruct.Entry entry = + CelStruct.Entry.newBuilder().setFieldKey("fieldKey").setValue(CelExpr.ofNotSet(1)).build(); assertThat(entry.id()).isEqualTo(0); assertThat(entry.optionalEntry()).isFalse(); diff --git a/common/src/test/java/dev/cel/common/ast/CelExprVisitorTest.java b/common/src/test/java/dev/cel/common/ast/CelExprVisitorTest.java index 5cfcef44e..cec7fa4fa 100644 --- a/common/src/test/java/dev/cel/common/ast/CelExprVisitorTest.java +++ b/common/src/test/java/dev/cel/common/ast/CelExprVisitorTest.java @@ -22,12 +22,12 @@ import dev.cel.common.CelAbstractSyntaxTree; import dev.cel.common.ast.CelExpr.CelCall; import dev.cel.common.ast.CelExpr.CelComprehension; -import dev.cel.common.ast.CelExpr.CelCreateList; -import dev.cel.common.ast.CelExpr.CelCreateMap; -import dev.cel.common.ast.CelExpr.CelCreateStruct; -import dev.cel.common.ast.CelExpr.CelCreateStruct.Entry; import dev.cel.common.ast.CelExpr.CelIdent; +import dev.cel.common.ast.CelExpr.CelList; +import dev.cel.common.ast.CelExpr.CelMap; import dev.cel.common.ast.CelExpr.CelSelect; +import dev.cel.common.ast.CelExpr.CelStruct; +import dev.cel.common.ast.CelExpr.CelStruct.Entry; import dev.cel.common.types.SimpleType; import dev.cel.compiler.CelCompiler; import dev.cel.compiler.CelCompilerFactory; @@ -53,11 +53,11 @@ public abstract static class VisitedReference { public abstract Optional call(); - public abstract Optional createStruct(); + public abstract Optional createStruct(); - public abstract Optional createMap(); + public abstract Optional createMap(); - public abstract Optional createList(); + public abstract Optional createList(); public abstract Optional comprehension(); @@ -73,11 +73,11 @@ public abstract static class Builder { public abstract Builder setCall(CelCall value); - public abstract Builder setCreateStruct(CelCreateStruct value); + public abstract Builder setCreateStruct(CelStruct value); - public abstract Builder setCreateMap(CelCreateMap value); + public abstract Builder setCreateMap(CelMap value); - public abstract Builder setCreateList(CelCreateList value); + public abstract Builder setCreateList(CelList value); public abstract Builder setComprehension(CelComprehension value); @@ -124,19 +124,19 @@ protected void visit(CelExpr expr, CelCall call) { } @Override - protected void visit(CelExpr expr, CelCreateStruct createStruct) { + protected void visit(CelExpr expr, CelStruct createStruct) { visitedReference.setCreateStruct(createStruct); super.visit(expr, createStruct); } @Override - protected void visit(CelExpr expr, CelCreateMap createMap) { + protected void visit(CelExpr expr, CelMap createMap) { visitedReference.setCreateMap(createMap); super.visit(expr, createMap); } @Override - protected void visit(CelExpr expr, CelCreateList createList) { + protected void visit(CelExpr expr, CelList createList) { visitedReference.setCreateList(createList); super.visit(expr, createList); } @@ -204,17 +204,14 @@ public void visitSelect() throws Exception { assertThat(visited) .isEqualTo( VisitedReference.newBuilder() - .setCreateStruct( - CelCreateStruct.newBuilder().setMessageName("TestAllTypes").build()) + .setCreateStruct(CelStruct.newBuilder().setMessageName("TestAllTypes").build()) .setSelect( CelSelect.newBuilder() .setOperand( CelExpr.newBuilder() .setId(1) .setCreateStruct( - CelCreateStruct.newBuilder() - .setMessageName("TestAllTypes") - .build()) + CelStruct.newBuilder().setMessageName("TestAllTypes").build()) .build()) .setField("single_int64") .build()) @@ -262,7 +259,7 @@ public void visitCreateStruct_fieldkey() throws Exception { VisitedReference.newBuilder() .setConstant(longConstant) .setCreateStruct( - CelCreateStruct.newBuilder() + CelStruct.newBuilder() .addEntries( Entry.newBuilder() .setId(2) @@ -287,9 +284,9 @@ public void visitCreateMap() throws Exception { VisitedReference.newBuilder() .setConstant(CelConstant.ofValue("b")) .setCreateMap( - CelCreateMap.newBuilder() + CelMap.newBuilder() .addEntries( - CelCreateMap.Entry.newBuilder() + CelMap.Entry.newBuilder() .setId(2) .setKey(CelExpr.ofConstant(3, CelConstant.ofValue("a"))) .setValue(CelExpr.ofConstant(4, CelConstant.ofValue("b"))) @@ -312,7 +309,7 @@ public void visitCreateList() throws Exception { VisitedReference.newBuilder() .setConstant(integerVal) .setCreateList( - CelCreateList.newBuilder() + CelList.newBuilder() .addElements(CelExpr.newBuilder().setId(2).setConstant(integerVal).build()) .addElements(CelExpr.newBuilder().setId(3).setConstant(integerVal).build()) .build()) diff --git a/common/src/test/java/dev/cel/common/ast/CelMutableExprConverterTest.java b/common/src/test/java/dev/cel/common/ast/CelMutableExprConverterTest.java index 06e8ff41e..2d0419bd4 100644 --- a/common/src/test/java/dev/cel/common/ast/CelMutableExprConverterTest.java +++ b/common/src/test/java/dev/cel/common/ast/CelMutableExprConverterTest.java @@ -23,8 +23,8 @@ import com.google.testing.junit.testparameterinjector.TestParameter; import com.google.testing.junit.testparameterinjector.TestParameterInjector; import dev.cel.common.ast.CelExpr.CelCall; -import dev.cel.common.ast.CelExpr.CelCreateList; -import dev.cel.common.ast.CelExpr.CelCreateStruct; +import dev.cel.common.ast.CelExpr.CelList; +import dev.cel.common.ast.CelExpr.CelStruct; import dev.cel.common.ast.CelMutableExpr.CelMutableCall; import dev.cel.common.ast.CelMutableExpr.CelMutableComprehension; import dev.cel.common.ast.CelMutableExpr.CelMutableCreateList; @@ -199,7 +199,7 @@ public void convertCelCall_toMutableCall() { } @Test - public void convertMutableCreateList_toCelCreateList() { + public void convertMutableCreateList_toCelList() { CelMutableExpr mutableExpr = CelMutableExpr.ofCreateList( 1L, @@ -222,7 +222,7 @@ public void convertMutableCreateList_toCelCreateList() { } @Test - public void convertCelCreateList_toMutableCreateList() { + public void convertCelList_toMutableCreateList() { CelExpr celExpr = CelExpr.ofCreateList( 1L, @@ -245,7 +245,7 @@ public void convertCelCreateList_toMutableCreateList() { } @Test - public void convertMutableCreateStruct_toCelCreateStruct() { + public void convertMutableCreateStruct_toCelStruct() { CelMutableExpr mutableExpr = CelMutableExpr.ofCreateStruct( 8L, @@ -266,7 +266,7 @@ public void convertMutableCreateStruct_toCelCreateStruct() { 8L, "message", ImmutableList.of( - CelCreateStruct.Entry.newBuilder() + CelStruct.Entry.newBuilder() .setId(9L) .setFieldKey("field") .setValue(CelExpr.ofConstant(10L, CelConstant.ofValue("value"))) @@ -275,13 +275,13 @@ public void convertMutableCreateStruct_toCelCreateStruct() { } @Test - public void convertCelCreateStruct_toMutableCreateStruct() { + public void convertCelStruct_toMutableCreateStruct() { CelExpr celExpr = CelExpr.ofCreateStruct( 8L, "message", ImmutableList.of( - CelCreateStruct.Entry.newBuilder() + CelStruct.Entry.newBuilder() .setId(9L) .setFieldKey("field") .setValue(CelExpr.ofConstant(10L, CelConstant.ofValue("value"))) @@ -305,7 +305,7 @@ public void convertCelCreateStruct_toMutableCreateStruct() { } @Test - public void convertMutableCreateMap_toCelCreateMap() { + public void convertMutableCreateMap_toCelMap() { CelMutableExpr mutableExpr = CelMutableExpr.ofCreateMap( 9L, @@ -332,7 +332,7 @@ public void convertMutableCreateMap_toCelCreateMap() { } @Test - public void convertCelCreateMap_toMutableCreateMap() { + public void convertCelMap_toMutableCreateMap() { CelExpr celExpr = CelExpr.ofCreateMap( 9L, @@ -385,7 +385,7 @@ public void convertMutableComprehension_toCelComprehension() { CelExpr.newBuilder() .setId(2L) .setCreateList( - CelCreateList.newBuilder() + CelList.newBuilder() .addElements(CelExpr.ofConstant(3L, CelConstant.ofValue(true))) .build()) .build(), @@ -405,7 +405,7 @@ public void convertCelComprehension_toMutableComprehension() { CelExpr.newBuilder() .setId(2L) .setCreateList( - CelCreateList.newBuilder() + CelList.newBuilder() .addElements(CelExpr.ofConstant(3L, CelConstant.ofValue(true))) .build()) .build(), diff --git a/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java b/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java index 90901fc05..22f60fa04 100644 --- a/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java +++ b/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java @@ -886,13 +886,13 @@ public void getExprValue_invalidKind_throws(@TestParameter MutableExprKindTestCa if (!testCaseKind.equals(Kind.CALL)) { assertThrows(IllegalArgumentException.class, testCase.mutableExpr::call); } - if (!testCaseKind.equals(Kind.CREATE_LIST)) { + if (!testCaseKind.equals(Kind.LIST)) { assertThrows(IllegalArgumentException.class, testCase.mutableExpr::createList); } - if (!testCaseKind.equals(Kind.CREATE_STRUCT)) { + if (!testCaseKind.equals(Kind.STRUCT)) { assertThrows(IllegalArgumentException.class, testCase.mutableExpr::createStruct); } - if (!testCaseKind.equals(Kind.CREATE_MAP)) { + if (!testCaseKind.equals(Kind.MAP)) { assertThrows(IllegalArgumentException.class, testCase.mutableExpr::createMap); } if (!testCaseKind.equals(Kind.COMPREHENSION)) { diff --git a/common/src/test/java/dev/cel/common/navigation/CelNavigableExprVisitorTest.java b/common/src/test/java/dev/cel/common/navigation/CelNavigableExprVisitorTest.java index 18c71cb28..e2429c7db 100644 --- a/common/src/test/java/dev/cel/common/navigation/CelNavigableExprVisitorTest.java +++ b/common/src/test/java/dev/cel/common/navigation/CelNavigableExprVisitorTest.java @@ -446,12 +446,12 @@ public void stringFormatCall_filterList_success() throws Exception { navigableAst .getRoot() .allNodes() - .filter(x -> x.getKind().equals(Kind.CREATE_LIST)) + .filter(x -> x.getKind().equals(Kind.LIST)) .collect(toImmutableList()); assertThat(allConstants).hasSize(1); CelNavigableExpr listExpr = allConstants.get(0); - assertThat(listExpr.getKind()).isEqualTo(Kind.CREATE_LIST); + assertThat(listExpr.getKind()).isEqualTo(Kind.LIST); assertThat(listExpr.parent()).isPresent(); CelNavigableExpr stringFormatExpr = listExpr.parent().get(); assertThat(stringFormatExpr.getKind()).isEqualTo(Kind.CALL); @@ -613,7 +613,7 @@ public void messageConstruction_filterCreateStruct_allNodesReturned() throws Exc navigableAst .getRoot() .allNodes() - .filter(x -> x.getKind().equals(Kind.CREATE_STRUCT)) + .filter(x -> x.getKind().equals(Kind.STRUCT)) .collect(toImmutableList()); assertThat(allNodes).hasSize(1); @@ -718,7 +718,7 @@ public void mapConstruction_filterCreateMap_allNodesReturned() throws Exception navigableAst .getRoot() .allNodes() - .filter(x -> x.getKind().equals(Kind.CREATE_MAP)) + .filter(x -> x.getKind().equals(Kind.MAP)) .collect(toImmutableList()); assertThat(allNodes).hasSize(1); diff --git a/extensions/src/main/java/dev/cel/extensions/CelMathExtensions.java b/extensions/src/main/java/dev/cel/extensions/CelMathExtensions.java index 7326cabf9..59e51e366 100644 --- a/extensions/src/main/java/dev/cel/extensions/CelMathExtensions.java +++ b/extensions/src/main/java/dev/cel/extensions/CelMathExtensions.java @@ -526,7 +526,7 @@ private static Optional checkInvalidArgument( private static Optional checkInvalidArgumentSingleArg( CelMacroExprFactory exprFactory, String functionName, CelExpr argument) { - if (argument.exprKind().getKind() == Kind.CREATE_LIST) { + if (argument.exprKind().getKind() == Kind.LIST) { if (argument.createList().elements().isEmpty()) { return newError( exprFactory, String.format("%s invalid single argument value", functionName), argument); @@ -548,9 +548,9 @@ private static boolean isArgumentValidType(CelExpr argument) { return constant.getKind() == CelConstant.Kind.INT64_VALUE || constant.getKind() == CelConstant.Kind.UINT64_VALUE || constant.getKind() == CelConstant.Kind.DOUBLE_VALUE; - } else if (argument.exprKind().getKind().equals(Kind.CREATE_LIST) - || argument.exprKind().getKind().equals(Kind.CREATE_STRUCT) - || argument.exprKind().getKind().equals(Kind.CREATE_MAP)) { + } else if (argument.exprKind().getKind().equals(Kind.LIST) + || argument.exprKind().getKind().equals(Kind.STRUCT) + || argument.exprKind().getKind().equals(Kind.MAP)) { return false; } diff --git a/optimizer/src/main/java/dev/cel/optimizer/AstMutator.java b/optimizer/src/main/java/dev/cel/optimizer/AstMutator.java index 7a8b636fb..0dfc6a4dd 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/AstMutator.java +++ b/optimizer/src/main/java/dev/cel/optimizer/AstMutator.java @@ -694,7 +694,7 @@ private CelMutableSource normalizeMacroSource( long replacedId = idGenerator.generate(exprIdToReplace); boolean isListExprBeingReplaced = allExprs.containsKey(replacedId) - && allExprs.get(replacedId).getKind().equals(Kind.CREATE_LIST); + && allExprs.get(replacedId).getKind().equals(Kind.LIST); if (isListExprBeingReplaced) { unwrapListArgumentsInMacroCallExpr( allExprs.get(callId).comprehension(), newMacroCallExpr); @@ -758,8 +758,7 @@ private CelMutableSource normalizeMacroSource( private static void unwrapListArgumentsInMacroCallExpr( CelMutableComprehension comprehension, CelMutableExpr newMacroCallExpr) { CelMutableExpr accuInit = comprehension.accuInit(); - if (!accuInit.getKind().equals(Kind.CREATE_LIST) - || !accuInit.createList().elements().isEmpty()) { + if (!accuInit.getKind().equals(Kind.LIST) || !accuInit.createList().elements().isEmpty()) { // Does not contain an extraneous list. return; } diff --git a/optimizer/src/main/java/dev/cel/optimizer/MutableExprVisitor.java b/optimizer/src/main/java/dev/cel/optimizer/MutableExprVisitor.java index e5109eef0..fd5cf4653 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/MutableExprVisitor.java +++ b/optimizer/src/main/java/dev/cel/optimizer/MutableExprVisitor.java @@ -70,11 +70,11 @@ CelMutableExpr visit(CelMutableExpr root) { return visit(root, root.select()); case CALL: return visit(root, root.call()); - case CREATE_LIST: + case LIST: return visit(root, root.createList()); - case CREATE_STRUCT: + case STRUCT: return visit(root, root.createStruct()); - case CREATE_MAP: + case MAP: return visit(root, root.createMap()); case COMPREHENSION: return visit(root, root.comprehension()); diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java b/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java index cd7e7fcd0..588f77405 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java @@ -199,9 +199,9 @@ private static boolean areChildrenArgConstant(CelNavigableMutableExpr expr) { } if (expr.getKind().equals(Kind.CALL) - || expr.getKind().equals(Kind.CREATE_LIST) - || expr.getKind().equals(Kind.CREATE_MAP) - || expr.getKind().equals(Kind.CREATE_STRUCT)) { + || expr.getKind().equals(Kind.LIST) + || expr.getKind().equals(Kind.MAP) + || expr.getKind().equals(Kind.STRUCT)) { return expr.children().allMatch(ConstantFoldingOptimizer::areChildrenArgConstant); } @@ -335,7 +335,7 @@ private Optional maybePruneBranches( return Optional.of(astMutator.replaceSubtree(mutableAst, result, expr.id())); } else if (function.equals(Operator.IN.getFunction())) { CelMutableExpr callArg = call.args().get(1); - if (!callArg.getKind().equals(Kind.CREATE_LIST)) { + if (!callArg.getKind().equals(Kind.LIST)) { return Optional.empty(); } @@ -412,21 +412,21 @@ private CelMutableAst pruneOptionalElements(CelMutableAst ast) { .allNodes() .filter( node -> - node.getKind().equals(Kind.CREATE_LIST) - || node.getKind().equals(Kind.CREATE_MAP) - || node.getKind().equals(Kind.CREATE_STRUCT)) + node.getKind().equals(Kind.LIST) + || node.getKind().equals(Kind.MAP) + || node.getKind().equals(Kind.STRUCT)) .map(CelNavigableMutableExpr::expr) .collect(toImmutableList()); for (CelMutableExpr expr : aggregateLiterals) { switch (expr.getKind()) { - case CREATE_LIST: + case LIST: ast = pruneOptionalListElements(ast, expr); break; - case CREATE_MAP: + case MAP: ast = pruneOptionalMapElements(ast, expr); break; - case CREATE_STRUCT: + case STRUCT: ast = pruneOptionalStructElements(ast, expr); break; default: diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java index 7057eb4ba..e60fd47b2 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java @@ -557,7 +557,7 @@ private boolean canEliminate( && !(navigableExpr.getKind().equals(Kind.IDENT) && navigableExpr.expr().ident().name().startsWith(BIND_IDENTIFIER_PREFIX)) // Exclude empty lists (cel.bind sets this for iterRange). - && !(navigableExpr.getKind().equals(Kind.CREATE_LIST) + && !(navigableExpr.getKind().equals(Kind.LIST) && navigableExpr.expr().createList().elements().isEmpty()) && containsEliminableFunctionOnly(navigableExpr) && !ineligibleExprs.contains(navigableExpr.expr()); diff --git a/parser/src/main/java/dev/cel/parser/CelMacroExprFactory.java b/parser/src/main/java/dev/cel/parser/CelMacroExprFactory.java index 531622486..70adbf510 100644 --- a/parser/src/main/java/dev/cel/parser/CelMacroExprFactory.java +++ b/parser/src/main/java/dev/cel/parser/CelMacroExprFactory.java @@ -85,25 +85,23 @@ public final CelExpr copy(CelExpr expr) { builder.setCall(callBuilder.build()); } break; - case CREATE_LIST: + case LIST: { - CelExpr.CelCreateList.Builder listBuilder = - CelExpr.CelCreateList.newBuilder() - .addOptionalIndices(expr.createList().optionalIndices()); + CelExpr.CelList.Builder listBuilder = + CelExpr.CelList.newBuilder().addOptionalIndices(expr.createList().optionalIndices()); for (CelExpr element : expr.createList().elements()) { listBuilder.addElements(copy(element)); } builder.setCreateList(listBuilder.build()); } break; - case CREATE_STRUCT: + case STRUCT: { - CelExpr.CelCreateStruct.Builder structBuilder = - CelExpr.CelCreateStruct.newBuilder() - .setMessageName(expr.createStruct().messageName()); - for (CelExpr.CelCreateStruct.Entry entry : expr.createStruct().entries()) { + CelExpr.CelStruct.Builder structBuilder = + CelExpr.CelStruct.newBuilder().setMessageName(expr.createStruct().messageName()); + for (CelExpr.CelStruct.Entry entry : expr.createStruct().entries()) { structBuilder.addEntries( - CelExpr.CelCreateStruct.Entry.newBuilder() + CelExpr.CelStruct.Entry.newBuilder() .setId(copyExprId(entry.id())) .setFieldKey(entry.fieldKey()) .setValue(copy(entry.value())) @@ -113,12 +111,12 @@ public final CelExpr copy(CelExpr expr) { builder.setCreateStruct(structBuilder.build()); } break; - case CREATE_MAP: + case MAP: { - CelExpr.CelCreateMap.Builder mapBuilder = CelExpr.CelCreateMap.newBuilder(); - for (CelExpr.CelCreateMap.Entry entry : expr.createMap().entries()) { + CelExpr.CelMap.Builder mapBuilder = CelExpr.CelMap.newBuilder(); + for (CelExpr.CelMap.Entry entry : expr.createMap().entries()) { mapBuilder.addEntries( - CelExpr.CelCreateMap.Entry.newBuilder() + CelExpr.CelMap.Entry.newBuilder() .setId(copyExprId(entry.id())) .setKey(copy(entry.key())) .setValue(copy(entry.value())) diff --git a/parser/src/main/java/dev/cel/parser/CelUnparserVisitor.java b/parser/src/main/java/dev/cel/parser/CelUnparserVisitor.java index 6e8d2350a..b43779ffa 100644 --- a/parser/src/main/java/dev/cel/parser/CelUnparserVisitor.java +++ b/parser/src/main/java/dev/cel/parser/CelUnparserVisitor.java @@ -20,11 +20,11 @@ import dev.cel.common.ast.CelExpr; import dev.cel.common.ast.CelExpr.CelCall; import dev.cel.common.ast.CelExpr.CelComprehension; -import dev.cel.common.ast.CelExpr.CelCreateList; -import dev.cel.common.ast.CelExpr.CelCreateMap; -import dev.cel.common.ast.CelExpr.CelCreateStruct; import dev.cel.common.ast.CelExpr.CelIdent; +import dev.cel.common.ast.CelExpr.CelList; +import dev.cel.common.ast.CelExpr.CelMap; import dev.cel.common.ast.CelExpr.CelSelect; +import dev.cel.common.ast.CelExpr.CelStruct; import dev.cel.common.ast.CelExpr.ExprKind.Kind; import dev.cel.common.ast.CelExprVisitor; import java.util.HashSet; @@ -163,7 +163,7 @@ protected void visit(CelExpr expr, CelCall call) { } @Override - protected void visit(CelExpr expr, CelCreateList createList) { + protected void visit(CelExpr expr, CelList createList) { stringBuilder.append(LEFT_BRACKET); HashSet optionalIndices = new HashSet<>(createList.optionalIndices()); for (int i = 0; i < createList.elements().size(); i++) { @@ -179,7 +179,7 @@ protected void visit(CelExpr expr, CelCreateList createList) { } @Override - protected void visit(CelExpr expr, CelCreateStruct createStruct) { + protected void visit(CelExpr expr, CelStruct createStruct) { stringBuilder.append(createStruct.messageName()); stringBuilder.append(LEFT_BRACE); for (int i = 0; i < createStruct.entries().size(); i++) { @@ -187,7 +187,7 @@ protected void visit(CelExpr expr, CelCreateStruct createStruct) { stringBuilder.append(COMMA).append(SPACE); } - CelCreateStruct.Entry e = createStruct.entries().get(i); + CelStruct.Entry e = createStruct.entries().get(i); if (e.optionalEntry()) { stringBuilder.append(QUESTION_MARK); } @@ -199,14 +199,14 @@ protected void visit(CelExpr expr, CelCreateStruct createStruct) { } @Override - protected void visit(CelExpr expr, CelCreateMap createMap) { + protected void visit(CelExpr expr, CelMap createMap) { stringBuilder.append(LEFT_BRACE); for (int i = 0; i < createMap.entries().size(); i++) { if (i > 0) { stringBuilder.append(COMMA).append(SPACE); } - CelCreateMap.Entry e = createMap.entries().get(i); + CelMap.Entry e = createMap.entries().get(i); if (e.optionalEntry()) { stringBuilder.append(QUESTION_MARK); } diff --git a/parser/src/main/java/dev/cel/parser/Parser.java b/parser/src/main/java/dev/cel/parser/Parser.java index 95fac0008..c4b3dffb6 100644 --- a/parser/src/main/java/dev/cel/parser/Parser.java +++ b/parser/src/main/java/dev/cel/parser/Parser.java @@ -524,7 +524,7 @@ public CelExpr visitCreateMessage(CreateMessageContext context) { } CelExpr.Builder exprBuilder = exprFactory.newExprBuilder(context.op); - CelExpr.CelCreateStruct.Builder structExpr = visitStructFields(context.entries); + CelExpr.CelStruct.Builder structExpr = visitStructFields(context.entries); return exprBuilder.setCreateStruct(structExpr.setMessageName(messageName).build()).build(); } @@ -564,13 +564,13 @@ public CelExpr visitNested(NestedContext context) { public CelExpr visitCreateList(CreateListContext context) { checkNotNull(context); CelExpr.Builder exprBuilder = exprFactory.newExprBuilder(context.op); - CelExpr.CelCreateList createListExpr = visitListInitElements(context.listInit()); + CelExpr.CelList createListExpr = visitListInitElements(context.listInit()); return exprBuilder.setCreateList(createListExpr).build(); } - private CelExpr.CelCreateList visitListInitElements(ListInitContext context) { - CelExpr.CelCreateList.Builder listExpr = CelExpr.CelCreateList.newBuilder(); + private CelExpr.CelList visitListInitElements(ListInitContext context) { + CelExpr.CelList.Builder listExpr = CelExpr.CelList.newBuilder(); if (context == null) { return listExpr.build(); } @@ -595,8 +595,7 @@ private CelExpr.CelCreateList visitListInitElements(ListInitContext context) { public CelExpr visitCreateMap(CreateMapContext context) { checkNotNull(context); CelExpr.Builder exprBuilder = exprFactory.newExprBuilder(context.op); - CelExpr.CelCreateMap.Builder createMapExpr = visitMapEntries(context.entries); - // CelExpr.CelCreateStruct.Builder structExpr = visitMapEntries(context.entries); + CelExpr.CelMap.Builder createMapExpr = visitMapEntries(context.entries); return exprBuilder.setCreateMap(createMapExpr.build()).build(); } @@ -664,15 +663,15 @@ private Optional visitMacro( return expandedMacro; } - private CelExpr.CelCreateStruct.Builder visitStructFields(FieldInitializerListContext context) { + private CelExpr.CelStruct.Builder visitStructFields(FieldInitializerListContext context) { if (context == null || context.cols == null || context.fields == null || context.values == null) { - return CelExpr.CelCreateStruct.newBuilder(); + return CelExpr.CelStruct.newBuilder(); } int entryCount = min(context.cols.size(), context.fields.size(), context.values.size()); - CelExpr.CelCreateStruct.Builder structExpr = CelExpr.CelCreateStruct.newBuilder(); + CelExpr.CelStruct.Builder structExpr = CelExpr.CelStruct.newBuilder(); for (int index = 0; index < entryCount; index++) { OptFieldContext fieldContext = context.fields.get(index); boolean isOptionalEntry = false; @@ -686,12 +685,12 @@ private CelExpr.CelCreateStruct.Builder visitStructFields(FieldInitializerListCo // The field may be empty due to a prior error. if (fieldContext.IDENTIFIER() == null) { - return CelExpr.CelCreateStruct.newBuilder(); + return CelExpr.CelStruct.newBuilder(); } String fieldName = fieldContext.IDENTIFIER().getText(); - CelExpr.CelCreateStruct.Entry.Builder exprBuilder = - CelExpr.CelCreateStruct.Entry.newBuilder() + CelExpr.CelStruct.Entry.Builder exprBuilder = + CelExpr.CelStruct.Entry.newBuilder() .setId(exprFactory.newExprId(exprFactory.getPosition(context.cols.get(index)))); structExpr.addEntries( exprBuilder @@ -703,12 +702,12 @@ private CelExpr.CelCreateStruct.Builder visitStructFields(FieldInitializerListCo return structExpr; } - private CelExpr.CelCreateMap.Builder visitMapEntries(MapInitializerListContext context) { + private CelExpr.CelMap.Builder visitMapEntries(MapInitializerListContext context) { if (context == null || context.cols == null || context.keys == null || context.values == null) { - return CelExpr.CelCreateMap.newBuilder(); + return CelExpr.CelMap.newBuilder(); } int entryCount = min(context.cols.size(), context.keys.size(), context.values.size()); - CelExpr.CelCreateMap.Builder mapExpr = CelExpr.CelCreateMap.newBuilder(); + CelExpr.CelMap.Builder mapExpr = CelExpr.CelMap.newBuilder(); for (int index = 0; index < entryCount; index++) { OptExprContext keyContext = context.keys.get(index); boolean isOptionalEntry = false; @@ -719,8 +718,8 @@ private CelExpr.CelCreateMap.Builder visitMapEntries(MapInitializerListContext c isOptionalEntry = true; } } - CelExpr.CelCreateMap.Entry.Builder exprBuilder = - CelExpr.CelCreateMap.Entry.newBuilder() + CelExpr.CelMap.Entry.Builder exprBuilder = + CelExpr.CelMap.Entry.newBuilder() .setId(exprFactory.newExprId(exprFactory.getPosition(context.cols.get(index)))); mapExpr.addEntries( exprBuilder diff --git a/parser/src/test/java/dev/cel/parser/CelMacroExprFactoryTest.java b/parser/src/test/java/dev/cel/parser/CelMacroExprFactoryTest.java index eacd5479c..c14d22c6b 100644 --- a/parser/src/test/java/dev/cel/parser/CelMacroExprFactoryTest.java +++ b/parser/src/test/java/dev/cel/parser/CelMacroExprFactoryTest.java @@ -22,8 +22,8 @@ import dev.cel.common.CelSourceLocation; import dev.cel.common.ast.CelConstant; import dev.cel.common.ast.CelExpr; -import dev.cel.common.ast.CelExpr.CelCreateMap; -import dev.cel.common.ast.CelExpr.CelCreateStruct.Entry; +import dev.cel.common.ast.CelExpr.CelMap; +import dev.cel.common.ast.CelExpr.CelStruct.Entry; import dev.cel.common.ast.CelExpr.ExprKind.Kind; import dev.cel.common.internal.Constants; import org.junit.Test; @@ -155,7 +155,7 @@ public void newList_returnsList() { CelExpr element = exprFactory.newStringLiteral("foo"); CelExpr expr = exprFactory.newList(element); assertThat(expr.id()).isEqualTo(2L); - assertThat(expr.exprKind().getKind()).isEqualTo(Kind.CREATE_LIST); + assertThat(expr.exprKind().getKind()).isEqualTo(Kind.LIST); assertThat(expr.createList().elements()).hasSize(1); assertThat(expr.createList().elements()).containsExactly(element); } @@ -163,12 +163,12 @@ public void newList_returnsList() { @Test public void newMap_returnsMap() { TestCelExprFactory exprFactory = new TestCelExprFactory(); - CelCreateMap.Entry entry = + CelMap.Entry entry = exprFactory.newMapEntry( exprFactory.newStringLiteral("foo"), exprFactory.newStringLiteral("bar")); CelExpr expr = exprFactory.newMap(entry); assertThat(expr.id()).isEqualTo(4L); - assertThat(expr.exprKind().getKind()).isEqualTo(Kind.CREATE_MAP); + assertThat(expr.exprKind().getKind()).isEqualTo(Kind.MAP); assertThat(expr.createMap().entries()).containsExactly(entry); } @@ -177,7 +177,7 @@ public void newMapEntry_returnsMapEntry() { TestCelExprFactory exprFactory = new TestCelExprFactory(); CelExpr key = exprFactory.newStringLiteral("foo"); CelExpr value = exprFactory.newStringLiteral("bar"); - CelCreateMap.Entry entry = exprFactory.newMapEntry(key, value); + CelMap.Entry entry = exprFactory.newMapEntry(key, value); assertThat(entry.id()).isEqualTo(3L); assertThat(entry.value()).isEqualTo(value); } @@ -188,7 +188,7 @@ public void newMessage_returnsMessage() { Entry field = exprFactory.newMessageField("foo", exprFactory.newStringLiteral("bar")); CelExpr expr = exprFactory.newMessage("google.example.Baz", field); assertThat(expr.id()).isEqualTo(3L); - assertThat(expr.exprKind().getKind()).isEqualTo(Kind.CREATE_STRUCT); + assertThat(expr.exprKind().getKind()).isEqualTo(Kind.STRUCT); assertThat(expr.createStruct().messageName()).isEqualTo("google.example.Baz"); assertThat(expr.createStruct().entries()).containsExactly(field); } diff --git a/parser/src/test/java/dev/cel/parser/CelUnparserImplTest.java b/parser/src/test/java/dev/cel/parser/CelUnparserImplTest.java index 86fb279c0..321db78ef 100644 --- a/parser/src/test/java/dev/cel/parser/CelUnparserImplTest.java +++ b/parser/src/test/java/dev/cel/parser/CelUnparserImplTest.java @@ -26,8 +26,8 @@ import dev.cel.common.CelSource; import dev.cel.common.ast.CelExpr; import dev.cel.common.ast.CelExpr.CelCall; -import dev.cel.common.ast.CelExpr.CelCreateMap; -import dev.cel.common.ast.CelExpr.CelCreateStruct; +import dev.cel.common.ast.CelExpr.CelMap; +import dev.cel.common.ast.CelExpr.CelStruct; import dev.cel.extensions.CelOptionalLibrary; import java.util.Arrays; import java.util.List; @@ -197,10 +197,10 @@ public List provideValues(Context context) { .build(), // bad args CelExpr.newBuilder() .setCreateStruct( - CelCreateStruct.newBuilder() + CelStruct.newBuilder() .setMessageName("Msg") .addEntries( - CelCreateStruct.Entry.newBuilder() + CelStruct.Entry.newBuilder() .setId(0) .setValue(CelExpr.newBuilder().build()) .setFieldKey("field") @@ -209,9 +209,9 @@ public List provideValues(Context context) { .build(), // bad struct CelExpr.newBuilder() .setCreateMap( - CelCreateMap.newBuilder() + CelMap.newBuilder() .addEntries( - CelCreateMap.Entry.newBuilder() + CelMap.Entry.newBuilder() .setId(0) .setValue(CelExpr.newBuilder().build()) .setKey(CelExpr.newBuilder().build()) diff --git a/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java b/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java index 0579887e9..b535028b0 100644 --- a/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java +++ b/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java @@ -30,10 +30,10 @@ import dev.cel.common.ast.CelExpr; import dev.cel.common.ast.CelExpr.CelCall; import dev.cel.common.ast.CelExpr.CelComprehension; -import dev.cel.common.ast.CelExpr.CelCreateList; -import dev.cel.common.ast.CelExpr.CelCreateMap; -import dev.cel.common.ast.CelExpr.CelCreateStruct; +import dev.cel.common.ast.CelExpr.CelList; +import dev.cel.common.ast.CelExpr.CelMap; import dev.cel.common.ast.CelExpr.CelSelect; +import dev.cel.common.ast.CelExpr.CelStruct; import dev.cel.common.ast.CelExpr.ExprKind; import dev.cel.common.ast.CelReference; import dev.cel.common.types.CelKind; @@ -201,13 +201,13 @@ private IntermediateResult evalInternal(ExecutionFrame frame, CelExpr expr) case CALL: result = evalCall(frame, expr, expr.call()); break; - case CREATE_LIST: + case LIST: result = evalList(frame, expr, expr.createList()); break; - case CREATE_STRUCT: + case STRUCT: result = evalStruct(frame, expr, expr.createStruct()); break; - case CREATE_MAP: + case MAP: result = evalMap(frame, expr.createMap()); break; case COMPREHENSION: @@ -709,8 +709,7 @@ private IntermediateResult evalBooleanNonstrict(ExecutionFrame frame, CelExpr ex return evalBoolean(frame, expr, /* strict= */ false); } - private IntermediateResult evalList( - ExecutionFrame frame, CelExpr unusedExpr, CelCreateList listExpr) + private IntermediateResult evalList(ExecutionFrame frame, CelExpr unusedExpr, CelList listExpr) throws InterpreterException { CallArgumentChecker argChecker = CallArgumentChecker.create(frame.getResolver()); @@ -742,14 +741,14 @@ private IntermediateResult evalList( return IntermediateResult.create(argChecker.maybeUnknowns().orElse(result)); } - private IntermediateResult evalMap(ExecutionFrame frame, CelCreateMap mapExpr) + private IntermediateResult evalMap(ExecutionFrame frame, CelMap mapExpr) throws InterpreterException { CallArgumentChecker argChecker = CallArgumentChecker.create(frame.getResolver()); Map result = new LinkedHashMap<>(); - for (CelCreateMap.Entry entry : mapExpr.entries()) { + for (CelMap.Entry entry : mapExpr.entries()) { IntermediateResult keyResult = evalInternal(frame, entry.key()); argChecker.checkArg(keyResult); @@ -784,21 +783,20 @@ private IntermediateResult evalMap(ExecutionFrame frame, CelCreateMap mapExpr) return IntermediateResult.create(argChecker.maybeUnknowns().orElse(result)); } - private IntermediateResult evalStruct( - ExecutionFrame frame, CelExpr expr, CelCreateStruct structExpr) + private IntermediateResult evalStruct(ExecutionFrame frame, CelExpr expr, CelStruct structExpr) throws InterpreterException { CelReference reference = ast.getReference(expr.id()) .orElseThrow( () -> new IllegalStateException( - "Could not find a reference for CelCreateStruct expresison at ID: " + "Could not find a reference for CelStruct expresison at ID: " + expr.id())); // Message creation. CallArgumentChecker argChecker = CallArgumentChecker.create(frame.getResolver()); Map fields = new HashMap<>(); - for (CelCreateStruct.Entry entry : structExpr.entries()) { + for (CelStruct.Entry entry : structExpr.entries()) { IntermediateResult fieldResult = evalInternal(frame, entry.value()); // TODO: remove support for IncompleteData InterpreterUtil.completeDataOnly( @@ -903,7 +901,7 @@ private IntermediateResult evalComprehension( private IntermediateResult evalCelBlock( ExecutionFrame frame, CelExpr unusedExpr, CelCall blockCall) throws InterpreterException { - CelCreateList exprList = blockCall.args().get(0).createList(); + CelList exprList = blockCall.args().get(0).createList(); Map blockList = new HashMap<>(); for (int index = 0; index < exprList.elements().size(); index++) { // Register the block indices as lazily evaluated expressions stored as unique identifiers. @@ -935,7 +933,7 @@ private static boolean isLazilyEvaluable(CelComprehension comprehension) { .equals(CelConstant.Kind.BOOLEAN_VALUE) && !comprehension.loopCondition().constant().booleanValue() && comprehension.iterVar().equals("#unused") - && comprehension.iterRange().exprKind().getKind().equals(ExprKind.Kind.CREATE_LIST) + && comprehension.iterRange().exprKind().getKind().equals(ExprKind.Kind.LIST) && comprehension.iterRange().createList().elements().isEmpty(); } diff --git a/runtime/src/test/java/dev/cel/runtime/CelRuntimeTest.java b/runtime/src/test/java/dev/cel/runtime/CelRuntimeTest.java index 8e065ea13..f66690912 100644 --- a/runtime/src/test/java/dev/cel/runtime/CelRuntimeTest.java +++ b/runtime/src/test/java/dev/cel/runtime/CelRuntimeTest.java @@ -312,7 +312,7 @@ public void trace_createStruct() throws Exception { public void trace_createList() throws Exception { CelEvaluationListener listener = (expr, res) -> { - if (expr.exprKind().getKind().equals(Kind.CREATE_LIST)) { + if (expr.exprKind().getKind().equals(Kind.LIST)) { assertThat((List) res).containsExactly(1L, 2L, 3L); assertThat(expr.createList().elements()).hasSize(3); } @@ -330,7 +330,7 @@ public void trace_createList() throws Exception { public void trace_createMap() throws Exception { CelEvaluationListener listener = (expr, res) -> { - if (expr.exprKind().getKind().equals(Kind.CREATE_MAP)) { + if (expr.exprKind().getKind().equals(Kind.MAP)) { assertThat((Map) res).containsExactly(1L, "a"); assertThat(expr.createMap().entries()).hasSize(1); } diff --git a/validator/src/main/java/dev/cel/validator/validators/HomogeneousLiteralValidator.java b/validator/src/main/java/dev/cel/validator/validators/HomogeneousLiteralValidator.java index 45ada6ca3..b47251ccf 100644 --- a/validator/src/main/java/dev/cel/validator/validators/HomogeneousLiteralValidator.java +++ b/validator/src/main/java/dev/cel/validator/validators/HomogeneousLiteralValidator.java @@ -19,7 +19,7 @@ import dev.cel.bundle.Cel; import dev.cel.common.CelAbstractSyntaxTree; import dev.cel.common.ast.CelExpr; -import dev.cel.common.ast.CelExpr.CelCreateMap; +import dev.cel.common.ast.CelExpr.CelMap; import dev.cel.common.ast.CelExpr.ExprKind.Kind; import dev.cel.common.navigation.CelNavigableAst; import dev.cel.common.navigation.CelNavigableExpr; @@ -58,16 +58,14 @@ public void validate(CelNavigableAst navigableAst, Cel cel, IssuesFactory issues navigableAst .getRoot() .allNodes() - .filter( - node -> - node.getKind().equals(Kind.CREATE_LIST) || node.getKind().equals(Kind.CREATE_MAP)) + .filter(node -> node.getKind().equals(Kind.LIST) || node.getKind().equals(Kind.MAP)) .filter(node -> !isExemptFunction(node)) .map(CelNavigableExpr::expr) .forEach( expr -> { - if (expr.exprKind().getKind().equals(Kind.CREATE_LIST)) { + if (expr.exprKind().getKind().equals(Kind.LIST)) { validateList(navigableAst.getAst(), issuesFactory, expr); - } else if (expr.exprKind().getKind().equals(Kind.CREATE_MAP)) { + } else if (expr.exprKind().getKind().equals(Kind.MAP)) { validateMap(navigableAst.getAst(), issuesFactory, expr); } }); @@ -96,7 +94,7 @@ private void validateList(CelAbstractSyntaxTree ast, IssuesFactory issuesFactory private void validateMap(CelAbstractSyntaxTree ast, IssuesFactory issuesFactory, CelExpr expr) { CelType previousKeyType = null; CelType previousValueType = null; - for (CelCreateMap.Entry entry : expr.createMap().entries()) { + for (CelMap.Entry entry : expr.createMap().entries()) { CelType currentKeyType = ast.getType(entry.key().id()).get(); CelType currentValueType = ast.getType(entry.value().id()).get(); if (entry.optionalEntry()) { From e22ff8587f0faec8a339477b88e63a7c2db8007c Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Tue, 30 Apr 2024 10:59:35 -0700 Subject: [PATCH 103/486] Remove modifier create from mutable variants of list, map and struct PiperOrigin-RevId: 629466314 --- .../dev/cel/common/ast/CelMutableExpr.java | 112 +++++++------- .../common/ast/CelMutableExprConverter.java | 39 +++-- .../ast/CelMutableExprConverterTest.java | 30 ++-- .../cel/common/ast/CelMutableExprTest.java | 142 +++++++++--------- .../CelNavigableMutableExprTest.java | 14 +- .../java/dev/cel/optimizer/AstMutator.java | 6 +- .../dev/cel/optimizer/MutableExprVisitor.java | 20 +-- .../optimizers/ConstantFoldingOptimizer.java | 38 +++-- .../dev/cel/optimizer/AstMutatorTest.java | 5 +- 9 files changed, 196 insertions(+), 210 deletions(-) diff --git a/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java b/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java index 4e7990179..fd4eebaee 100644 --- a/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java +++ b/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java @@ -86,21 +86,21 @@ public CelMutableCall call() { } @Override - public CelMutableCreateList createList() { + public CelMutableList createList() { checkExprKind(Kind.LIST); - return (CelMutableCreateList) exprValue; + return (CelMutableList) exprValue; } @Override - public CelMutableCreateStruct createStruct() { + public CelMutableStruct createStruct() { checkExprKind(Kind.STRUCT); - return (CelMutableCreateStruct) exprValue; + return (CelMutableStruct) exprValue; } @Override - public CelMutableCreateMap createMap() { + public CelMutableMap createMap() { checkExprKind(Kind.MAP); - return (CelMutableCreateMap) exprValue; + return (CelMutableMap) exprValue; } @Override @@ -129,17 +129,17 @@ public void setCall(CelMutableCall call) { this.exprValue = checkNotNull(call); } - public void setCreateList(CelMutableCreateList createList) { + public void setCreateList(CelMutableList createList) { this.exprKind = ExprKind.Kind.LIST; this.exprValue = checkNotNull(createList); } - public void setCreateStruct(CelMutableCreateStruct createStruct) { + public void setCreateStruct(CelMutableStruct createStruct) { this.exprKind = ExprKind.Kind.STRUCT; this.exprValue = checkNotNull(createStruct); } - public void setCreateMap(CelMutableCreateMap createMap) { + public void setCreateMap(CelMutableMap createMap) { this.exprKind = ExprKind.Kind.MAP; this.exprValue = checkNotNull(createMap); } @@ -386,7 +386,7 @@ private CelMutableCall(CelMutableExpr target, String function, List { + public static final class CelMutableList implements Expression.CreateList { private final List elements; private final List optionalIndices; @@ -410,8 +410,8 @@ public boolean equals(Object obj) { if (obj == this) { return true; } - if (obj instanceof CelMutableCreateList) { - CelMutableCreateList that = (CelMutableCreateList) obj; + if (obj instanceof CelMutableList) { + CelMutableList that = (CelMutableList) obj; return this.elements.equals(that.elements()) && this.optionalIndices.equals(that.optionalIndices()); } @@ -430,35 +430,34 @@ public int hashCode() { return h; } - private CelMutableCreateList deepCopy() { + private CelMutableList deepCopy() { return create(deepCopyList(elements), optionalIndices); } - public static CelMutableCreateList create(CelMutableExpr... elements) { + public static CelMutableList create(CelMutableExpr... elements) { return create(Arrays.asList(checkNotNull(elements))); } - public static CelMutableCreateList create(List elements) { + public static CelMutableList create(List elements) { return create(elements, new ArrayList<>()); } - public static CelMutableCreateList create( + public static CelMutableList create( List mutableExprList, List optionalIndices) { - return new CelMutableCreateList(mutableExprList, optionalIndices); + return new CelMutableList(mutableExprList, optionalIndices); } - private CelMutableCreateList( - List mutableExprList, List optionalIndices) { + private CelMutableList(List mutableExprList, List optionalIndices) { this.elements = new ArrayList<>(checkNotNull(mutableExprList)); this.optionalIndices = new ArrayList<>(checkNotNull(optionalIndices)); } } /** A mutable list creation expression. See {@link Expression.CreateStruct} */ - public static final class CelMutableCreateStruct - implements Expression.CreateStruct { + public static final class CelMutableStruct + implements Expression.CreateStruct { private String messageName = ""; - private List entries; + private List entries; @Override public String messageName() { @@ -470,15 +469,15 @@ public void setMessageName(String messageName) { } @Override - public List entries() { + public List entries() { return entries; } - public void setEntries(List entries) { + public void setEntries(List entries) { this.entries = checkNotNull(entries); } - public void setEntry(int index, CelMutableCreateStruct.Entry entry) { + public void setEntry(int index, CelMutableStruct.Entry entry) { checkArgument(index >= 0 && index < entries().size()); entries.set(index, checkNotNull(entry)); } @@ -581,8 +580,8 @@ public boolean equals(Object obj) { if (obj == this) { return true; } - if (obj instanceof CelMutableCreateStruct) { - CelMutableCreateStruct that = (CelMutableCreateStruct) obj; + if (obj instanceof CelMutableStruct) { + CelMutableStruct that = (CelMutableStruct) obj; return this.messageName.equals(that.messageName()) && this.entries.equals(that.entries()); } return false; @@ -598,41 +597,40 @@ public int hashCode() { return h; } - private CelMutableCreateStruct deepCopy() { - ArrayList copiedEntries = new ArrayList<>(); - for (CelMutableCreateStruct.Entry entry : entries) { + private CelMutableStruct deepCopy() { + ArrayList copiedEntries = new ArrayList<>(); + for (CelMutableStruct.Entry entry : entries) { copiedEntries.add(entry.deepCopy()); } return create(messageName, copiedEntries); } - public static CelMutableCreateStruct create( - String messageName, List entries) { - return new CelMutableCreateStruct(messageName, entries); + public static CelMutableStruct create( + String messageName, List entries) { + return new CelMutableStruct(messageName, entries); } - private CelMutableCreateStruct(String messageName, List entries) { + private CelMutableStruct(String messageName, List entries) { this.messageName = checkNotNull(messageName); this.entries = new ArrayList<>(checkNotNull(entries)); } } /** A mutable map creation expression. See {@link Expression.CreateMap} */ - public static final class CelMutableCreateMap - implements Expression.CreateMap { - private List entries; + public static final class CelMutableMap implements Expression.CreateMap { + private List entries; @Override - public List entries() { + public List entries() { return entries; } - public void setEntries(List entries) { + public void setEntries(List entries) { this.entries = checkNotNull(entries); } - public void setEntry(int index, CelMutableCreateMap.Entry entry) { + public void setEntry(int index, CelMutableMap.Entry entry) { checkArgument(index >= 0 && index < entries().size()); entries.set(index, checkNotNull(entry)); } @@ -739,8 +737,8 @@ public boolean equals(Object obj) { if (obj == this) { return true; } - if (obj instanceof CelMutableCreateMap) { - CelMutableCreateMap that = (CelMutableCreateMap) obj; + if (obj instanceof CelMutableMap) { + CelMutableMap that = (CelMutableMap) obj; return this.entries.equals(that.entries()); } return false; @@ -754,20 +752,20 @@ public int hashCode() { return h; } - private CelMutableCreateMap deepCopy() { - ArrayList copiedEntries = new ArrayList<>(); - for (CelMutableCreateMap.Entry entry : entries) { + private CelMutableMap deepCopy() { + ArrayList copiedEntries = new ArrayList<>(); + for (CelMutableMap.Entry entry : entries) { copiedEntries.add(entry.deepCopy()); } return create(copiedEntries); } - public static CelMutableCreateMap create(List entries) { - return new CelMutableCreateMap(new ArrayList<>(entries)); + public static CelMutableMap create(List entries) { + return new CelMutableMap(new ArrayList<>(entries)); } - private CelMutableCreateMap(List entries) { + private CelMutableMap(List entries) { this.entries = checkNotNull(entries); } } @@ -975,27 +973,27 @@ public static CelMutableExpr ofCall(long id, CelMutableCall mutableCall) { return new CelMutableExpr(id, mutableCall); } - public static CelMutableExpr ofCreateList(CelMutableCreateList mutableCreateList) { + public static CelMutableExpr ofCreateList(CelMutableList mutableCreateList) { return ofCreateList(0, mutableCreateList); } - public static CelMutableExpr ofCreateList(long id, CelMutableCreateList mutableCreateList) { + public static CelMutableExpr ofCreateList(long id, CelMutableList mutableCreateList) { return new CelMutableExpr(id, mutableCreateList); } - public static CelMutableExpr ofCreateStruct(CelMutableCreateStruct mutableCreateStruct) { + public static CelMutableExpr ofCreateStruct(CelMutableStruct mutableCreateStruct) { return ofCreateStruct(0, mutableCreateStruct); } - public static CelMutableExpr ofCreateStruct(long id, CelMutableCreateStruct mutableCreateStruct) { + public static CelMutableExpr ofCreateStruct(long id, CelMutableStruct mutableCreateStruct) { return new CelMutableExpr(id, mutableCreateStruct); } - public static CelMutableExpr ofCreateMap(CelMutableCreateMap mutableCreateMap) { + public static CelMutableExpr ofCreateMap(CelMutableMap mutableCreateMap) { return ofCreateMap(0, mutableCreateMap); } - public static CelMutableExpr ofCreateMap(long id, CelMutableCreateMap mutableCreateMap) { + public static CelMutableExpr ofCreateMap(long id, CelMutableMap mutableCreateMap) { return new CelMutableExpr(id, mutableCreateMap); } @@ -1029,17 +1027,17 @@ private CelMutableExpr(long id, CelMutableCall mutableCall) { setCall(mutableCall); } - private CelMutableExpr(long id, CelMutableCreateList mutableCreateList) { + private CelMutableExpr(long id, CelMutableList mutableCreateList) { this.id = id; setCreateList(mutableCreateList); } - private CelMutableExpr(long id, CelMutableCreateStruct mutableCreateStruct) { + private CelMutableExpr(long id, CelMutableStruct mutableCreateStruct) { this.id = id; setCreateStruct(mutableCreateStruct); } - private CelMutableExpr(long id, CelMutableCreateMap mutableCreateMap) { + private CelMutableExpr(long id, CelMutableMap mutableCreateMap) { this.id = id; setCreateMap(mutableCreateMap); } diff --git a/common/src/main/java/dev/cel/common/ast/CelMutableExprConverter.java b/common/src/main/java/dev/cel/common/ast/CelMutableExprConverter.java index cf5fc6b94..a7c51342d 100644 --- a/common/src/main/java/dev/cel/common/ast/CelMutableExprConverter.java +++ b/common/src/main/java/dev/cel/common/ast/CelMutableExprConverter.java @@ -26,10 +26,10 @@ import dev.cel.common.ast.CelExpr.CelStruct; import dev.cel.common.ast.CelMutableExpr.CelMutableCall; import dev.cel.common.ast.CelMutableExpr.CelMutableComprehension; -import dev.cel.common.ast.CelMutableExpr.CelMutableCreateList; -import dev.cel.common.ast.CelMutableExpr.CelMutableCreateMap; -import dev.cel.common.ast.CelMutableExpr.CelMutableCreateStruct; +import dev.cel.common.ast.CelMutableExpr.CelMutableList; +import dev.cel.common.ast.CelMutableExpr.CelMutableMap; import dev.cel.common.ast.CelMutableExpr.CelMutableSelect; +import dev.cel.common.ast.CelMutableExpr.CelMutableStruct; import java.util.ArrayList; import java.util.List; import java.util.Optional; @@ -69,7 +69,7 @@ public static CelMutableExpr fromCelExpr(CelExpr celExpr) { CelList createList = celExpr.createList(); return CelMutableExpr.ofCreateList( celExpr.id(), - CelMutableCreateList.create( + CelMutableList.create( fromCelExprList(createList.elements()), createList.optionalIndices())); case STRUCT: return CelMutableExpr.ofCreateStruct( @@ -105,32 +105,32 @@ private static List fromCelExprList(Iterable celExprLis return mutableExprList; } - private static CelMutableCreateStruct fromCelStructToMutableStruct(CelStruct celCreateStruct) { - List entries = new ArrayList<>(); + private static CelMutableStruct fromCelStructToMutableStruct(CelStruct celCreateStruct) { + List entries = new ArrayList<>(); for (CelStruct.Entry celStructExprEntry : celCreateStruct.entries()) { entries.add( - CelMutableCreateStruct.Entry.create( + CelMutableStruct.Entry.create( celStructExprEntry.id(), celStructExprEntry.fieldKey(), fromCelExpr(celStructExprEntry.value()), celStructExprEntry.optionalEntry())); } - return CelMutableCreateStruct.create(celCreateStruct.messageName(), entries); + return CelMutableStruct.create(celCreateStruct.messageName(), entries); } - private static CelMutableCreateMap fromCelMapToMutableMap(CelMap celCreateMap) { - List entries = new ArrayList<>(); + private static CelMutableMap fromCelMapToMutableMap(CelMap celCreateMap) { + List entries = new ArrayList<>(); for (CelMap.Entry celMapExprEntry : celCreateMap.entries()) { entries.add( - CelMutableCreateMap.Entry.create( + CelMutableMap.Entry.create( celMapExprEntry.id(), fromCelExpr(celMapExprEntry.key()), fromCelExpr(celMapExprEntry.value()), celMapExprEntry.optionalEntry())); } - return CelMutableCreateMap.create(entries); + return CelMutableMap.create(entries); } public static CelExpr fromMutableExpr(CelMutableExpr mutableExpr) { @@ -154,19 +154,19 @@ public static CelExpr fromMutableExpr(CelMutableExpr mutableExpr) { mutableCall.target().map(CelMutableExprConverter::fromMutableExpr); return CelExpr.ofCall(id, targetExpr, mutableCall.function(), args); case LIST: - CelMutableCreateList mutableCreateList = mutableExpr.createList(); + CelMutableList mutableCreateList = mutableExpr.createList(); return CelExpr.ofCreateList( id, fromMutableExprList(mutableCreateList.elements()), ImmutableList.copyOf(mutableCreateList.optionalIndices())); case STRUCT: - CelMutableCreateStruct mutableCreateStruct = mutableExpr.createStruct(); + CelMutableStruct mutableCreateStruct = mutableExpr.createStruct(); return CelExpr.newBuilder() .setId(id) .setCreateStruct(fromMutableStructToCelStruct(mutableCreateStruct)) .build(); case MAP: - CelMutableCreateMap mutableCreateMap = mutableExpr.createMap(); + CelMutableMap mutableCreateMap = mutableExpr.createMap(); return CelExpr.newBuilder() .setId(id) .setCreateMap(fromMutableMapToCelMap(mutableCreateMap)) @@ -198,10 +198,9 @@ private static ImmutableList fromMutableExprList( return celExprList.build(); } - private static CelStruct fromMutableStructToCelStruct( - CelMutableCreateStruct mutableCreateStruct) { + private static CelStruct fromMutableStructToCelStruct(CelMutableStruct mutableCreateStruct) { List entries = new ArrayList<>(); - for (CelMutableCreateStruct.Entry mutableStructEntry : mutableCreateStruct.entries()) { + for (CelMutableStruct.Entry mutableStructEntry : mutableCreateStruct.entries()) { entries.add( CelExpr.ofCreateStructEntry( mutableStructEntry.id(), @@ -216,9 +215,9 @@ private static CelStruct fromMutableStructToCelStruct( .build(); } - private static CelMap fromMutableMapToCelMap(CelMutableCreateMap mutableCreateMap) { + private static CelMap fromMutableMapToCelMap(CelMutableMap mutableCreateMap) { List entries = new ArrayList<>(); - for (CelMutableCreateMap.Entry mutableMapEntry : mutableCreateMap.entries()) { + for (CelMutableMap.Entry mutableMapEntry : mutableCreateMap.entries()) { entries.add( CelExpr.ofCreateMapEntry( mutableMapEntry.id(), diff --git a/common/src/test/java/dev/cel/common/ast/CelMutableExprConverterTest.java b/common/src/test/java/dev/cel/common/ast/CelMutableExprConverterTest.java index 2d0419bd4..927c10243 100644 --- a/common/src/test/java/dev/cel/common/ast/CelMutableExprConverterTest.java +++ b/common/src/test/java/dev/cel/common/ast/CelMutableExprConverterTest.java @@ -27,10 +27,10 @@ import dev.cel.common.ast.CelExpr.CelStruct; import dev.cel.common.ast.CelMutableExpr.CelMutableCall; import dev.cel.common.ast.CelMutableExpr.CelMutableComprehension; -import dev.cel.common.ast.CelMutableExpr.CelMutableCreateList; -import dev.cel.common.ast.CelMutableExpr.CelMutableCreateMap; -import dev.cel.common.ast.CelMutableExpr.CelMutableCreateStruct; +import dev.cel.common.ast.CelMutableExpr.CelMutableList; +import dev.cel.common.ast.CelMutableExpr.CelMutableMap; import dev.cel.common.ast.CelMutableExpr.CelMutableSelect; +import dev.cel.common.ast.CelMutableExpr.CelMutableStruct; import org.junit.Test; import org.junit.runner.RunWith; @@ -203,7 +203,7 @@ public void convertMutableCreateList_toCelList() { CelMutableExpr mutableExpr = CelMutableExpr.ofCreateList( 1L, - CelMutableCreateList.create( + CelMutableList.create( ImmutableList.of( CelMutableExpr.ofConstant(2L, CelConstant.ofValue("element1")), CelMutableExpr.ofConstant(3L, CelConstant.ofValue("element2"))), @@ -237,7 +237,7 @@ public void convertCelList_toMutableCreateList() { .isEqualTo( CelMutableExpr.ofCreateList( 1L, - CelMutableCreateList.create( + CelMutableList.create( ImmutableList.of( CelMutableExpr.ofConstant(2L, CelConstant.ofValue("element1")), CelMutableExpr.ofConstant(3L, CelConstant.ofValue("element2"))), @@ -249,10 +249,10 @@ public void convertMutableCreateStruct_toCelStruct() { CelMutableExpr mutableExpr = CelMutableExpr.ofCreateStruct( 8L, - CelMutableCreateStruct.create( + CelMutableStruct.create( "message", ImmutableList.of( - CelMutableCreateStruct.Entry.create( + CelMutableStruct.Entry.create( 9L, "field", CelMutableExpr.ofConstant(10L, CelConstant.ofValue("value")), @@ -294,10 +294,10 @@ public void convertCelStruct_toMutableCreateStruct() { .isEqualTo( CelMutableExpr.ofCreateStruct( 8L, - CelMutableCreateStruct.create( + CelMutableStruct.create( "message", ImmutableList.of( - CelMutableCreateStruct.Entry.create( + CelMutableStruct.Entry.create( 9L, "field", CelMutableExpr.ofConstant(10L, CelConstant.ofValue("value")), @@ -309,9 +309,9 @@ public void convertMutableCreateMap_toCelMap() { CelMutableExpr mutableExpr = CelMutableExpr.ofCreateMap( 9L, - CelMutableCreateMap.create( + CelMutableMap.create( ImmutableList.of( - CelMutableCreateMap.Entry.create( + CelMutableMap.Entry.create( 10L, CelMutableExpr.ofConstant(11L, CelConstant.ofValue("key")), CelMutableExpr.ofConstant(12L, CelConstant.ofValue("value")), @@ -349,9 +349,9 @@ public void convertCelMap_toMutableCreateMap() { .isEqualTo( CelMutableExpr.ofCreateMap( 9L, - CelMutableCreateMap.create( + CelMutableMap.create( ImmutableList.of( - CelMutableCreateMap.Entry.create( + CelMutableMap.Entry.create( 10L, CelMutableExpr.ofConstant(11L, CelConstant.ofValue("key")), CelMutableExpr.ofConstant(12L, CelConstant.ofValue("value")), @@ -367,7 +367,7 @@ public void convertMutableComprehension_toCelComprehension() { "iterVar", CelMutableExpr.ofCreateList( 2L, - CelMutableCreateList.create( + CelMutableList.create( CelMutableExpr.ofConstant(3L, CelConstant.ofValue(true)))), "accuVar", CelMutableExpr.ofConstant(4L, CelConstant.ofValue(true)), @@ -425,7 +425,7 @@ public void convertCelComprehension_toMutableComprehension() { "iterVar", CelMutableExpr.ofCreateList( 2L, - CelMutableCreateList.create( + CelMutableList.create( CelMutableExpr.ofConstant(3L, CelConstant.ofValue(true)))), "accuVar", CelMutableExpr.ofConstant(4L, CelConstant.ofValue(true)), diff --git a/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java b/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java index 22f60fa04..620fe2e8b 100644 --- a/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java +++ b/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java @@ -25,11 +25,11 @@ import dev.cel.common.ast.CelExpr.ExprKind.Kind; import dev.cel.common.ast.CelMutableExpr.CelMutableCall; import dev.cel.common.ast.CelMutableExpr.CelMutableComprehension; -import dev.cel.common.ast.CelMutableExpr.CelMutableCreateList; -import dev.cel.common.ast.CelMutableExpr.CelMutableCreateMap; -import dev.cel.common.ast.CelMutableExpr.CelMutableCreateStruct; import dev.cel.common.ast.CelMutableExpr.CelMutableIdent; +import dev.cel.common.ast.CelMutableExpr.CelMutableList; +import dev.cel.common.ast.CelMutableExpr.CelMutableMap; import dev.cel.common.ast.CelMutableExpr.CelMutableSelect; +import dev.cel.common.ast.CelMutableExpr.CelMutableStruct; import java.util.ArrayList; import org.junit.Test; import org.junit.runner.RunWith; @@ -317,7 +317,7 @@ public void mutableCall_setFunction() { public void ofCreateList() { CelMutableExpr mutableExpr = CelMutableExpr.ofCreateList( - CelMutableCreateList.create( + CelMutableList.create( CelMutableExpr.ofConstant(CelConstant.ofValue("element1")), CelMutableExpr.ofConstant(CelConstant.ofValue("element2")))); @@ -335,7 +335,7 @@ public void ofCreateList_withId() { CelMutableExpr mutableExpr = CelMutableExpr.ofCreateList( 1L, - CelMutableCreateList.create( + CelMutableList.create( ImmutableList.of( CelMutableExpr.ofConstant(CelConstant.ofValue("element1")), CelMutableExpr.ofConstant(CelConstant.ofValue("element2"))), @@ -352,8 +352,8 @@ public void ofCreateList_withId() { @Test public void mutableCreateList_setElementAtIndex() { - CelMutableCreateList createList = - CelMutableCreateList.create(CelMutableExpr.ofConstant(CelConstant.ofValue("element1"))); + CelMutableList createList = + CelMutableList.create(CelMutableExpr.ofConstant(CelConstant.ofValue("element1"))); createList.setElement(0, CelMutableExpr.ofConstant(CelConstant.ofValue("hello"))); @@ -367,7 +367,7 @@ public void mutableCreateList_setElementAtIndex() { public void mutableCreateList_deepCopy() { CelMutableExpr mutableExpr = CelMutableExpr.ofCreateList( - CelMutableCreateList.create( + CelMutableList.create( CelMutableExpr.ofConstant(CelConstant.ofValue("element1")), CelMutableExpr.ofConstant(CelConstant.ofValue("element2")))); @@ -388,7 +388,7 @@ public void mutableCreateList_deepCopy() { @Test public void ofCreateStruct() { CelMutableExpr mutableExpr = - CelMutableExpr.ofCreateStruct(CelMutableCreateStruct.create("message", ImmutableList.of())); + CelMutableExpr.ofCreateStruct(CelMutableStruct.create("message", ImmutableList.of())); assertThat(mutableExpr.id()).isEqualTo(0L); assertThat(mutableExpr.createStruct().messageName()).isEqualTo("message"); @@ -400,10 +400,10 @@ public void ofCreateStruct_withId() { CelMutableExpr mutableExpr = CelMutableExpr.ofCreateStruct( 8L, - CelMutableCreateStruct.create( + CelMutableStruct.create( "message", ImmutableList.of( - CelMutableCreateStruct.Entry.create( + CelMutableStruct.Entry.create( 9L, "field", CelMutableExpr.ofConstant(CelConstant.ofValue("value")), @@ -413,7 +413,7 @@ public void ofCreateStruct_withId() { assertThat(mutableExpr.createStruct().messageName()).isEqualTo("message"); assertThat(mutableExpr.createStruct().entries()) .containsExactly( - CelMutableCreateStruct.Entry.create( + CelMutableStruct.Entry.create( 9L, "field", CelMutableExpr.ofConstant(CelConstant.ofValue("value")), @@ -422,14 +422,14 @@ public void ofCreateStruct_withId() { @Test public void mutableCreateStruct_setEntryAtIndex() { - CelMutableCreateStruct createStruct = - CelMutableCreateStruct.create( + CelMutableStruct createStruct = + CelMutableStruct.create( "message", ImmutableList.of( - CelMutableCreateStruct.Entry.create( + CelMutableStruct.Entry.create( 1L, "field", CelMutableExpr.ofConstant(CelConstant.ofValue("value"))))); - CelMutableCreateStruct.Entry newEntry = - CelMutableCreateStruct.Entry.create( + CelMutableStruct.Entry newEntry = + CelMutableStruct.Entry.create( 2L, "field2", CelMutableExpr.ofConstant(CelConstant.ofValue("value2")), @@ -442,8 +442,8 @@ public void mutableCreateStruct_setEntryAtIndex() { @Test public void mutableCreateStructEntry_setters() { - CelMutableCreateStruct.Entry createStructEntry = - CelMutableCreateStruct.Entry.create( + CelMutableStruct.Entry createStructEntry = + CelMutableStruct.Entry.create( 1L, "field", CelMutableExpr.ofConstant(CelConstant.ofValue("value"))); createStructEntry.setId(2L); @@ -453,7 +453,7 @@ public void mutableCreateStructEntry_setters() { assertThat(createStructEntry) .isEqualTo( - CelMutableCreateStruct.Entry.create( + CelMutableStruct.Entry.create( 2L, "field2", CelMutableExpr.ofConstant(CelConstant.ofValue("value2")), true)); } @@ -463,10 +463,10 @@ public void mutableCreateStruct_deepCopy() { CelMutableExpr mutableExpr = CelMutableExpr.ofCreateStruct( 8L, - CelMutableCreateStruct.create( + CelMutableStruct.create( "message", ImmutableList.of( - CelMutableCreateStruct.Entry.create( + CelMutableStruct.Entry.create( 8L, "field", CelMutableExpr.ofConstant(CelConstant.ofValue("value")), @@ -482,7 +482,7 @@ public void mutableCreateStruct_deepCopy() { .isNotSameInstanceAs(deepCopiedExpr.createStruct().entries()); assertThat(mutableExpr.createStruct().entries()) .comparingElementsUsing( - Correspondence.from( + Correspondence.from( (e1, e2) -> e1 != e2 && e1.equals(e2) @@ -495,7 +495,7 @@ public void mutableCreateStruct_deepCopy() { @Test public void ofCreateMap() { CelMutableExpr mutableExpr = - CelMutableExpr.ofCreateMap(CelMutableCreateMap.create(ImmutableList.of())); + CelMutableExpr.ofCreateMap(CelMutableMap.create(ImmutableList.of())); assertThat(mutableExpr.id()).isEqualTo(0L); assertThat(mutableExpr.createMap().entries()).isEmpty(); @@ -506,9 +506,9 @@ public void ofCreateMap_withId() { CelMutableExpr mutableExpr = CelMutableExpr.ofCreateMap( 9L, - CelMutableCreateMap.create( + CelMutableMap.create( ImmutableList.of( - CelMutableCreateMap.Entry.create( + CelMutableMap.Entry.create( 10L, CelMutableExpr.ofConstant(CelConstant.ofValue("key")), CelMutableExpr.ofConstant(CelConstant.ofValue("value")), @@ -517,7 +517,7 @@ public void ofCreateMap_withId() { assertThat(mutableExpr.id()).isEqualTo(9L); assertThat(mutableExpr.createMap().entries()) .containsExactly( - CelMutableCreateMap.Entry.create( + CelMutableMap.Entry.create( 10L, CelMutableExpr.ofConstant(CelConstant.ofValue("key")), CelMutableExpr.ofConstant(CelConstant.ofValue("value")), @@ -526,15 +526,15 @@ public void ofCreateMap_withId() { @Test public void mutableCreateMap_setEntryAtIndex() { - CelMutableCreateMap createMap = - CelMutableCreateMap.create( + CelMutableMap createMap = + CelMutableMap.create( ImmutableList.of( - CelMutableCreateMap.Entry.create( + CelMutableMap.Entry.create( 10L, CelMutableExpr.ofConstant(CelConstant.ofValue("key")), CelMutableExpr.ofConstant(CelConstant.ofValue("value"))))); - CelMutableCreateMap.Entry newEntry = - CelMutableCreateMap.Entry.create( + CelMutableMap.Entry newEntry = + CelMutableMap.Entry.create( 2L, CelMutableExpr.ofConstant(CelConstant.ofValue("key2")), CelMutableExpr.ofConstant(CelConstant.ofValue("value2")), @@ -547,8 +547,8 @@ public void mutableCreateMap_setEntryAtIndex() { @Test public void mutableCreateMapEntry_setters() { - CelMutableCreateMap.Entry createMapEntry = - CelMutableCreateMap.Entry.create( + CelMutableMap.Entry createMapEntry = + CelMutableMap.Entry.create( 1L, CelMutableExpr.ofConstant(CelConstant.ofValue("key")), CelMutableExpr.ofConstant(CelConstant.ofValue("value"))); @@ -560,7 +560,7 @@ public void mutableCreateMapEntry_setters() { assertThat(createMapEntry) .isEqualTo( - CelMutableCreateMap.Entry.create( + CelMutableMap.Entry.create( 2L, CelMutableExpr.ofConstant(CelConstant.ofValue("key2")), CelMutableExpr.ofConstant(CelConstant.ofValue("value2")), @@ -573,9 +573,9 @@ public void mutableCreateMap_deepCopy() { CelMutableExpr mutableExpr = CelMutableExpr.ofCreateMap( 9L, - CelMutableCreateMap.create( + CelMutableMap.create( ImmutableList.of( - CelMutableCreateMap.Entry.create( + CelMutableMap.Entry.create( 10L, CelMutableExpr.ofConstant(CelConstant.ofValue("key")), CelMutableExpr.ofConstant(CelConstant.ofValue("value")), @@ -589,7 +589,7 @@ public void mutableCreateMap_deepCopy() { assertThat(mutableExpr.createMap()).isNotSameInstanceAs(deepCopiedExpr.createMap()); assertThat(mutableExpr.createMap().entries()) .comparingElementsUsing( - Correspondence.from( + Correspondence.from( (e1, e2) -> e1 != e2 && e1.equals(e2) @@ -609,8 +609,7 @@ public void ofComprehension_withId() { CelMutableComprehension.create( "iterVar", CelMutableExpr.ofCreateList( - CelMutableCreateList.create( - CelMutableExpr.ofConstant(CelConstant.ofValue(true)))), + CelMutableList.create(CelMutableExpr.ofConstant(CelConstant.ofValue(true)))), "accuVar", CelMutableExpr.ofConstant(CelConstant.ofValue(true)), CelMutableExpr.ofConstant(CelConstant.ofValue(true)), @@ -623,8 +622,7 @@ public void ofComprehension_withId() { CelMutableComprehension.create( "iterVar", CelMutableExpr.ofCreateList( - CelMutableCreateList.create( - CelMutableExpr.ofConstant(CelConstant.ofValue(true)))), + CelMutableList.create(CelMutableExpr.ofConstant(CelConstant.ofValue(true)))), "accuVar", CelMutableExpr.ofConstant(CelConstant.ofValue(true)), CelMutableExpr.ofConstant(CelConstant.ofValue(true)), @@ -648,7 +646,7 @@ public void mutableComprehension_setters() { mutableComprehension.setAccuVar("accuVar2"); mutableComprehension.setIterRange( CelMutableExpr.ofCreateList( - CelMutableCreateList.create(CelMutableExpr.ofConstant(CelConstant.ofValue(true))))); + CelMutableList.create(CelMutableExpr.ofConstant(CelConstant.ofValue(true))))); mutableComprehension.setAccuInit(CelMutableExpr.ofConstant(CelConstant.ofValue(true))); mutableComprehension.setLoopCondition(CelMutableExpr.ofConstant(CelConstant.ofValue(true))); mutableComprehension.setLoopStep(CelMutableExpr.ofConstant(CelConstant.ofValue(true))); @@ -659,8 +657,7 @@ public void mutableComprehension_setters() { CelMutableComprehension.create( "iterVar2", CelMutableExpr.ofCreateList( - CelMutableCreateList.create( - CelMutableExpr.ofConstant(CelConstant.ofValue(true)))), + CelMutableList.create(CelMutableExpr.ofConstant(CelConstant.ofValue(true)))), "accuVar2", CelMutableExpr.ofConstant(CelConstant.ofValue(true)), CelMutableExpr.ofConstant(CelConstant.ofValue(true)), @@ -676,8 +673,7 @@ public void mutableComprehension_deepCopy() { CelMutableComprehension.create( "iterVar", CelMutableExpr.ofCreateList( - CelMutableCreateList.create( - CelMutableExpr.ofConstant(CelConstant.ofValue(true)))), + CelMutableList.create(CelMutableExpr.ofConstant(CelConstant.ofValue(true)))), "accuVar", CelMutableExpr.ofConstant(CelConstant.ofValue(true)), CelMutableExpr.ofConstant(CelConstant.ofValue(true)), @@ -744,55 +740,53 @@ public void equalityTest() { CelMutableExpr.ofConstant(CelConstant.ofValue("target")), "function", CelMutableExpr.ofConstant(CelConstant.ofValue("arg"))))) - .addEqualityGroup(CelMutableExpr.ofCreateList(CelMutableCreateList.create())) + .addEqualityGroup(CelMutableExpr.ofCreateList(CelMutableList.create())) .addEqualityGroup( CelMutableExpr.ofCreateList( 6L, - CelMutableCreateList.create( + CelMutableList.create( CelMutableExpr.ofConstant(CelConstant.ofValue("element1")), CelMutableExpr.ofConstant(CelConstant.ofValue("element2")))), CelMutableExpr.ofCreateList( 6L, - CelMutableCreateList.create( + CelMutableList.create( CelMutableExpr.ofConstant(CelConstant.ofValue("element1")), CelMutableExpr.ofConstant(CelConstant.ofValue("element2"))))) .addEqualityGroup( - CelMutableExpr.ofCreateStruct( - CelMutableCreateStruct.create("message", ImmutableList.of()))) + CelMutableExpr.ofCreateStruct(CelMutableStruct.create("message", ImmutableList.of()))) .addEqualityGroup( CelMutableExpr.ofCreateStruct( 7L, - CelMutableCreateStruct.create( + CelMutableStruct.create( "message", ImmutableList.of( - CelMutableCreateStruct.Entry.create( + CelMutableStruct.Entry.create( 8L, "field", CelMutableExpr.ofConstant(CelConstant.ofValue("value")), /* optionalEntry= */ true)))), CelMutableExpr.ofCreateStruct( 7L, - CelMutableCreateStruct.create( + CelMutableStruct.create( "message", ImmutableList.of( - CelMutableCreateStruct.Entry.create( + CelMutableStruct.Entry.create( 8L, "field", CelMutableExpr.ofConstant(CelConstant.ofValue("value")), /* optionalEntry= */ true))))) + .addEqualityGroup(CelMutableExpr.ofCreateMap(CelMutableMap.create(ImmutableList.of()))) .addEqualityGroup( - CelMutableExpr.ofCreateMap(CelMutableCreateMap.create(ImmutableList.of()))) - .addEqualityGroup( - CelMutableCreateMap.create( + CelMutableMap.create( ImmutableList.of( - CelMutableCreateMap.Entry.create( + CelMutableMap.Entry.create( 9L, CelMutableExpr.ofConstant(CelConstant.ofValue("key")), CelMutableExpr.ofConstant(CelConstant.ofValue("value")), /* optionalEntry= */ true))), - CelMutableCreateMap.create( + CelMutableMap.create( ImmutableList.of( - CelMutableCreateMap.Entry.create( + CelMutableMap.Entry.create( 9L, CelMutableExpr.ofConstant(CelConstant.ofValue("key")), CelMutableExpr.ofConstant(CelConstant.ofValue("value")), @@ -814,7 +808,7 @@ public void equalityTest() { CelMutableComprehension.create( "iterVar", CelMutableExpr.ofCreateList( - CelMutableCreateList.create( + CelMutableList.create( CelMutableExpr.ofConstant(CelConstant.ofValue(true)))), "accuVar", CelMutableExpr.ofConstant(CelConstant.ofValue(true)), @@ -826,7 +820,7 @@ public void equalityTest() { CelMutableComprehension.create( "iterVar", CelMutableExpr.ofCreateList( - CelMutableCreateList.create( + CelMutableList.create( CelMutableExpr.ofConstant(CelConstant.ofValue(true)))), "accuVar", CelMutableExpr.ofConstant(CelConstant.ofValue(true)), @@ -843,11 +837,10 @@ private enum MutableExprKindTestCase { IDENT(CelMutableExpr.ofIdent("test")), SELECT(CelMutableExpr.ofSelect(CelMutableSelect.create(CelMutableExpr.ofNotSet(), "field"))), CALL(CelMutableExpr.ofCall(CelMutableCall.create("call"))), - CREATE_LIST(CelMutableExpr.ofCreateList(CelMutableCreateList.create())), + CREATE_LIST(CelMutableExpr.ofCreateList(CelMutableList.create())), CREATE_STRUCT( - CelMutableExpr.ofCreateStruct( - CelMutableCreateStruct.create("message", ImmutableList.of()))), - CREATE_MAP(CelMutableExpr.ofCreateMap(CelMutableCreateMap.create(ImmutableList.of()))), + CelMutableExpr.ofCreateStruct(CelMutableStruct.create("message", ImmutableList.of()))), + CREATE_MAP(CelMutableExpr.ofCreateMap(CelMutableMap.create(ImmutableList.of()))), COMPREHENSION( CelMutableExpr.ofComprehension( 10L, @@ -921,17 +914,17 @@ private enum HashCodeTestCase { CREATE_LIST( CelMutableExpr.ofCreateList( 6L, - CelMutableCreateList.create( + CelMutableList.create( CelMutableExpr.ofConstant(CelConstant.ofValue("element1")), CelMutableExpr.ofConstant(CelConstant.ofValue("element2")))), 165341403), CREATE_STRUCT( CelMutableExpr.ofCreateStruct( 7L, - CelMutableCreateStruct.create( + CelMutableStruct.create( "message", ImmutableList.of( - CelMutableCreateStruct.Entry.create( + CelMutableStruct.Entry.create( 8L, "field", CelMutableExpr.ofConstant(CelConstant.ofValue("value")), @@ -940,9 +933,9 @@ private enum HashCodeTestCase { CREATE_MAP( CelMutableExpr.ofCreateMap( 8L, - CelMutableCreateMap.create( + CelMutableMap.create( ImmutableList.of( - CelMutableCreateMap.Entry.create( + CelMutableMap.Entry.create( 9L, CelMutableExpr.ofConstant(CelConstant.ofValue("key")), CelMutableExpr.ofConstant(CelConstant.ofValue("value")), @@ -954,8 +947,7 @@ private enum HashCodeTestCase { CelMutableComprehension.create( "iterVar", CelMutableExpr.ofCreateList( - CelMutableCreateList.create( - CelMutableExpr.ofConstant(CelConstant.ofValue(true)))), + CelMutableList.create(CelMutableExpr.ofConstant(CelConstant.ofValue(true)))), "accuVar", CelMutableExpr.ofConstant(CelConstant.ofValue(true)), CelMutableExpr.ofConstant(CelConstant.ofValue(true)), diff --git a/common/src/test/java/dev/cel/common/navigation/CelNavigableMutableExprTest.java b/common/src/test/java/dev/cel/common/navigation/CelNavigableMutableExprTest.java index 7d6a9e0f7..a4e8d455a 100644 --- a/common/src/test/java/dev/cel/common/navigation/CelNavigableMutableExprTest.java +++ b/common/src/test/java/dev/cel/common/navigation/CelNavigableMutableExprTest.java @@ -21,7 +21,7 @@ import dev.cel.common.ast.CelConstant; import dev.cel.common.ast.CelExpr.ExprKind.Kind; import dev.cel.common.ast.CelMutableExpr; -import dev.cel.common.ast.CelMutableExpr.CelMutableCreateList; +import dev.cel.common.ast.CelMutableExpr.CelMutableList; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -81,10 +81,10 @@ public void allNodes_filteredConstants_returnsAllConstants() { CelNavigableMutableExpr mutableExpr = CelNavigableMutableExpr.fromExpr( CelMutableExpr.ofCreateList( - CelMutableCreateList.create( + CelMutableList.create( CelMutableExpr.ofConstant(CelConstant.ofValue("element1")), CelMutableExpr.ofCreateList( - CelMutableCreateList.create( + CelMutableList.create( CelMutableExpr.ofConstant(CelConstant.ofValue("element2"))))))); ImmutableList allNodes = @@ -106,10 +106,10 @@ public void descendants_filteredConstants_returnsAllConstants() { CelNavigableMutableExpr mutableExpr = CelNavigableMutableExpr.fromExpr( CelMutableExpr.ofCreateList( - CelMutableCreateList.create( + CelMutableList.create( CelMutableExpr.ofConstant(CelConstant.ofValue("element1")), CelMutableExpr.ofCreateList( - CelMutableCreateList.create( + CelMutableList.create( CelMutableExpr.ofConstant(CelConstant.ofValue("element2"))))))); ImmutableList allNodes = @@ -131,10 +131,10 @@ public void children_filteredConstants_returnsSingleConstant() { CelNavigableMutableExpr mutableExpr = CelNavigableMutableExpr.fromExpr( CelMutableExpr.ofCreateList( - CelMutableCreateList.create( + CelMutableList.create( CelMutableExpr.ofConstant(CelConstant.ofValue("element1")), CelMutableExpr.ofCreateList( - CelMutableCreateList.create( + CelMutableList.create( CelMutableExpr.ofConstant(CelConstant.ofValue("element2"))))))); ImmutableList allNodes = diff --git a/optimizer/src/main/java/dev/cel/optimizer/AstMutator.java b/optimizer/src/main/java/dev/cel/optimizer/AstMutator.java index 0dfc6a4dd..2159b14a8 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/AstMutator.java +++ b/optimizer/src/main/java/dev/cel/optimizer/AstMutator.java @@ -35,7 +35,7 @@ import dev.cel.common.ast.CelMutableExpr; import dev.cel.common.ast.CelMutableExpr.CelMutableCall; import dev.cel.common.ast.CelMutableExpr.CelMutableComprehension; -import dev.cel.common.ast.CelMutableExpr.CelMutableCreateList; +import dev.cel.common.ast.CelMutableExpr.CelMutableList; import dev.cel.common.navigation.CelNavigableMutableAst; import dev.cel.common.navigation.CelNavigableMutableExpr; import dev.cel.common.navigation.TraversalOrder; @@ -90,7 +90,7 @@ public CelMutableAst wrapAstWithNewCelBlock( ++maxId, CelMutableCall.create( celBlockFunction, - CelMutableExpr.ofCreateList(++maxId, CelMutableCreateList.create(subexpressions)), + CelMutableExpr.ofCreateList(++maxId, CelMutableList.create(subexpressions)), ast.expr())); return CelMutableAst.of(blockExpr, ast.source()); @@ -569,7 +569,7 @@ private CelMutableExpr newBindMacroExpr( comprehensionId, CelMutableComprehension.create( "#unused", - CelMutableExpr.ofCreateList(iterRangeId, CelMutableCreateList.create()), + CelMutableExpr.ofCreateList(iterRangeId, CelMutableList.create()), varName, varInit, CelMutableExpr.ofConstant(loopConditionId, CelConstant.ofValue(false)), diff --git a/optimizer/src/main/java/dev/cel/optimizer/MutableExprVisitor.java b/optimizer/src/main/java/dev/cel/optimizer/MutableExprVisitor.java index fd5cf4653..d9ecb70c9 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/MutableExprVisitor.java +++ b/optimizer/src/main/java/dev/cel/optimizer/MutableExprVisitor.java @@ -21,10 +21,10 @@ import dev.cel.common.ast.CelMutableExpr; import dev.cel.common.ast.CelMutableExpr.CelMutableCall; import dev.cel.common.ast.CelMutableExpr.CelMutableComprehension; -import dev.cel.common.ast.CelMutableExpr.CelMutableCreateList; -import dev.cel.common.ast.CelMutableExpr.CelMutableCreateMap; -import dev.cel.common.ast.CelMutableExpr.CelMutableCreateStruct; +import dev.cel.common.ast.CelMutableExpr.CelMutableList; +import dev.cel.common.ast.CelMutableExpr.CelMutableMap; import dev.cel.common.ast.CelMutableExpr.CelMutableSelect; +import dev.cel.common.ast.CelMutableExpr.CelMutableStruct; import java.util.List; /** @@ -107,9 +107,9 @@ private CelMutableExpr visit(CelMutableExpr expr, CelMutableCall call) { } @CanIgnoreReturnValue - private CelMutableExpr visit(CelMutableExpr expr, CelMutableCreateStruct createStruct) { - List entries = createStruct.entries(); - for (CelMutableCreateStruct.Entry entry : entries) { + private CelMutableExpr visit(CelMutableExpr expr, CelMutableStruct createStruct) { + List entries = createStruct.entries(); + for (CelMutableStruct.Entry entry : entries) { entry.setId(celExprIdGenerator.generate(entry.id())); entry.setValue(visit(entry.value())); } @@ -118,9 +118,9 @@ private CelMutableExpr visit(CelMutableExpr expr, CelMutableCreateStruct createS } @CanIgnoreReturnValue - private CelMutableExpr visit(CelMutableExpr expr, CelMutableCreateMap createMap) { - List entriesBuilders = createMap.entries(); - for (CelMutableCreateMap.Entry entry : entriesBuilders) { + private CelMutableExpr visit(CelMutableExpr expr, CelMutableMap createMap) { + List entriesBuilders = createMap.entries(); + for (CelMutableMap.Entry entry : entriesBuilders) { entry.setId(celExprIdGenerator.generate(entry.id())); entry.setKey(visit(entry.key())); entry.setValue(visit(entry.value())); @@ -130,7 +130,7 @@ private CelMutableExpr visit(CelMutableExpr expr, CelMutableCreateMap createMap) } @CanIgnoreReturnValue - private CelMutableExpr visit(CelMutableExpr expr, CelMutableCreateList createList) { + private CelMutableExpr visit(CelMutableExpr expr, CelMutableList createList) { List elementsBuilders = createList.elements(); for (int i = 0; i < elementsBuilders.size(); i++) { CelMutableExpr elem = elementsBuilders.get(i); diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java b/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java index 588f77405..bef87765b 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java @@ -27,9 +27,9 @@ import dev.cel.common.ast.CelExprUtil; import dev.cel.common.ast.CelMutableExpr; import dev.cel.common.ast.CelMutableExpr.CelMutableCall; -import dev.cel.common.ast.CelMutableExpr.CelMutableCreateList; -import dev.cel.common.ast.CelMutableExpr.CelMutableCreateMap; -import dev.cel.common.ast.CelMutableExpr.CelMutableCreateStruct; +import dev.cel.common.ast.CelMutableExpr.CelMutableList; +import dev.cel.common.ast.CelMutableExpr.CelMutableMap; +import dev.cel.common.ast.CelMutableExpr.CelMutableStruct; import dev.cel.common.ast.CelMutableExprConverter; import dev.cel.common.navigation.CelNavigableMutableAst; import dev.cel.common.navigation.CelNavigableMutableExpr; @@ -258,10 +258,10 @@ private Optional maybeAdaptEvaluatedResult(Object result) { listElements.add(adaptedExpr); } - return Optional.of(CelMutableExpr.ofCreateList(CelMutableCreateList.create(listElements))); + return Optional.of(CelMutableExpr.ofCreateList(CelMutableList.create(listElements))); } else if (result instanceof Map) { Map map = (Map) result; - List mapEntries = new ArrayList<>(); + List mapEntries = new ArrayList<>(); for (Entry entry : map.entrySet()) { CelMutableExpr adaptedKey = maybeAdaptEvaluatedResult(entry.getKey()).orElse(null); if (adaptedKey == null) { @@ -272,10 +272,10 @@ private Optional maybeAdaptEvaluatedResult(Object result) { return Optional.empty(); } - mapEntries.add(CelMutableCreateMap.Entry.create(adaptedKey, adaptedValue)); + mapEntries.add(CelMutableMap.Entry.create(adaptedKey, adaptedValue)); } - return Optional.of(CelMutableExpr.ofCreateMap(CelMutableCreateMap.create(mapEntries))); + return Optional.of(CelMutableExpr.ofCreateMap(CelMutableMap.create(mapEntries))); } // Evaluated result cannot be folded (e.g: unknowns) @@ -339,7 +339,7 @@ private Optional maybePruneBranches( return Optional.empty(); } - CelMutableCreateList haystack = callArg.createList(); + CelMutableList haystack = callArg.createList(); if (haystack.elements().isEmpty()) { return Optional.of( astMutator.replaceSubtree( @@ -438,7 +438,7 @@ private CelMutableAst pruneOptionalElements(CelMutableAst ast) { } private CelMutableAst pruneOptionalListElements(CelMutableAst mutableAst, CelMutableExpr expr) { - CelMutableCreateList createList = expr.createList(); + CelMutableList createList = expr.createList(); if (createList.optionalIndices().isEmpty()) { return mutableAst; } @@ -478,16 +478,15 @@ private CelMutableAst pruneOptionalListElements(CelMutableAst mutableAst, CelMut return astMutator.replaceSubtree( mutableAst, CelMutableExpr.ofCreateList( - CelMutableCreateList.create(updatedElemBuilder.build(), updatedIndicesBuilder.build())), + CelMutableList.create(updatedElemBuilder.build(), updatedIndicesBuilder.build())), expr.id()); } private CelMutableAst pruneOptionalMapElements(CelMutableAst ast, CelMutableExpr expr) { - CelMutableCreateMap createMap = expr.createMap(); - ImmutableList.Builder updatedEntryBuilder = - new ImmutableList.Builder<>(); + CelMutableMap createMap = expr.createMap(); + ImmutableList.Builder updatedEntryBuilder = new ImmutableList.Builder<>(); boolean modified = false; - for (CelMutableCreateMap.Entry entry : createMap.entries()) { + for (CelMutableMap.Entry entry : createMap.entries()) { CelMutableExpr key = entry.key(); Kind keyKind = key.getKind(); CelMutableExpr value = entry.value(); @@ -521,7 +520,7 @@ private CelMutableAst pruneOptionalMapElements(CelMutableAst ast, CelMutableExpr if (modified) { return astMutator.replaceSubtree( ast, - CelMutableExpr.ofCreateMap(CelMutableCreateMap.create(updatedEntryBuilder.build())), + CelMutableExpr.ofCreateMap(CelMutableMap.create(updatedEntryBuilder.build())), expr.id()); } @@ -529,11 +528,11 @@ private CelMutableAst pruneOptionalMapElements(CelMutableAst ast, CelMutableExpr } private CelMutableAst pruneOptionalStructElements(CelMutableAst ast, CelMutableExpr expr) { - CelMutableCreateStruct createStruct = expr.createStruct(); - ImmutableList.Builder updatedEntryBuilder = + CelMutableStruct createStruct = expr.createStruct(); + ImmutableList.Builder updatedEntryBuilder = new ImmutableList.Builder<>(); boolean modified = false; - for (CelMutableCreateStruct.Entry entry : createStruct.entries()) { + for (CelMutableStruct.Entry entry : createStruct.entries()) { CelMutableExpr value = entry.value(); Kind valueKind = value.getKind(); if (!entry.optionalEntry() || !valueKind.equals(Kind.CALL)) { @@ -565,8 +564,7 @@ private CelMutableAst pruneOptionalStructElements(CelMutableAst ast, CelMutableE return astMutator.replaceSubtree( ast, CelMutableExpr.ofCreateStruct( - CelMutableCreateStruct.create( - createStruct.messageName(), updatedEntryBuilder.build())), + CelMutableStruct.create(createStruct.messageName(), updatedEntryBuilder.build())), expr.id()); } diff --git a/optimizer/src/test/java/dev/cel/optimizer/AstMutatorTest.java b/optimizer/src/test/java/dev/cel/optimizer/AstMutatorTest.java index e199ea6e2..50c0cc388 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/AstMutatorTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/AstMutatorTest.java @@ -36,7 +36,7 @@ import dev.cel.common.ast.CelExpr.ExprKind.Kind; import dev.cel.common.ast.CelMutableExpr; import dev.cel.common.ast.CelMutableExpr.CelMutableCall; -import dev.cel.common.ast.CelMutableExpr.CelMutableCreateList; +import dev.cel.common.ast.CelMutableExpr.CelMutableList; import dev.cel.common.ast.CelMutableExpr.CelMutableSelect; import dev.cel.common.ast.CelMutableExprConverter; import dev.cel.common.navigation.CelNavigableAst; @@ -491,8 +491,7 @@ public void replaceSubtree_replaceExtraneousListCreatedByMacro_unparseSuccess() .replaceSubtree( mutableAst, CelMutableExpr.ofCreateList( - CelMutableCreateList.create( - CelMutableExpr.ofConstant(CelConstant.ofValue(2L)))), + CelMutableList.create(CelMutableExpr.ofConstant(CelConstant.ofValue(2L)))), 9L) .toParsedAst(); CelAbstractSyntaxTree mutatedAstWithConstant = From f5b49069e508a063951f7a84393f18f33190c884 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Tue, 30 Apr 2024 13:40:39 -0700 Subject: [PATCH 104/486] Remove modifier create from the common expression interface PiperOrigin-RevId: 629515551 --- .../main/java/dev/cel/common/ast/CelExpr.java | 25 ++++--- .../dev/cel/common/ast/CelMutableExpr.java | 71 ++++++++++--------- .../java/dev/cel/common/ast/Expression.java | 23 +++--- .../navigation/CelNavigableExprVisitor.java | 15 ++-- .../navigation/ExprPropertyCalculator.java | 18 ++--- 5 files changed, 75 insertions(+), 77 deletions(-) diff --git a/common/src/main/java/dev/cel/common/ast/CelExpr.java b/common/src/main/java/dev/cel/common/ast/CelExpr.java index d85348175..bac1410bf 100644 --- a/common/src/main/java/dev/cel/common/ast/CelExpr.java +++ b/common/src/main/java/dev/cel/common/ast/CelExpr.java @@ -27,7 +27,6 @@ import dev.cel.common.ast.CelExpr.ExprKind.Kind; import java.util.ArrayList; import java.util.Arrays; -import java.util.List; import java.util.Optional; /** @@ -508,7 +507,7 @@ public abstract static class CelCall implements Expression.Call { /** Builder for CelCall. */ @AutoValue.Builder public abstract static class Builder { - private List mutableArgs = new ArrayList<>(); + private java.util.List mutableArgs = new ArrayList<>(); // Not public. This only exists to make AutoValue.Builder work. abstract ImmutableList args(); @@ -588,10 +587,10 @@ public static Builder newBuilder() { } } - /** A list creation expression. See {@link Expression.CreateList} */ + /** A list creation expression. See {@link List} */ @AutoValue @Immutable - public abstract static class CelList implements Expression.CreateList { + public abstract static class CelList implements List { @Override public abstract ImmutableList elements(); @@ -601,7 +600,7 @@ public abstract static class CelList implements Expression.CreateList { /** Builder for CelList. */ @AutoValue.Builder public abstract static class Builder { - private List mutableElements = new ArrayList<>(); + private java.util.List mutableElements = new ArrayList<>(); // Not public. This only exists to make AutoValue.Builder work. abstract ImmutableList elements(); @@ -680,10 +679,10 @@ public static Builder newBuilder() { } } - /** A message creation expression. See {@link Expression.CreateStruct} */ + /** A message creation expression. See {@link Expression.Struct} */ @AutoValue @Immutable - public abstract static class CelStruct implements Expression.CreateStruct { + public abstract static class CelStruct implements Expression.Struct { @Override public abstract String messageName(); @@ -693,7 +692,7 @@ public abstract static class CelStruct implements Expression.CreateStruct mutableEntries = new ArrayList<>(); + private java.util.List mutableEntries = new ArrayList<>(); // Not public. This only exists to make AutoValue.Builder work. abstract ImmutableList entries(); @@ -761,7 +760,7 @@ public static Builder newBuilder() { /** Represents an entry of the struct */ @AutoValue @Immutable - public abstract static class Entry implements Expression.CreateStruct.Entry { + public abstract static class Entry implements Expression.Struct.Entry { @Override public abstract long id(); @@ -803,10 +802,10 @@ public static Builder newBuilder() { } } - /** A map creation expression. See {@link Expression.CreateMap} */ + /** A map creation expression. See {@link Expression.Map} */ @AutoValue @Immutable - public abstract static class CelMap implements Expression.CreateMap { + public abstract static class CelMap implements Expression.Map { /** The entries in the creation expression. */ @Override public abstract ImmutableList entries(); @@ -815,7 +814,7 @@ public abstract static class CelMap implements Expression.CreateMap mutableEntries = new ArrayList<>(); + private java.util.List mutableEntries = new ArrayList<>(); // Not public. This only exists to make AutoValue.Builder work. abstract ImmutableList entries(); @@ -880,7 +879,7 @@ public static Builder newBuilder() { /** Represents an entry of the map. */ @AutoValue @Immutable - public abstract static class Entry implements Expression.CreateMap.Entry { + public abstract static class Entry implements Expression.Map.Entry { @Override public abstract long id(); diff --git a/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java b/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java index fd4eebaee..1ea48d420 100644 --- a/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java +++ b/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java @@ -23,7 +23,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.List; import java.util.Optional; /** @@ -275,7 +274,7 @@ private CelMutableSelect(CelMutableExpr operand, String field, boolean testOnly) public static final class CelMutableCall implements Expression.Call { private Optional target; private String function; - private List args; + private java.util.List args; @Override public Optional target() { @@ -296,7 +295,7 @@ public void setFunction(String function) { } @Override - public List args() { + public java.util.List args() { return args; } @@ -349,7 +348,7 @@ public int hashCode() { } private CelMutableCall deepCopy() { - List copiedArgs = deepCopyList(args); + java.util.List copiedArgs = deepCopyList(args); return target().isPresent() ? create(newInstance(target.get()), function, copiedArgs) : create(function, copiedArgs); @@ -359,7 +358,7 @@ public static CelMutableCall create(String function, CelMutableExpr... args) { return create(function, Arrays.asList(checkNotNull(args))); } - public static CelMutableCall create(String function, List args) { + public static CelMutableCall create(String function, java.util.List args) { return new CelMutableCall(function, args); } @@ -369,29 +368,30 @@ public static CelMutableCall create( } public static CelMutableCall create( - CelMutableExpr target, String function, List args) { + CelMutableExpr target, String function, java.util.List args) { return new CelMutableCall(target, function, args); } - private CelMutableCall(String function, List args) { + private CelMutableCall(String function, java.util.List args) { this.target = Optional.empty(); this.function = checkNotNull(function); this.args = new ArrayList<>(checkNotNull(args)); } - private CelMutableCall(CelMutableExpr target, String function, List args) { + private CelMutableCall( + CelMutableExpr target, String function, java.util.List args) { this(function, args); this.target = Optional.of(target); } } - /** A mutable list creation expression. See {@link Expression.CreateList} */ - public static final class CelMutableList implements Expression.CreateList { - private final List elements; - private final List optionalIndices; + /** A mutable list creation expression. See {@link List} */ + public static final class CelMutableList implements List { + private final java.util.List elements; + private final java.util.List optionalIndices; @Override - public List elements() { + public java.util.List elements() { return elements; } @@ -401,7 +401,7 @@ public void setElement(int index, CelMutableExpr element) { } @Override - public List optionalIndices() { + public java.util.List optionalIndices() { return optionalIndices; } @@ -438,26 +438,26 @@ public static CelMutableList create(CelMutableExpr... elements) { return create(Arrays.asList(checkNotNull(elements))); } - public static CelMutableList create(List elements) { + public static CelMutableList create(java.util.List elements) { return create(elements, new ArrayList<>()); } public static CelMutableList create( - List mutableExprList, List optionalIndices) { + java.util.List mutableExprList, java.util.List optionalIndices) { return new CelMutableList(mutableExprList, optionalIndices); } - private CelMutableList(List mutableExprList, List optionalIndices) { + private CelMutableList( + java.util.List mutableExprList, java.util.List optionalIndices) { this.elements = new ArrayList<>(checkNotNull(mutableExprList)); this.optionalIndices = new ArrayList<>(checkNotNull(optionalIndices)); } } - /** A mutable list creation expression. See {@link Expression.CreateStruct} */ - public static final class CelMutableStruct - implements Expression.CreateStruct { + /** A mutable list creation expression. See {@link Expression.Struct} */ + public static final class CelMutableStruct implements Expression.Struct { private String messageName = ""; - private List entries; + private java.util.List entries; @Override public String messageName() { @@ -469,11 +469,11 @@ public void setMessageName(String messageName) { } @Override - public List entries() { + public java.util.List entries() { return entries; } - public void setEntries(List entries) { + public void setEntries(java.util.List entries) { this.entries = checkNotNull(entries); } @@ -483,7 +483,7 @@ public void setEntry(int index, CelMutableStruct.Entry entry) { } /** Represents a mutable entry of the struct. */ - public static final class Entry implements Expression.CreateStruct.Entry { + public static final class Entry implements Expression.Struct.Entry { private long id; private String fieldKey = ""; private CelMutableExpr value; @@ -607,26 +607,26 @@ private CelMutableStruct deepCopy() { } public static CelMutableStruct create( - String messageName, List entries) { + String messageName, java.util.List entries) { return new CelMutableStruct(messageName, entries); } - private CelMutableStruct(String messageName, List entries) { + private CelMutableStruct(String messageName, java.util.List entries) { this.messageName = checkNotNull(messageName); this.entries = new ArrayList<>(checkNotNull(entries)); } } - /** A mutable map creation expression. See {@link Expression.CreateMap} */ - public static final class CelMutableMap implements Expression.CreateMap { - private List entries; + /** A mutable map creation expression. See {@link Expression.Map} */ + public static final class CelMutableMap implements Expression.Map { + private java.util.List entries; @Override - public List entries() { + public java.util.List entries() { return entries; } - public void setEntries(List entries) { + public void setEntries(java.util.List entries) { this.entries = checkNotNull(entries); } @@ -636,7 +636,7 @@ public void setEntry(int index, CelMutableMap.Entry entry) { } /** Represents an entry of the map */ - public static final class Entry implements Expression.CreateMap.Entry { + public static final class Entry implements Expression.Map.Entry { private long id; private CelMutableExpr key; private CelMutableExpr value; @@ -761,11 +761,11 @@ private CelMutableMap deepCopy() { return create(copiedEntries); } - public static CelMutableMap create(List entries) { + public static CelMutableMap create(java.util.List entries) { return new CelMutableMap(new ArrayList<>(entries)); } - private CelMutableMap(List entries) { + private CelMutableMap(java.util.List entries) { this.entries = checkNotNull(entries); } } @@ -1119,7 +1119,8 @@ private Object exprValue() { throw new IllegalStateException("Unexpected expr kind: " + this.exprKind); } - private static List deepCopyList(List elements) { + private static java.util.List deepCopyList( + java.util.List elements) { ArrayList copiedArgs = new ArrayList<>(); for (CelMutableExpr arg : elements) { copiedArgs.add(newInstance(arg)); diff --git a/common/src/main/java/dev/cel/common/ast/Expression.java b/common/src/main/java/dev/cel/common/ast/Expression.java index 3c2f7a4ed..16852a15c 100644 --- a/common/src/main/java/dev/cel/common/ast/Expression.java +++ b/common/src/main/java/dev/cel/common/ast/Expression.java @@ -15,7 +15,6 @@ package dev.cel.common.ast; import dev.cel.common.annotations.Internal; -import java.util.List; import java.util.Optional; /** @@ -55,16 +54,16 @@ public interface Expression { Call call(); /** Gets the underlying identifier expression. */ - CreateList createList(); + List createList(); /** Gets the underlying select expression. */ Select select(); /** Gets the underlying createStruct expression. */ - CreateStruct> createStruct(); + Struct> createStruct(); /** Gets the underlying createMap expression. */ - CreateMap> createMap(); + Map> createMap(); /** Gets the underlying comprehension expression. */ Comprehension comprehension(); @@ -97,7 +96,7 @@ interface Call { * *

For example, `foo` in `f(foo)` or `x.f(foo)`. */ - List args(); + java.util.List args(); } /** @@ -106,10 +105,10 @@ interface Call { *

Lists may either be homogenous, e.g. `[1, 2, 3]`, or heterogeneous, e.g. `dyn([1, 'hello', * 2.0])` */ - interface CreateList { + interface List { /** The elements part of the list */ - List elements(); + java.util.List elements(); /** * The indices within the elements list which are marked as optional elements. @@ -117,7 +116,7 @@ interface CreateList { *

When an optional-typed value is present, the value it contains is included in the list. If * the optional-typed value is absent, the list element is omitted from the CreateList result. */ - List optionalIndices(); + java.util.List optionalIndices(); } /** A field selection expression. e.g. `request.auth`. */ @@ -152,13 +151,13 @@ interface Select { *

Messages are constructed with a type name and composed of field ids: `types.MyType{field_id: * 'value'}`. */ - interface CreateStruct> { + interface Struct> { /** The type name of the message to be created, empty when creating map literals. */ String messageName(); /** The entries in the creation expression. */ - List entries(); + java.util.List entries(); /** Represents an entry of the struct */ interface Entry { @@ -190,9 +189,9 @@ interface Entry { * *

Maps are constructed as `{'key_name': 'value'}`. */ - interface CreateMap> { + interface Map> { - List entries(); + java.util.List entries(); /** Represents an entry of the map. */ interface Entry { diff --git a/common/src/main/java/dev/cel/common/navigation/CelNavigableExprVisitor.java b/common/src/main/java/dev/cel/common/navigation/CelNavigableExprVisitor.java index 06956d425..41e9802a0 100644 --- a/common/src/main/java/dev/cel/common/navigation/CelNavigableExprVisitor.java +++ b/common/src/main/java/dev/cel/common/navigation/CelNavigableExprVisitor.java @@ -15,8 +15,8 @@ package dev.cel.common.navigation; import dev.cel.common.ast.Expression; +import dev.cel.common.ast.Expression.List; import dev.cel.common.navigation.ExprPropertyCalculator.ExprProperty; -import java.util.List; import java.util.stream.Stream; /** Visitor implementation to navigate an AST. */ @@ -137,7 +137,7 @@ private void visit(T navigableExpr, Expression.Call call) { visitExprList(call.args(), navigableExpr); } - private void visit(T navigableExpr, Expression.CreateList createList) { + private void visit(T navigableExpr, List createList) { visitExprList(createList.elements(), navigableExpr); } @@ -154,15 +154,14 @@ private void visit(T navigableExpr, Expression.Comprehension comprehension) { visit(newNavigableChild(navigableExpr, comprehension.result())); } - private void visitStruct( - T navigableExpr, Expression.CreateStruct> struct) { - for (Expression.CreateStruct.Entry entry : struct.entries()) { + private void visitStruct(T navigableExpr, Expression.Struct> struct) { + for (Expression.Struct.Entry entry : struct.entries()) { visit(newNavigableChild(navigableExpr, entry.value())); } } - private void visitMap(T navigableExpr, Expression.CreateMap> map) { - for (Expression.CreateMap.Entry entry : map.entries()) { + private void visitMap(T navigableExpr, Expression.Map> map) { + for (Expression.Map.Entry entry : map.entries()) { T key = newNavigableChild(navigableExpr, entry.key()); visit(key); @@ -171,7 +170,7 @@ private void visitMap(T navigableExpr, Expression.CreateMap createListExpr, T parent) { + private void visitExprList(java.util.List createListExpr, T parent) { for (E expr : createListExpr) { visit(newNavigableChild(parent, expr)); } diff --git a/common/src/main/java/dev/cel/common/navigation/ExprPropertyCalculator.java b/common/src/main/java/dev/cel/common/navigation/ExprPropertyCalculator.java index f939f3b4b..7c59682f8 100644 --- a/common/src/main/java/dev/cel/common/navigation/ExprPropertyCalculator.java +++ b/common/src/main/java/dev/cel/common/navigation/ExprPropertyCalculator.java @@ -18,10 +18,10 @@ import com.google.auto.value.AutoValue; import dev.cel.common.ast.Expression; -import dev.cel.common.ast.Expression.CreateMap; -import dev.cel.common.ast.Expression.CreateStruct; +import dev.cel.common.ast.Expression.List; +import dev.cel.common.ast.Expression.Map; +import dev.cel.common.ast.Expression.Struct; import java.util.HashMap; -import java.util.List; /** Package-private class to assist computing the height and the max ID of expression nodes. */ final class ExprPropertyCalculator { @@ -94,7 +94,7 @@ private ExprProperty visit(Expression.Call call) { return ExprProperty.merge(visitedArgument, visitedTarget); } - private ExprProperty visit(Expression.CreateList createList) { + private ExprProperty visit(List createList) { return visitExprList(createList.elements()); } @@ -112,24 +112,24 @@ private ExprProperty visit(Expression.Comprehension comprehension) { return visitedProperty; } - private ExprProperty visitStruct(Expression.CreateStruct> struct) { + private ExprProperty visitStruct(Expression.Struct> struct) { ExprProperty visitedProperty = ExprProperty.create(0, 0); - for (CreateStruct.Entry entry : struct.entries()) { + for (Struct.Entry entry : struct.entries()) { visitedProperty = ExprProperty.merge(visitedProperty, visit(entry.value())); } return visitedProperty; } - private ExprProperty visitMap(Expression.CreateMap> map) { + private ExprProperty visitMap(Expression.Map> map) { ExprProperty visitedProperty = ExprProperty.create(0, 0); - for (CreateMap.Entry entry : map.entries()) { + for (Map.Entry entry : map.entries()) { visitedProperty = ExprProperty.merge(visitedProperty, visit(entry.key())); visitedProperty = ExprProperty.merge(visitedProperty, visit(entry.value())); } return visitedProperty; } - private ExprProperty visitExprList(List createListExpr) { + private ExprProperty visitExprList(java.util.List createListExpr) { ExprProperty visitedProperty = ExprProperty.create(0, 0); for (E expr : createListExpr) { visitedProperty = ExprProperty.merge(visitedProperty, visit(expr)); From bac7ae6107a0a6af2f44914ee2abf58e2abc5bb2 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Tue, 30 Apr 2024 14:13:41 -0700 Subject: [PATCH 105/486] Remove appending create modifier in ExprFormatter PiperOrigin-RevId: 629525744 --- .../dev/cel/common/ast/CelExprFormatter.java | 18 +- .../cel/common/ast/CelExprFormatterTest.java | 8 +- .../dev/cel/optimizer/AstMutatorTest.java | 8 +- .../ConstantFoldingOptimizerTest.java | 4 +- ...ion_ast_block_common_subexpr_only.baseline | 214 +++++++------- ...ssion_ast_block_recursion_depth_1.baseline | 232 +++++++-------- ...ssion_ast_block_recursion_depth_2.baseline | 240 ++++++++-------- ...ssion_ast_block_recursion_depth_3.baseline | 232 +++++++-------- ...ssion_ast_block_recursion_depth_4.baseline | 232 +++++++-------- ...ssion_ast_block_recursion_depth_5.baseline | 230 +++++++-------- ...ssion_ast_block_recursion_depth_6.baseline | 226 +++++++-------- ...ssion_ast_block_recursion_depth_7.baseline | 226 +++++++-------- ...ssion_ast_block_recursion_depth_8.baseline | 224 +++++++-------- ...ssion_ast_block_recursion_depth_9.baseline | 222 +++++++-------- .../subexpression_ast_cascaded_binds.baseline | 266 +++++++++--------- 15 files changed, 1283 insertions(+), 1299 deletions(-) diff --git a/common/src/main/java/dev/cel/common/ast/CelExprFormatter.java b/common/src/main/java/dev/cel/common/ast/CelExprFormatter.java index e6783e359..2b14fef78 100644 --- a/common/src/main/java/dev/cel/common/ast/CelExprFormatter.java +++ b/common/src/main/java/dev/cel/common/ast/CelExprFormatter.java @@ -33,23 +33,7 @@ static String format(CelExpr celExpr) { private void formatExpr(CelExpr celExpr) { CelExpr.ExprKind.Kind exprKind = celExpr.exprKind().getKind(); - String kindFormattedText; - // Temporarily retain existing formatted expr kinds until callers are migrated - switch (exprKind) { - case LIST: - kindFormattedText = "CREATE_LIST"; - break; - case STRUCT: - kindFormattedText = "CREATE_STRUCT"; - break; - case MAP: - kindFormattedText = "CREATE_MAP"; - break; - default: - kindFormattedText = exprKind.toString(); - break; - } - append(String.format("%s [%d] {", kindFormattedText, celExpr.id())); + append(String.format("%s [%d] {", exprKind, celExpr.id())); if (!EXCLUDED_NEWLINE_KINDS.contains(exprKind)) { appendNewline(); } diff --git a/common/src/test/java/dev/cel/common/ast/CelExprFormatterTest.java b/common/src/test/java/dev/cel/common/ast/CelExprFormatterTest.java index 0efb890c1..b77c23834 100644 --- a/common/src/test/java/dev/cel/common/ast/CelExprFormatterTest.java +++ b/common/src/test/java/dev/cel/common/ast/CelExprFormatterTest.java @@ -148,7 +148,7 @@ public void create_list() throws Exception { assertThat(formattedExpr) .isEqualTo( - "CREATE_LIST [1] {\n" + "LIST [1] {\n" + " elements: {\n" + " CONSTANT [2] { value: 1 }\n" + " CONSTANT [3] { value: 2 }\n" @@ -188,7 +188,7 @@ public void create_struct() throws Exception { assertThat(formattedExpr) .isEqualTo( - "CREATE_STRUCT [1] {\n" + "STRUCT [1] {\n" + " name: TestAllTypes\n" + " entries: {\n" + " ENTRY [2] {\n" @@ -234,7 +234,7 @@ public void create_map() throws Exception { assertThat(formattedExpr) .isEqualTo( - "CREATE_MAP [1] {\n" + "MAP [1] {\n" + " MAP_ENTRY [2] {\n" + " key: {\n" + " CONSTANT [3] { value: 1 }\n" @@ -283,7 +283,7 @@ public void comprehension() throws Exception { "COMPREHENSION [17] {\n" + " iter_var: x\n" + " iter_range: {\n" - + " CREATE_LIST [1] {\n" + + " LIST [1] {\n" + " elements: {\n" + " CONSTANT [2] { value: 1 }\n" + " CONSTANT [3] { value: 2 }\n" diff --git a/optimizer/src/test/java/dev/cel/optimizer/AstMutatorTest.java b/optimizer/src/test/java/dev/cel/optimizer/AstMutatorTest.java index 50c0cc388..24084156e 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/AstMutatorTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/AstMutatorTest.java @@ -474,7 +474,7 @@ public void replaceSubtree_replaceExtraneousListCreatedByMacro_unparseSuccess() // IDENT [8] { // name: __result__ // } - // CREATE_LIST [9] { + // LIST [9] { // elements: { // CONSTANT [5] { value: 1 } // } @@ -810,7 +810,7 @@ public void mangleComprehensionVariable_singleMacro() throws Exception { "COMPREHENSION [13] {\n" + " iter_var: @c0:0\n" + " iter_range: {\n" - + " CREATE_LIST [1] {\n" + + " LIST [1] {\n" + " elements: {\n" + " CONSTANT [2] { value: false }\n" + " }\n" @@ -893,7 +893,7 @@ public void mangleComprehensionVariable_nestedMacroWithShadowedVariables() throw "COMPREHENSION [27] {\n" + " iter_var: @c0:0\n" + " iter_range: {\n" - + " CREATE_LIST [1] {\n" + + " LIST [1] {\n" + " elements: {\n" + " IDENT [2] {\n" + " name: x\n" @@ -930,7 +930,7 @@ public void mangleComprehensionVariable_nestedMacroWithShadowedVariables() throw + " COMPREHENSION [19] {\n" + " iter_var: @c1:0\n" + " iter_range: {\n" - + " CREATE_LIST [5] {\n" + + " LIST [5] {\n" + " elements: {\n" + " IDENT [6] {\n" + " name: @c0:0\n" diff --git a/optimizer/src/test/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizerTest.java b/optimizer/src/test/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizerTest.java index 306960b02..9813ee266 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizerTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizerTest.java @@ -355,7 +355,7 @@ public void constantFold_withMacroCallPopulated_comprehensionsAreReplacedWithNot "CALL [0] {\n" + " function: map\n" + " target: {\n" - + " CREATE_LIST [3] {\n" + + " LIST [3] {\n" + " elements: {\n" + " CONSTANT [4] { value: 1 }\n" + " CONSTANT [5] { value: 2 }\n" @@ -382,7 +382,7 @@ public void constantFold_astProducesConsistentlyNumberedIds() throws Exception { assertThat(optimizedAst.getExpr().toString()) .isEqualTo( - "CREATE_LIST [1] {\n" + "LIST [1] {\n" + " elements: {\n" + " CONSTANT [2] { value: 1 }\n" + " CONSTANT [3] { value: 2 }\n" diff --git a/optimizer/src/test/resources/subexpression_ast_block_common_subexpr_only.baseline b/optimizer/src/test/resources/subexpression_ast_block_common_subexpr_only.baseline index 552ed004c..a6bb92bb4 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_common_subexpr_only.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_common_subexpr_only.baseline @@ -4,12 +4,12 @@ Source: size([1,2]) + size([1,2]) + 1 == 5 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: size args: { - CREATE_LIST [4] { + LIST [4] { elements: { CONSTANT [5] { value: 1 } CONSTANT [6] { value: 2 } @@ -50,12 +50,12 @@ Source: 2 + size([1,2]) + size([1,2]) + 1 == 7 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: size args: { - CREATE_LIST [4] { + LIST [4] { elements: { CONSTANT [5] { value: 1 } CONSTANT [6] { value: 2 } @@ -102,12 +102,12 @@ Source: size([0]) + size([0]) + size([1,2]) + size([1,2]) == 6 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: size args: { - CREATE_LIST [4] { + LIST [4] { elements: { CONSTANT [5] { value: 0 } } @@ -117,7 +117,7 @@ CALL [1] { CALL [6] { function: size args: { - CREATE_LIST [7] { + LIST [7] { elements: { CONSTANT [8] { value: 1 } CONSTANT [9] { value: 2 } @@ -168,12 +168,12 @@ Source: 5 + size([0]) + size([0]) + size([1,2]) + size([1,2]) + size([1,2,3]) + CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: size args: { - CREATE_LIST [4] { + LIST [4] { elements: { CONSTANT [5] { value: 0 } } @@ -183,7 +183,7 @@ CALL [1] { CALL [6] { function: size args: { - CREATE_LIST [7] { + LIST [7] { elements: { CONSTANT [8] { value: 1 } CONSTANT [9] { value: 2 } @@ -194,7 +194,7 @@ CALL [1] { CALL [10] { function: size args: { - CREATE_LIST [11] { + LIST [11] { elements: { CONSTANT [12] { value: 1 } CONSTANT [13] { value: 2 } @@ -268,7 +268,7 @@ Source: timestamp(int(timestamp(1000000000))).getFullYear() + timestamp(int(time CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: getFullYear @@ -459,12 +459,12 @@ Source: {"a": 2}["a"] + {"a": 2}["a"] * {"a": 2}["a"] == 6 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _[_] args: { - CREATE_MAP [4] { + MAP [4] { MAP_ENTRY [5] { key: { CONSTANT [6] { value: "a" } @@ -512,9 +512,9 @@ Source: {'a': {'b': 1}, 'c': {'b': 1}, 'd': {'e': {'b': 1}}, 'e': {'e': {'b': 1} CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_MAP [3] { + MAP [3] { MAP_ENTRY [4] { key: { CONSTANT [5] { value: "b" } @@ -524,7 +524,7 @@ CALL [1] { } } } - CREATE_MAP [7] { + MAP [7] { MAP_ENTRY [8] { key: { CONSTANT [9] { value: "e" } @@ -538,7 +538,7 @@ CALL [1] { } } } - CREATE_MAP [11] { + MAP [11] { MAP_ENTRY [12] { key: { CONSTANT [13] { value: "a" } @@ -588,9 +588,9 @@ Source: [1, [1,2,3,4], 2, [1,2,3,4], 5, [1,2,3,4], 7, [[1,2], [1,2,3,4]], [1,2]] CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_LIST [3] { + LIST [3] { elements: { CONSTANT [4] { value: 1 } CONSTANT [5] { value: 2 } @@ -598,7 +598,7 @@ CALL [1] { CONSTANT [7] { value: 4 } } } - CREATE_LIST [8] { + LIST [8] { elements: { CONSTANT [9] { value: 1 } CONSTANT [10] { value: 2 } @@ -606,7 +606,7 @@ CALL [1] { } } } - CREATE_LIST [11] { + LIST [11] { elements: { CONSTANT [12] { value: 1 } IDENT [13] { @@ -621,7 +621,7 @@ CALL [1] { name: @index0 } CONSTANT [18] { value: 7 } - CREATE_LIST [19] { + LIST [19] { elements: { IDENT [20] { name: @index1 @@ -644,7 +644,7 @@ Source: msg.single_int64 + msg.single_int64 == 6 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -678,7 +678,7 @@ Source: msg.oneof_type.payload.single_int64 + msg.oneof_type.payload.single_int3 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -753,7 +753,7 @@ Source: true || msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.one CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -811,7 +811,7 @@ Source: msg.oneof_type.payload.map_int32_int64[1] + msg.oneof_type.payload.map_i CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _[_] @@ -863,7 +863,7 @@ Source: msg.oneof_type.payload.map_int32_int64[0] + msg.oneof_type.payload.map_i CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -951,7 +951,7 @@ Source: (msg.single_int64 > 0 ? msg.single_int64 : 0) == 3 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -992,7 +992,7 @@ Source: false ? false : (msg.single_int64) + ((msg.single_int64 + 1) * 2) == 11 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -1045,7 +1045,7 @@ Source: (msg.single_int64 > 0 ? (msg.single_int32 > 0 ? msg.single_int64 + msg.s CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -1114,17 +1114,17 @@ Source: size([[1].exists(i, i > 0)]) + size([[1].exists(j, j > 0)]) + size([[2]. CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: size args: { - CREATE_LIST [4] { + LIST [4] { elements: { COMPREHENSION [5] { iter_var: @c0:0 iter_range: { - CREATE_LIST [6] { + LIST [6] { elements: { CONSTANT [7] { value: 1 } } @@ -1181,12 +1181,12 @@ CALL [1] { CALL [18] { function: size args: { - CREATE_LIST [19] { + LIST [19] { elements: { COMPREHENSION [20] { iter_var: @c0:0 iter_range: { - CREATE_LIST [21] { + LIST [21] { elements: { CONSTANT [22] { value: 2 } } @@ -1283,14 +1283,14 @@ Source: [[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_LIST [3] { + LIST [3] { elements: { COMPREHENSION [4] { iter_var: @c0:0 iter_range: { - CREATE_LIST [5] { + LIST [5] { elements: { CONSTANT [6] { value: 1 } } @@ -1342,12 +1342,12 @@ CALL [1] { } } } - CREATE_LIST [17] { + LIST [17] { elements: { COMPREHENSION [18] { iter_var: @c0:1 iter_range: { - CREATE_LIST [19] { + LIST [19] { elements: { CONSTANT [20] { value: "a" } } @@ -1431,7 +1431,7 @@ CALL [1] { } } } - CREATE_LIST [39] { + LIST [39] { elements: { CONSTANT [40] { value: true } CONSTANT [41] { value: true } @@ -1449,16 +1449,16 @@ Source: [1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [[2, 3, 4], [2, 3, 4], [2, 3, CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_LIST [3] { + LIST [3] { elements: { CONSTANT [4] { value: 1 } CONSTANT [5] { value: 2 } CONSTANT [6] { value: 3 } } } - CREATE_LIST [7] { + LIST [7] { elements: { CONSTANT [8] { value: 2 } CONSTANT [9] { value: 3 } @@ -1479,7 +1479,7 @@ CALL [1] { } accu_var: @x0:0 accu_init: { - CREATE_LIST [14] { + LIST [14] { elements: { } } @@ -1494,7 +1494,7 @@ CALL [1] { IDENT [17] { name: @x0:0 } - CREATE_LIST [18] { + LIST [18] { elements: { COMPREHENSION [19] { iter_var: @c1:0 @@ -1505,7 +1505,7 @@ CALL [1] { } accu_var: @x1:0 accu_init: { - CREATE_LIST [21] { + LIST [21] { elements: { } } @@ -1520,7 +1520,7 @@ CALL [1] { IDENT [24] { name: @x1:0 } - CREATE_LIST [25] { + LIST [25] { elements: { CALL [26] { function: _+_ @@ -1553,7 +1553,7 @@ CALL [1] { } } } - CREATE_LIST [31] { + LIST [31] { elements: { IDENT [32] { name: @index1 @@ -1579,7 +1579,7 @@ CALL [31] { COMPREHENSION [30] { iter_var: @c0:0 iter_range: { - CREATE_LIST [1] { + LIST [1] { elements: { CONSTANT [2] { value: 1 } CONSTANT [3] { value: 2 } @@ -1588,7 +1588,7 @@ CALL [31] { } accu_var: @x0:0 accu_init: { - CREATE_LIST [24] { + LIST [24] { elements: { } } @@ -1603,12 +1603,12 @@ CALL [31] { IDENT [26] { name: @x0:0 } - CREATE_LIST [27] { + LIST [27] { elements: { COMPREHENSION [23] { iter_var: @c1:0 iter_range: { - CREATE_LIST [6] { + LIST [6] { elements: { CONSTANT [7] { value: 1 } CONSTANT [8] { value: 2 } @@ -1618,7 +1618,7 @@ CALL [31] { } accu_var: @x1:0 accu_init: { - CREATE_LIST [15] { + LIST [15] { elements: { } } @@ -1647,7 +1647,7 @@ CALL [31] { IDENT [17] { name: @x1:0 } - CREATE_LIST [18] { + LIST [18] { elements: { IDENT [11] { name: @c1:0 @@ -1679,14 +1679,14 @@ CALL [31] { } } } - CREATE_LIST [32] { + LIST [32] { elements: { - CREATE_LIST [33] { + LIST [33] { elements: { CONSTANT [34] { value: 1 } } } - CREATE_LIST [35] { + LIST [35] { elements: { CONSTANT [36] { value: 2 } } @@ -1701,9 +1701,9 @@ Source: 1 in [1,2,3] && 2 in [1,2,3] && 3 in [3, [1,2,3]] && 1 in [1,2,3] CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_LIST [3] { + LIST [3] { elements: { CONSTANT [4] { value: 1 } CONSTANT [5] { value: 2 } @@ -1748,7 +1748,7 @@ CALL [1] { function: @in args: { CONSTANT [18] { value: 3 } - CREATE_LIST [19] { + LIST [19] { elements: { CONSTANT [20] { value: 3 } IDENT [21] { @@ -1773,9 +1773,9 @@ Source: 2 in {'a': 1, 2: {true: false}, 3: {true: false}} CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_MAP [3] { + MAP [3] { MAP_ENTRY [4] { key: { CONSTANT [5] { value: true } @@ -1791,7 +1791,7 @@ CALL [1] { function: @in args: { CONSTANT [8] { value: 2 } - CREATE_MAP [9] { + MAP [9] { MAP_ENTRY [10] { key: { CONSTANT [11] { value: "a" } @@ -1831,21 +1831,21 @@ Source: [1,2].map(i, [1, 2].map(i, [3,4])) == [[[3, 4], [3, 4]], [[3, 4], [3, 4] CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_LIST [3] { + LIST [3] { elements: { CONSTANT [4] { value: 1 } CONSTANT [5] { value: 2 } } } - CREATE_LIST [6] { + LIST [6] { elements: { CONSTANT [7] { value: 3 } CONSTANT [8] { value: 4 } } } - CREATE_LIST [9] { + LIST [9] { elements: { IDENT [10] { name: @index1 @@ -1869,7 +1869,7 @@ CALL [1] { } accu_var: @x0:0 accu_init: { - CREATE_LIST [15] { + LIST [15] { elements: { } } @@ -1884,7 +1884,7 @@ CALL [1] { IDENT [18] { name: @x0:0 } - CREATE_LIST [19] { + LIST [19] { elements: { COMPREHENSION [20] { iter_var: @c1:0 @@ -1895,7 +1895,7 @@ CALL [1] { } accu_var: @x1:0 accu_init: { - CREATE_LIST [22] { + LIST [22] { elements: { } } @@ -1910,7 +1910,7 @@ CALL [1] { IDENT [25] { name: @x1:0 } - CREATE_LIST [26] { + LIST [26] { elements: { IDENT [27] { name: @index1 @@ -1937,7 +1937,7 @@ CALL [1] { } } } - CREATE_LIST [30] { + LIST [30] { elements: { IDENT [31] { name: @index2 @@ -1957,7 +1957,7 @@ Source: [x - 1 > 3 ? x - 1 : 5].exists(x, x - 1 > 3) || x - 1 > 3 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _-_ @@ -1985,7 +1985,7 @@ CALL [1] { COMPREHENSION [10] { iter_var: @c0:0 iter_range: { - CREATE_LIST [11] { + LIST [11] { elements: { CALL [12] { function: _?_:_ @@ -2065,7 +2065,7 @@ Source: ["foo", "bar"].map(x, [x + x, x + x]).map(x, [x + x, x + x]) CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _+_ @@ -2097,7 +2097,7 @@ CALL [1] { COMPREHENSION [10] { iter_var: @c1:0 iter_range: { - CREATE_LIST [11] { + LIST [11] { elements: { CONSTANT [12] { value: "foo" } CONSTANT [13] { value: "bar" } @@ -2106,7 +2106,7 @@ CALL [1] { } accu_var: @x1:0 accu_init: { - CREATE_LIST [14] { + LIST [14] { elements: { } } @@ -2121,9 +2121,9 @@ CALL [1] { IDENT [17] { name: @x1:0 } - CREATE_LIST [18] { + LIST [18] { elements: { - CREATE_LIST [19] { + LIST [19] { elements: { IDENT [20] { name: @index0 @@ -2147,7 +2147,7 @@ CALL [1] { } accu_var: @x0:0 accu_init: { - CREATE_LIST [23] { + LIST [23] { elements: { } } @@ -2162,9 +2162,9 @@ CALL [1] { IDENT [26] { name: @x0:0 } - CREATE_LIST [27] { + LIST [27] { elements: { - CREATE_LIST [28] { + LIST [28] { elements: { IDENT [29] { name: @index1 @@ -2193,9 +2193,9 @@ Source: has({'a': true}.a) && {'a':true}['a'] CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_MAP [3] { + MAP [3] { MAP_ENTRY [4] { key: { CONSTANT [5] { value: "a" } @@ -2234,10 +2234,10 @@ Source: has({'a': true}.a) && has({'a': true}.a) CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { - CREATE_MAP [4] { + MAP [4] { MAP_ENTRY [5] { key: { CONSTANT [6] { value: "a" } @@ -2269,7 +2269,7 @@ Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : 0) CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -2310,7 +2310,7 @@ Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : msg CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -2362,7 +2362,7 @@ Source: (has(msg.oneof_type.payload.single_int64) ? msg.oneof_type.payload.singl CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -2414,7 +2414,7 @@ Source: (has(msg.oneof_type) && has(msg.oneof_type.payload) && has(msg.oneof_typ CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -2504,14 +2504,14 @@ Source: [10, ?optional.none(), [?optional.none(), ?opt_x], [?optional.none(), ?o CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: optional.none args: { } } - CREATE_LIST [4] { + LIST [4] { elements: { IDENT [5] { name: @index0 @@ -2522,7 +2522,7 @@ CALL [1] { } optional_indices: [0, 1] } - CREATE_LIST [7] { + LIST [7] { elements: { CONSTANT [8] { value: 5 } } @@ -2532,7 +2532,7 @@ CALL [1] { CALL [9] { function: _==_ args: { - CREATE_LIST [10] { + LIST [10] { elements: { CONSTANT [11] { value: 10 } IDENT [12] { @@ -2547,7 +2547,7 @@ CALL [1] { } optional_indices: [0] } - CREATE_LIST [15] { + LIST [15] { elements: { CONSTANT [16] { value: 10 } IDENT [17] { @@ -2568,12 +2568,12 @@ Source: {?'hello': optional.of('hello')}['hello'] + {?'hello': optional.of('hell CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _[_] args: { - CREATE_MAP [4] { + MAP [4] { MAP_ENTRY [5] { key: { CONSTANT [6] { value: "hello" } @@ -2619,9 +2619,9 @@ Source: {?'key': optional.of('test')}[?'bogus'].or({'key': 'test'}[?'bogus']).or CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_MAP [3] { + MAP [3] { MAP_ENTRY [4] { key: { CONSTANT [5] { value: "key" } @@ -2645,7 +2645,7 @@ CALL [1] { CALL [10] { function: _[?_] args: { - CREATE_MAP [11] { + MAP [11] { MAP_ENTRY [12] { key: { CONSTANT [13] { value: "key" } @@ -2701,9 +2701,9 @@ Source: TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: o CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_STRUCT [3] { + STRUCT [3] { name: TestAllTypes entries: { ENTRY [4] { @@ -2763,7 +2763,7 @@ Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('h' + 'e' + 'l' + 'l' + CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _+_ @@ -2963,7 +2963,7 @@ Source: non_pure_custom_func(msg.oneof_type.payload.single_int64) + non_pure_cus CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -3038,7 +3038,7 @@ Source: pure_custom_func(msg.oneof_type.payload.single_int64) + pure_custom_func CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_1.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_1.baseline index cc88bd2e0..497825b80 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_1.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_1.baseline @@ -4,9 +4,9 @@ Source: size([1,2]) + size([1,2]) + 1 == 5 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_LIST [3] { + LIST [3] { elements: { CONSTANT [4] { value: 1 } CONSTANT [5] { value: 2 } @@ -59,9 +59,9 @@ Source: 2 + size([1,2]) + size([1,2]) + 1 == 7 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_LIST [3] { + LIST [3] { elements: { CONSTANT [4] { value: 1 } CONSTANT [5] { value: 2 } @@ -123,9 +123,9 @@ Source: size([0]) + size([0]) + size([1,2]) + size([1,2]) == 6 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_LIST [3] { + LIST [3] { elements: { CONSTANT [4] { value: 0 } } @@ -138,7 +138,7 @@ CALL [1] { } } } - CREATE_LIST [7] { + LIST [7] { elements: { CONSTANT [8] { value: 1 } CONSTANT [9] { value: 2 } @@ -204,9 +204,9 @@ Source: 5 + size([0]) + size([0]) + size([1,2]) + size([1,2]) + size([1,2,3]) + CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_LIST [3] { + LIST [3] { elements: { CONSTANT [4] { value: 0 } } @@ -219,7 +219,7 @@ CALL [1] { } } } - CREATE_LIST [7] { + LIST [7] { elements: { CONSTANT [8] { value: 1 } CONSTANT [9] { value: 2 } @@ -233,7 +233,7 @@ CALL [1] { } } } - CREATE_LIST [12] { + LIST [12] { elements: { CONSTANT [13] { value: 1 } CONSTANT [14] { value: 2 } @@ -331,7 +331,7 @@ Source: timestamp(int(timestamp(1000000000))).getFullYear() + timestamp(int(time CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: timestamp @@ -588,9 +588,9 @@ Source: {"a": 2}["a"] + {"a": 2}["a"] * {"a": 2}["a"] == 6 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_MAP [3] { + MAP [3] { MAP_ENTRY [4] { key: { CONSTANT [5] { value: "a" } @@ -650,9 +650,9 @@ Source: {'a': {'b': 1}, 'c': {'b': 1}, 'd': {'e': {'b': 1}}, 'e': {'e': {'b': 1} CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_MAP [3] { + MAP [3] { MAP_ENTRY [4] { key: { CONSTANT [5] { value: "b" } @@ -662,7 +662,7 @@ CALL [1] { } } } - CREATE_MAP [7] { + MAP [7] { MAP_ENTRY [8] { key: { CONSTANT [9] { value: "e" } @@ -676,7 +676,7 @@ CALL [1] { } } } - CREATE_MAP [11] { + MAP [11] { MAP_ENTRY [12] { key: { CONSTANT [13] { value: "a" } @@ -726,9 +726,9 @@ Source: [1, [1,2,3,4], 2, [1,2,3,4], 5, [1,2,3,4], 7, [[1,2], [1,2,3,4]], [1,2]] CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_LIST [3] { + LIST [3] { elements: { CONSTANT [4] { value: 1 } CONSTANT [5] { value: 2 } @@ -736,13 +736,13 @@ CALL [1] { CONSTANT [7] { value: 4 } } } - CREATE_LIST [8] { + LIST [8] { elements: { CONSTANT [9] { value: 1 } CONSTANT [10] { value: 2 } } } - CREATE_LIST [11] { + LIST [11] { elements: { IDENT [12] { name: @index1 @@ -754,7 +754,7 @@ CALL [1] { } } } - CREATE_LIST [14] { + LIST [14] { elements: { CONSTANT [15] { value: 1 } IDENT [16] { @@ -785,7 +785,7 @@ Source: msg.single_int64 + msg.single_int64 == 6 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -822,7 +822,7 @@ Source: msg.oneof_type.payload.single_int64 + msg.oneof_type.payload.single_int3 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -927,7 +927,7 @@ Source: true || msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.one CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -1024,7 +1024,7 @@ Source: msg.oneof_type.payload.map_int32_int64[1] + msg.oneof_type.payload.map_i CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -1091,7 +1091,7 @@ Source: msg.oneof_type.payload.map_int32_int64[0] + msg.oneof_type.payload.map_i CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -1176,7 +1176,7 @@ Source: msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type. CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -1233,7 +1233,7 @@ Source: (msg.single_int64 > 0 ? msg.single_int64 : 0) == 3 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -1280,7 +1280,7 @@ Source: false ? false : (msg.single_int64) + ((msg.single_int64 + 1) * 2) == 11 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -1345,7 +1345,7 @@ Source: (msg.single_int64 > 0 ? (msg.single_int32 > 0 ? msg.single_int64 + msg.s CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -1429,9 +1429,9 @@ Source: size([[1].exists(i, i > 0)]) + size([[1].exists(j, j > 0)]) + size([[2]. CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_LIST [3] { + LIST [3] { elements: { CONSTANT [4] { value: 1 } } @@ -1456,7 +1456,7 @@ CALL [1] { } } } - CREATE_LIST [11] { + LIST [11] { elements: { CONSTANT [12] { value: 2 } } @@ -1498,7 +1498,7 @@ CALL [1] { CALL [23] { function: size args: { - CREATE_LIST [24] { + LIST [24] { elements: { COMPREHENSION [25] { iter_var: @c0:0 @@ -1544,7 +1544,7 @@ CALL [1] { CALL [33] { function: size args: { - CREATE_LIST [34] { + LIST [34] { elements: { COMPREHENSION [35] { iter_var: @c0:0 @@ -1592,7 +1592,7 @@ CALL [1] { CALL [43] { function: size args: { - CREATE_LIST [44] { + LIST [44] { elements: { COMPREHENSION [45] { iter_var: @c0:0 @@ -1640,7 +1640,7 @@ CALL [1] { CALL [53] { function: size args: { - CREATE_LIST [54] { + LIST [54] { elements: { COMPREHENSION [55] { iter_var: @c0:0 @@ -1696,9 +1696,9 @@ Source: [[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_LIST [3] { + LIST [3] { elements: { CONSTANT [4] { value: 1 } } @@ -1723,7 +1723,7 @@ CALL [1] { } } } - CREATE_LIST [11] { + LIST [11] { elements: { CONSTANT [12] { value: "a" } } @@ -1748,7 +1748,7 @@ CALL [1] { } } } - CREATE_LIST [19] { + LIST [19] { elements: { CONSTANT [20] { value: true } CONSTANT [21] { value: true } @@ -1770,7 +1770,7 @@ CALL [1] { CALL [27] { function: _+_ args: { - CREATE_LIST [28] { + LIST [28] { elements: { COMPREHENSION [29] { iter_var: @c0:0 @@ -1811,7 +1811,7 @@ CALL [1] { } } } - CREATE_LIST [37] { + LIST [37] { elements: { COMPREHENSION [38] { iter_var: @c0:0 @@ -1854,7 +1854,7 @@ CALL [1] { } } } - CREATE_LIST [46] { + LIST [46] { elements: { COMPREHENSION [47] { iter_var: @c0:1 @@ -1897,7 +1897,7 @@ CALL [1] { } } } - CREATE_LIST [55] { + LIST [55] { elements: { COMPREHENSION [56] { iter_var: @c0:1 @@ -1953,16 +1953,16 @@ Source: [1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [[2, 3, 4], [2, 3, 4], [2, 3, CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_LIST [3] { + LIST [3] { elements: { CONSTANT [4] { value: 1 } CONSTANT [5] { value: 2 } CONSTANT [6] { value: 3 } } } - CREATE_LIST [7] { + LIST [7] { elements: { CONSTANT [8] { value: 2 } CONSTANT [9] { value: 3 } @@ -1978,7 +1978,7 @@ CALL [1] { CONSTANT [13] { value: 1 } } } - CREATE_LIST [14] { + LIST [14] { elements: { IDENT [15] { name: @index2 @@ -1996,7 +1996,7 @@ CALL [1] { } } } - CREATE_LIST [19] { + LIST [19] { elements: { IDENT [20] { name: @index1 @@ -2023,7 +2023,7 @@ CALL [1] { } accu_var: @x0:0 accu_init: { - CREATE_LIST [26] { + LIST [26] { elements: { } } @@ -2038,7 +2038,7 @@ CALL [1] { IDENT [29] { name: @x0:0 } - CREATE_LIST [30] { + LIST [30] { elements: { COMPREHENSION [31] { iter_var: @c1:0 @@ -2049,7 +2049,7 @@ CALL [1] { } accu_var: @x1:0 accu_init: { - CREATE_LIST [33] { + LIST [33] { elements: { } } @@ -2092,15 +2092,15 @@ Source: [1, 2].map(y, [1, 2, 3].filter(x, x == y)) == [[1], [2]] CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_LIST [3] { + LIST [3] { elements: { CONSTANT [4] { value: 1 } CONSTANT [5] { value: 2 } } } - CREATE_LIST [6] { + LIST [6] { elements: { CONSTANT [7] { value: 1 } CONSTANT [8] { value: 2 } @@ -2118,7 +2118,7 @@ CALL [1] { } } } - CREATE_LIST [13] { + LIST [13] { elements: { IDENT [14] { name: @c1:0 @@ -2150,17 +2150,17 @@ CALL [1] { } } } - CREATE_LIST [22] { + LIST [22] { elements: { CONSTANT [23] { value: 1 } } } - CREATE_LIST [24] { + LIST [24] { elements: { CONSTANT [25] { value: 2 } } } - CREATE_LIST [26] { + LIST [26] { elements: { IDENT [27] { name: @index6 @@ -2184,7 +2184,7 @@ CALL [1] { } accu_var: @x0:0 accu_init: { - CREATE_LIST [32] { + LIST [32] { elements: { } } @@ -2199,7 +2199,7 @@ CALL [1] { IDENT [35] { name: @x0:0 } - CREATE_LIST [36] { + LIST [36] { elements: { COMPREHENSION [37] { iter_var: @c1:0 @@ -2210,7 +2210,7 @@ CALL [1] { } accu_var: @x1:0 accu_init: { - CREATE_LIST [39] { + LIST [39] { elements: { } } @@ -2253,9 +2253,9 @@ Source: 1 in [1,2,3] && 2 in [1,2,3] && 3 in [3, [1,2,3]] && 1 in [1,2,3] CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_LIST [3] { + LIST [3] { elements: { CONSTANT [4] { value: 1 } CONSTANT [5] { value: 2 } @@ -2291,7 +2291,7 @@ CALL [1] { } } } - CREATE_LIST [16] { + LIST [16] { elements: { CONSTANT [17] { value: 3 } IDENT [18] { @@ -2340,9 +2340,9 @@ Source: 2 in {'a': 1, 2: {true: false}, 3: {true: false}} CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_MAP [3] { + MAP [3] { MAP_ENTRY [4] { key: { CONSTANT [5] { value: true } @@ -2352,7 +2352,7 @@ CALL [1] { } } } - CREATE_MAP [7] { + MAP [7] { MAP_ENTRY [8] { key: { CONSTANT [9] { value: "a" } @@ -2401,21 +2401,21 @@ Source: [1,2].map(i, [1, 2].map(i, [3,4])) == [[[3, 4], [3, 4]], [[3, 4], [3, 4] CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_LIST [3] { + LIST [3] { elements: { CONSTANT [4] { value: 1 } CONSTANT [5] { value: 2 } } } - CREATE_LIST [6] { + LIST [6] { elements: { CONSTANT [7] { value: 3 } CONSTANT [8] { value: 4 } } } - CREATE_LIST [9] { + LIST [9] { elements: { IDENT [10] { name: @index1 @@ -2425,7 +2425,7 @@ CALL [1] { } } } - CREATE_LIST [12] { + LIST [12] { elements: { IDENT [13] { name: @index1 @@ -2443,7 +2443,7 @@ CALL [1] { } } } - CREATE_LIST [17] { + LIST [17] { elements: { IDENT [18] { name: @index2 @@ -2467,7 +2467,7 @@ CALL [1] { } accu_var: @x0:0 accu_init: { - CREATE_LIST [23] { + LIST [23] { elements: { } } @@ -2482,7 +2482,7 @@ CALL [1] { IDENT [26] { name: @x0:0 } - CREATE_LIST [27] { + LIST [27] { elements: { COMPREHENSION [28] { iter_var: @c1:0 @@ -2493,7 +2493,7 @@ CALL [1] { } accu_var: @x1:0 accu_init: { - CREATE_LIST [30] { + LIST [30] { elements: { } } @@ -2536,7 +2536,7 @@ Source: [x - 1 > 3 ? x - 1 : 5].exists(x, x - 1 > 3) || x - 1 > 3 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _-_ @@ -2568,7 +2568,7 @@ CALL [1] { CONSTANT [12] { value: 5 } } } - CREATE_LIST [13] { + LIST [13] { elements: { IDENT [14] { name: @index2 @@ -2659,7 +2659,7 @@ Source: ["foo", "bar"].map(x, [x + x, x + x]).map(x, [x + x, x + x]) CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _+_ @@ -2683,13 +2683,13 @@ CALL [1] { } } } - CREATE_LIST [9] { + LIST [9] { elements: { CONSTANT [10] { value: "foo" } CONSTANT [11] { value: "bar" } } } - CREATE_LIST [12] { + LIST [12] { elements: { IDENT [13] { name: @index0 @@ -2699,7 +2699,7 @@ CALL [1] { } } } - CREATE_LIST [15] { + LIST [15] { elements: { IDENT [16] { name: @index3 @@ -2717,7 +2717,7 @@ CALL [1] { } } } - CREATE_LIST [20] { + LIST [20] { elements: { IDENT [21] { name: @index1 @@ -2727,7 +2727,7 @@ CALL [1] { } } } - CREATE_LIST [23] { + LIST [23] { elements: { IDENT [24] { name: @index6 @@ -2759,7 +2759,7 @@ CALL [1] { } accu_var: @x1:0 accu_init: { - CREATE_LIST [31] { + LIST [31] { elements: { } } @@ -2781,7 +2781,7 @@ CALL [1] { } accu_var: @x0:0 accu_init: { - CREATE_LIST [35] { + LIST [35] { elements: { } } @@ -2808,9 +2808,9 @@ Source: has({'a': true}.a) && {'a':true}['a'] CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_MAP [3] { + MAP [3] { MAP_ENTRY [4] { key: { CONSTANT [5] { value: "a" } @@ -2855,9 +2855,9 @@ Source: has({'a': true}.a) && has({'a': true}.a) CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_MAP [3] { + MAP [3] { MAP_ENTRY [4] { key: { CONSTANT [5] { value: "a" } @@ -2893,7 +2893,7 @@ Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : 0) CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -2946,7 +2946,7 @@ Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : msg CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -3010,7 +3010,7 @@ Source: (has(msg.oneof_type.payload.single_int64) ? msg.oneof_type.payload.singl CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -3074,7 +3074,7 @@ Source: (has(msg.oneof_type) && has(msg.oneof_type.payload) && has(msg.oneof_typ CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -3197,14 +3197,14 @@ Source: [10, ?optional.none(), [?optional.none(), ?opt_x], [?optional.none(), ?o CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: optional.none args: { } } - CREATE_LIST [4] { + LIST [4] { elements: { IDENT [5] { name: @index0 @@ -3215,12 +3215,12 @@ CALL [1] { } optional_indices: [0, 1] } - CREATE_LIST [7] { + LIST [7] { elements: { CONSTANT [8] { value: 5 } } } - CREATE_LIST [9] { + LIST [9] { elements: { CONSTANT [10] { value: 10 } IDENT [11] { @@ -3235,7 +3235,7 @@ CALL [1] { } optional_indices: [0] } - CREATE_LIST [14] { + LIST [14] { elements: { CONSTANT [15] { value: 10 } IDENT [16] { @@ -3267,7 +3267,7 @@ Source: {?'hello': optional.of('hello')}['hello'] + {?'hello': optional.of('hell CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: optional.of @@ -3275,7 +3275,7 @@ CALL [1] { CONSTANT [4] { value: "hello" } } } - CREATE_MAP [5] { + MAP [5] { MAP_ENTRY [6] { key: { CONSTANT [7] { value: "hello" } @@ -3327,9 +3327,9 @@ Source: {?'key': optional.of('test')}[?'bogus'].or({'key': 'test'}[?'bogus']).or CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_MAP [3] { + MAP [3] { MAP_ENTRY [4] { key: { CONSTANT [5] { value: "key" } @@ -3345,7 +3345,7 @@ CALL [1] { CONSTANT [8] { value: "test" } } } - CREATE_MAP [9] { + MAP [9] { MAP_ENTRY [10] { key: { CONSTANT [11] { value: "key" } @@ -3430,7 +3430,7 @@ Source: TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: o CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: optional.ofNonZeroValue @@ -3444,7 +3444,7 @@ CALL [1] { CONSTANT [6] { value: 4 } } } - CREATE_STRUCT [7] { + STRUCT [7] { name: TestAllTypes entries: { ENTRY [8] { @@ -3507,7 +3507,7 @@ Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('h' + 'e' + 'l' + 'l' + CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _+_ @@ -3575,7 +3575,7 @@ Source: 'hello world'.matches('h' + 'e' + 'l' + 'l' + 'o') CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _+_ @@ -3632,7 +3632,7 @@ Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('hello') CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _+_ @@ -3698,7 +3698,7 @@ Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('w' + 'o' + 'r' + 'l' + CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _+_ @@ -3800,7 +3800,7 @@ Source: non_pure_custom_func(msg.oneof_type.payload.single_int64) + non_pure_cus CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -3878,7 +3878,7 @@ Source: pure_custom_func(msg.oneof_type.payload.single_int64) + pure_custom_func CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_2.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_2.baseline index aca5d438e..7a5fa722d 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_2.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_2.baseline @@ -4,12 +4,12 @@ Source: size([1,2]) + size([1,2]) + 1 == 5 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: size args: { - CREATE_LIST [4] { + LIST [4] { elements: { CONSTANT [5] { value: 1 } CONSTANT [6] { value: 2 } @@ -53,12 +53,12 @@ Source: 2 + size([1,2]) + size([1,2]) + 1 == 7 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: size args: { - CREATE_LIST [4] { + LIST [4] { elements: { CONSTANT [5] { value: 1 } CONSTANT [6] { value: 2 } @@ -108,12 +108,12 @@ Source: size([0]) + size([0]) + size([1,2]) + size([1,2]) == 6 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: size args: { - CREATE_LIST [4] { + LIST [4] { elements: { CONSTANT [5] { value: 0 } } @@ -123,7 +123,7 @@ CALL [1] { CALL [6] { function: size args: { - CREATE_LIST [7] { + LIST [7] { elements: { CONSTANT [8] { value: 1 } CONSTANT [9] { value: 2 } @@ -177,12 +177,12 @@ Source: 5 + size([0]) + size([0]) + size([1,2]) + size([1,2]) + size([1,2,3]) + CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: size args: { - CREATE_LIST [4] { + LIST [4] { elements: { CONSTANT [5] { value: 0 } } @@ -192,7 +192,7 @@ CALL [1] { CALL [6] { function: size args: { - CREATE_LIST [7] { + LIST [7] { elements: { CONSTANT [8] { value: 1 } CONSTANT [9] { value: 2 } @@ -203,7 +203,7 @@ CALL [1] { CALL [10] { function: size args: { - CREATE_LIST [11] { + LIST [11] { elements: { CONSTANT [12] { value: 1 } CONSTANT [13] { value: 2 } @@ -286,7 +286,7 @@ Source: timestamp(int(timestamp(1000000000))).getFullYear() + timestamp(int(time CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: int @@ -504,12 +504,12 @@ Source: {"a": 2}["a"] + {"a": 2}["a"] * {"a": 2}["a"] == 6 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _[_] args: { - CREATE_MAP [4] { + MAP [4] { MAP_ENTRY [5] { key: { CONSTANT [6] { value: "a" } @@ -560,15 +560,15 @@ Source: {'a': {'b': 1}, 'c': {'b': 1}, 'd': {'e': {'b': 1}}, 'e': {'e': {'b': 1} CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_MAP [3] { + MAP [3] { MAP_ENTRY [4] { key: { CONSTANT [5] { value: "e" } } value: { - CREATE_MAP [6] { + MAP [6] { MAP_ENTRY [7] { key: { CONSTANT [8] { value: "b" } @@ -581,7 +581,7 @@ CALL [1] { } } } - CREATE_MAP [10] { + MAP [10] { MAP_ENTRY [11] { key: { CONSTANT [12] { value: "b" } @@ -593,7 +593,7 @@ CALL [1] { } } } - CREATE_MAP [14] { + MAP [14] { MAP_ENTRY [15] { key: { CONSTANT [16] { value: "a" } @@ -643,9 +643,9 @@ Source: [1, [1,2,3,4], 2, [1,2,3,4], 5, [1,2,3,4], 7, [[1,2], [1,2,3,4]], [1,2]] CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_LIST [3] { + LIST [3] { elements: { CONSTANT [4] { value: 1 } CONSTANT [5] { value: 2 } @@ -653,7 +653,7 @@ CALL [1] { CONSTANT [7] { value: 4 } } } - CREATE_LIST [8] { + LIST [8] { elements: { CONSTANT [9] { value: 1 } CONSTANT [10] { value: 2 } @@ -661,7 +661,7 @@ CALL [1] { } } } - CREATE_LIST [11] { + LIST [11] { elements: { CONSTANT [12] { value: 1 } IDENT [13] { @@ -676,7 +676,7 @@ CALL [1] { name: @index0 } CONSTANT [18] { value: 7 } - CREATE_LIST [19] { + LIST [19] { elements: { IDENT [20] { name: @index1 @@ -699,7 +699,7 @@ Source: msg.single_int64 + msg.single_int64 == 6 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -733,7 +733,7 @@ Source: msg.oneof_type.payload.single_int64 + msg.oneof_type.payload.single_int3 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -820,7 +820,7 @@ Source: true || msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.one CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -896,7 +896,7 @@ Source: msg.oneof_type.payload.map_int32_int64[1] + msg.oneof_type.payload.map_i CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -954,7 +954,7 @@ Source: msg.oneof_type.payload.map_int32_int64[0] + msg.oneof_type.payload.map_i CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -1027,7 +1027,7 @@ Source: msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type. CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -1072,7 +1072,7 @@ Source: (msg.single_int64 > 0 ? msg.single_int64 : 0) == 3 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -1116,7 +1116,7 @@ Source: false ? false : (msg.single_int64) + ((msg.single_int64 + 1) * 2) == 11 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -1175,7 +1175,7 @@ Source: (msg.single_int64 > 0 ? (msg.single_int32 > 0 ? msg.single_int64 + msg.s CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -1250,7 +1250,7 @@ Source: size([[1].exists(i, i > 0)]) + size([[1].exists(j, j > 0)]) + size([[2]. CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _||_ @@ -1286,12 +1286,12 @@ CALL [1] { } } } - CREATE_LIST [13] { + LIST [13] { elements: { CONSTANT [14] { value: 1 } } } - CREATE_LIST [15] { + LIST [15] { elements: { CONSTANT [16] { value: 2 } } @@ -1313,7 +1313,7 @@ CALL [1] { CALL [21] { function: size args: { - CREATE_LIST [22] { + LIST [22] { elements: { COMPREHENSION [23] { iter_var: @c0:0 @@ -1359,7 +1359,7 @@ CALL [1] { CALL [31] { function: size args: { - CREATE_LIST [32] { + LIST [32] { elements: { COMPREHENSION [33] { iter_var: @c0:0 @@ -1407,7 +1407,7 @@ CALL [1] { CALL [41] { function: size args: { - CREATE_LIST [42] { + LIST [42] { elements: { COMPREHENSION [43] { iter_var: @c0:0 @@ -1455,7 +1455,7 @@ CALL [1] { CALL [51] { function: size args: { - CREATE_LIST [52] { + LIST [52] { elements: { COMPREHENSION [53] { iter_var: @c0:0 @@ -1511,7 +1511,7 @@ Source: [[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _||_ @@ -1547,17 +1547,17 @@ CALL [1] { } } } - CREATE_LIST [13] { + LIST [13] { elements: { CONSTANT [14] { value: 1 } } } - CREATE_LIST [15] { + LIST [15] { elements: { CONSTANT [16] { value: "a" } } } - CREATE_LIST [17] { + LIST [17] { elements: { CONSTANT [18] { value: true } CONSTANT [19] { value: true } @@ -1579,7 +1579,7 @@ CALL [1] { CALL [25] { function: _+_ args: { - CREATE_LIST [26] { + LIST [26] { elements: { COMPREHENSION [27] { iter_var: @c0:0 @@ -1620,7 +1620,7 @@ CALL [1] { } } } - CREATE_LIST [35] { + LIST [35] { elements: { COMPREHENSION [36] { iter_var: @c0:0 @@ -1663,7 +1663,7 @@ CALL [1] { } } } - CREATE_LIST [44] { + LIST [44] { elements: { COMPREHENSION [45] { iter_var: @c0:1 @@ -1706,7 +1706,7 @@ CALL [1] { } } } - CREATE_LIST [53] { + LIST [53] { elements: { COMPREHENSION [54] { iter_var: @c0:1 @@ -1762,23 +1762,23 @@ Source: [1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [[2, 3, 4], [2, 3, 4], [2, 3, CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_LIST [3] { + LIST [3] { elements: { CONSTANT [4] { value: 1 } CONSTANT [5] { value: 2 } CONSTANT [6] { value: 3 } } } - CREATE_LIST [7] { + LIST [7] { elements: { CONSTANT [8] { value: 2 } CONSTANT [9] { value: 3 } CONSTANT [10] { value: 4 } } } - CREATE_LIST [11] { + LIST [11] { elements: { CALL [12] { function: _+_ @@ -1800,7 +1800,7 @@ CALL [1] { } accu_var: @x1:0 accu_init: { - CREATE_LIST [17] { + LIST [17] { elements: { } } @@ -1833,7 +1833,7 @@ CALL [1] { IDENT [24] { name: @x0:0 } - CREATE_LIST [25] { + LIST [25] { elements: { IDENT [26] { name: @index3 @@ -1851,7 +1851,7 @@ CALL [1] { } accu_var: @x0:0 accu_init: { - CREATE_LIST [29] { + LIST [29] { elements: { } } @@ -1878,7 +1878,7 @@ CALL [1] { IDENT [34] { name: @index5 } - CREATE_LIST [35] { + LIST [35] { elements: { IDENT [36] { name: @index1 @@ -1901,7 +1901,7 @@ Source: [1, 2].map(y, [1, 2, 3].filter(x, x == y)) == [[1], [2]] CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _+_ @@ -1909,7 +1909,7 @@ CALL [1] { IDENT [4] { name: @x1:0 } - CREATE_LIST [5] { + LIST [5] { elements: { IDENT [6] { name: @c1:0 @@ -1943,7 +1943,7 @@ CALL [1] { COMPREHENSION [13] { iter_var: @c1:0 iter_range: { - CREATE_LIST [14] { + LIST [14] { elements: { CONSTANT [15] { value: 1 } CONSTANT [16] { value: 2 } @@ -1953,7 +1953,7 @@ CALL [1] { } accu_var: @x1:0 accu_init: { - CREATE_LIST [18] { + LIST [18] { elements: { } } @@ -1978,7 +1978,7 @@ CALL [1] { IDENT [23] { name: @x0:0 } - CREATE_LIST [24] { + LIST [24] { elements: { IDENT [25] { name: @index2 @@ -1990,7 +1990,7 @@ CALL [1] { COMPREHENSION [26] { iter_var: @c0:0 iter_range: { - CREATE_LIST [27] { + LIST [27] { elements: { CONSTANT [28] { value: 1 } CONSTANT [29] { value: 2 } @@ -1999,7 +1999,7 @@ CALL [1] { } accu_var: @x0:0 accu_init: { - CREATE_LIST [30] { + LIST [30] { elements: { } } @@ -2018,14 +2018,14 @@ CALL [1] { } } } - CREATE_LIST [34] { + LIST [34] { elements: { - CREATE_LIST [35] { + LIST [35] { elements: { CONSTANT [36] { value: 1 } } } - CREATE_LIST [37] { + LIST [37] { elements: { CONSTANT [38] { value: 2 } } @@ -2053,13 +2053,13 @@ Source: 1 in [1,2,3] && 2 in [1,2,3] && 3 in [3, [1,2,3]] && 1 in [1,2,3] CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: @in args: { CONSTANT [4] { value: 1 } - CREATE_LIST [5] { + LIST [5] { elements: { CONSTANT [6] { value: 1 } CONSTANT [7] { value: 2 } @@ -2068,7 +2068,7 @@ CALL [1] { } } } - CREATE_LIST [9] { + LIST [9] { elements: { CONSTANT [10] { value: 1 } CONSTANT [11] { value: 2 } @@ -2096,7 +2096,7 @@ CALL [1] { function: @in args: { CONSTANT [19] { value: 3 } - CREATE_LIST [20] { + LIST [20] { elements: { CONSTANT [21] { value: 3 } IDENT [22] { @@ -2135,9 +2135,9 @@ Source: 2 in {'a': 1, 2: {true: false}, 3: {true: false}} CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_MAP [3] { + MAP [3] { MAP_ENTRY [4] { key: { CONSTANT [5] { value: true } @@ -2153,7 +2153,7 @@ CALL [1] { function: @in args: { CONSTANT [8] { value: 2 } - CREATE_MAP [9] { + MAP [9] { MAP_ENTRY [10] { key: { CONSTANT [11] { value: "a" } @@ -2193,17 +2193,17 @@ Source: [1,2].map(i, [1, 2].map(i, [3,4])) == [[[3, 4], [3, 4]], [[3, 4], [3, 4] CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_LIST [3] { + LIST [3] { elements: { - CREATE_LIST [4] { + LIST [4] { elements: { CONSTANT [5] { value: 3 } CONSTANT [6] { value: 4 } } } - CREATE_LIST [7] { + LIST [7] { elements: { CONSTANT [8] { value: 3 } CONSTANT [9] { value: 4 } @@ -2211,15 +2211,15 @@ CALL [1] { } } } - CREATE_LIST [10] { + LIST [10] { elements: { CONSTANT [11] { value: 1 } CONSTANT [12] { value: 2 } } } - CREATE_LIST [13] { + LIST [13] { elements: { - CREATE_LIST [14] { + LIST [14] { elements: { CONSTANT [15] { value: 3 } CONSTANT [16] { value: 4 } @@ -2236,7 +2236,7 @@ CALL [1] { } accu_var: @x1:0 accu_init: { - CREATE_LIST [19] { + LIST [19] { elements: { } } @@ -2269,7 +2269,7 @@ CALL [1] { IDENT [26] { name: @x0:0 } - CREATE_LIST [27] { + LIST [27] { elements: { IDENT [28] { name: @index3 @@ -2287,7 +2287,7 @@ CALL [1] { } accu_var: @x0:0 accu_init: { - CREATE_LIST [31] { + LIST [31] { elements: { } } @@ -2314,7 +2314,7 @@ CALL [1] { IDENT [36] { name: @index5 } - CREATE_LIST [37] { + LIST [37] { elements: { IDENT [38] { name: @index0 @@ -2334,7 +2334,7 @@ Source: [x - 1 > 3 ? x - 1 : 5].exists(x, x - 1 > 3) || x - 1 > 3 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _>_ @@ -2384,7 +2384,7 @@ CALL [1] { CONSTANT [18] { value: 3 } } } - CREATE_LIST [19] { + LIST [19] { elements: { IDENT [20] { name: @index1 @@ -2457,7 +2457,7 @@ Source: ["foo", "bar"].map(x, [x + x, x + x]).map(x, [x + x, x + x]) CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _+_ @@ -2481,9 +2481,9 @@ CALL [1] { } } } - CREATE_LIST [9] { + LIST [9] { elements: { - CREATE_LIST [10] { + LIST [10] { elements: { IDENT [11] { name: @index0 @@ -2498,7 +2498,7 @@ CALL [1] { COMPREHENSION [13] { iter_var: @c1:0 iter_range: { - CREATE_LIST [14] { + LIST [14] { elements: { CONSTANT [15] { value: "foo" } CONSTANT [16] { value: "bar" } @@ -2507,7 +2507,7 @@ CALL [1] { } accu_var: @x1:0 accu_init: { - CREATE_LIST [17] { + LIST [17] { elements: { } } @@ -2534,9 +2534,9 @@ CALL [1] { } } } - CREATE_LIST [23] { + LIST [23] { elements: { - CREATE_LIST [24] { + LIST [24] { elements: { IDENT [25] { name: @index1 @@ -2559,7 +2559,7 @@ CALL [1] { } accu_var: @x0:0 accu_init: { - CREATE_LIST [29] { + LIST [29] { elements: { } } @@ -2594,9 +2594,9 @@ Source: has({'a': true}.a) && {'a':true}['a'] CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_MAP [3] { + MAP [3] { MAP_ENTRY [4] { key: { CONSTANT [5] { value: "a" } @@ -2635,10 +2635,10 @@ Source: has({'a': true}.a) && has({'a': true}.a) CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { - CREATE_MAP [4] { + MAP [4] { MAP_ENTRY [5] { key: { CONSTANT [6] { value: "a" } @@ -2670,7 +2670,7 @@ Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : 0) CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -2717,7 +2717,7 @@ Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : msg CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -2777,7 +2777,7 @@ Source: (has(msg.oneof_type.payload.single_int64) ? msg.oneof_type.payload.singl CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -2832,7 +2832,7 @@ Source: (has(msg.oneof_type) && has(msg.oneof_type.payload) && has(msg.oneof_typ CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -2936,9 +2936,9 @@ Source: [10, ?optional.none(), [?optional.none(), ?opt_x], [?optional.none(), ?o CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_LIST [3] { + LIST [3] { elements: { CALL [4] { function: optional.none @@ -2951,12 +2951,12 @@ CALL [1] { } optional_indices: [0, 1] } - CREATE_LIST [6] { + LIST [6] { elements: { CONSTANT [7] { value: 5 } } } - CREATE_LIST [8] { + LIST [8] { elements: { CONSTANT [9] { value: 10 } CALL [10] { @@ -2981,7 +2981,7 @@ CALL [1] { IDENT [14] { name: @index2 } - CREATE_LIST [15] { + LIST [15] { elements: { CONSTANT [16] { value: 10 } IDENT [17] { @@ -3002,9 +3002,9 @@ Source: {?'hello': optional.of('hello')}['hello'] + {?'hello': optional.of('hell CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_MAP [3] { + MAP [3] { MAP_ENTRY [4] { key: { CONSTANT [5] { value: "hello" } @@ -3056,9 +3056,9 @@ Source: {?'key': optional.of('test')}[?'bogus'].or({'key': 'test'}[?'bogus']).or CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_MAP [3] { + MAP [3] { MAP_ENTRY [4] { key: { CONSTANT [5] { value: "key" } @@ -3068,7 +3068,7 @@ CALL [1] { } } } - CREATE_MAP [7] { + MAP [7] { MAP_ENTRY [8] { key: { CONSTANT [9] { value: "key" } @@ -3147,9 +3147,9 @@ Source: TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: o CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_STRUCT [3] { + STRUCT [3] { name: TestAllTypes entries: { ENTRY [4] { @@ -3212,7 +3212,7 @@ Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('h' + 'e' + 'l' + 'l' + CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _+_ @@ -3271,7 +3271,7 @@ Source: 'hello world'.matches('h' + 'e' + 'l' + 'l' + 'o') CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _+_ @@ -3322,7 +3322,7 @@ Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('hello') CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _+_ @@ -3379,7 +3379,7 @@ Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('w' + 'o' + 'r' + 'l' + CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _+_ @@ -3466,7 +3466,7 @@ Source: non_pure_custom_func(msg.oneof_type.payload.single_int64) + non_pure_cus CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -3541,7 +3541,7 @@ Source: pure_custom_func(msg.oneof_type.payload.single_int64) + pure_custom_func CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_3.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_3.baseline index babd462ba..a87fd8f5a 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_3.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_3.baseline @@ -4,12 +4,12 @@ Source: size([1,2]) + size([1,2]) + 1 == 5 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: size args: { - CREATE_LIST [4] { + LIST [4] { elements: { CONSTANT [5] { value: 1 } CONSTANT [6] { value: 2 } @@ -50,12 +50,12 @@ Source: 2 + size([1,2]) + size([1,2]) + 1 == 7 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: size args: { - CREATE_LIST [4] { + LIST [4] { elements: { CONSTANT [5] { value: 1 } CONSTANT [6] { value: 2 } @@ -105,12 +105,12 @@ Source: size([0]) + size([0]) + size([1,2]) + size([1,2]) == 6 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: size args: { - CREATE_LIST [4] { + LIST [4] { elements: { CONSTANT [5] { value: 0 } } @@ -120,7 +120,7 @@ CALL [1] { CALL [6] { function: size args: { - CREATE_LIST [7] { + LIST [7] { elements: { CONSTANT [8] { value: 1 } CONSTANT [9] { value: 2 } @@ -174,12 +174,12 @@ Source: 5 + size([0]) + size([0]) + size([1,2]) + size([1,2]) + size([1,2,3]) + CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: size args: { - CREATE_LIST [4] { + LIST [4] { elements: { CONSTANT [5] { value: 0 } } @@ -189,7 +189,7 @@ CALL [1] { CALL [6] { function: size args: { - CREATE_LIST [7] { + LIST [7] { elements: { CONSTANT [8] { value: 1 } CONSTANT [9] { value: 2 } @@ -200,7 +200,7 @@ CALL [1] { CALL [10] { function: size args: { - CREATE_LIST [11] { + LIST [11] { elements: { CONSTANT [12] { value: 1 } CONSTANT [13] { value: 2 } @@ -280,7 +280,7 @@ Source: timestamp(int(timestamp(1000000000))).getFullYear() + timestamp(int(time CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: timestamp @@ -486,12 +486,12 @@ Source: {"a": 2}["a"] + {"a": 2}["a"] * {"a": 2}["a"] == 6 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _[_] args: { - CREATE_MAP [4] { + MAP [4] { MAP_ENTRY [5] { key: { CONSTANT [6] { value: "a" } @@ -539,15 +539,15 @@ Source: {'a': {'b': 1}, 'c': {'b': 1}, 'd': {'e': {'b': 1}}, 'e': {'e': {'b': 1} CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_MAP [3] { + MAP [3] { MAP_ENTRY [4] { key: { CONSTANT [5] { value: "e" } } value: { - CREATE_MAP [6] { + MAP [6] { MAP_ENTRY [7] { key: { CONSTANT [8] { value: "b" } @@ -560,7 +560,7 @@ CALL [1] { } } } - CREATE_MAP [10] { + MAP [10] { MAP_ENTRY [11] { key: { CONSTANT [12] { value: "b" } @@ -572,7 +572,7 @@ CALL [1] { } } } - CREATE_MAP [14] { + MAP [14] { MAP_ENTRY [15] { key: { CONSTANT [16] { value: "a" } @@ -622,9 +622,9 @@ Source: [1, [1,2,3,4], 2, [1,2,3,4], 5, [1,2,3,4], 7, [[1,2], [1,2,3,4]], [1,2]] CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_LIST [3] { + LIST [3] { elements: { CONSTANT [4] { value: 1 } CONSTANT [5] { value: 2 } @@ -632,7 +632,7 @@ CALL [1] { CONSTANT [7] { value: 4 } } } - CREATE_LIST [8] { + LIST [8] { elements: { CONSTANT [9] { value: 1 } CONSTANT [10] { value: 2 } @@ -640,7 +640,7 @@ CALL [1] { } } } - CREATE_LIST [11] { + LIST [11] { elements: { CONSTANT [12] { value: 1 } IDENT [13] { @@ -655,7 +655,7 @@ CALL [1] { name: @index0 } CONSTANT [18] { value: 7 } - CREATE_LIST [19] { + LIST [19] { elements: { IDENT [20] { name: @index1 @@ -678,7 +678,7 @@ Source: msg.single_int64 + msg.single_int64 == 6 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -712,7 +712,7 @@ Source: msg.oneof_type.payload.single_int64 + msg.oneof_type.payload.single_int3 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -800,7 +800,7 @@ Source: true || msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.one CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -867,7 +867,7 @@ Source: msg.oneof_type.payload.map_int32_int64[1] + msg.oneof_type.payload.map_i CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -922,7 +922,7 @@ Source: msg.oneof_type.payload.map_int32_int64[0] + msg.oneof_type.payload.map_i CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -989,7 +989,7 @@ Source: msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type. CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -1028,7 +1028,7 @@ Source: (msg.single_int64 > 0 ? msg.single_int64 : 0) == 3 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -1069,7 +1069,7 @@ Source: false ? false : (msg.single_int64) + ((msg.single_int64 + 1) * 2) == 11 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -1125,7 +1125,7 @@ Source: (msg.single_int64 > 0 ? (msg.single_int32 > 0 ? msg.single_int64 + msg.s CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -1197,12 +1197,12 @@ Source: size([[1].exists(i, i > 0)]) + size([[1].exists(j, j > 0)]) + size([[2]. CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { COMPREHENSION [3] { iter_var: @c0:0 iter_range: { - CREATE_LIST [4] { + LIST [4] { elements: { CONSTANT [5] { value: 1 } } @@ -1255,7 +1255,7 @@ CALL [1] { COMPREHENSION [16] { iter_var: @c0:0 iter_range: { - CREATE_LIST [17] { + LIST [17] { elements: { CONSTANT [18] { value: 2 } } @@ -1308,7 +1308,7 @@ CALL [1] { CALL [29] { function: size args: { - CREATE_LIST [30] { + LIST [30] { elements: { IDENT [31] { name: @index0 @@ -1320,7 +1320,7 @@ CALL [1] { CALL [32] { function: size args: { - CREATE_LIST [33] { + LIST [33] { elements: { IDENT [34] { name: @index1 @@ -1375,12 +1375,12 @@ Source: [[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { COMPREHENSION [3] { iter_var: @c0:0 iter_range: { - CREATE_LIST [4] { + LIST [4] { elements: { CONSTANT [5] { value: 1 } } @@ -1433,7 +1433,7 @@ CALL [1] { COMPREHENSION [16] { iter_var: @c0:1 iter_range: { - CREATE_LIST [17] { + LIST [17] { elements: { CONSTANT [18] { value: "a" } } @@ -1483,14 +1483,14 @@ CALL [1] { } } } - CREATE_LIST [29] { + LIST [29] { elements: { IDENT [30] { name: @index0 } } } - CREATE_LIST [31] { + LIST [31] { elements: { IDENT [32] { name: @index1 @@ -1532,7 +1532,7 @@ CALL [1] { IDENT [41] { name: @index4 } - CREATE_LIST [42] { + LIST [42] { elements: { CONSTANT [43] { value: true } CONSTANT [44] { value: true } @@ -1550,16 +1550,16 @@ Source: [1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [[2, 3, 4], [2, 3, 4], [2, 3, CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_LIST [3] { + LIST [3] { elements: { CONSTANT [4] { value: 1 } CONSTANT [5] { value: 2 } CONSTANT [6] { value: 3 } } } - CREATE_LIST [7] { + LIST [7] { elements: { CONSTANT [8] { value: 2 } CONSTANT [9] { value: 3 } @@ -1572,7 +1572,7 @@ CALL [1] { IDENT [12] { name: @x1:0 } - CREATE_LIST [13] { + LIST [13] { elements: { CALL [14] { function: _+_ @@ -1587,7 +1587,7 @@ CALL [1] { } } } - CREATE_LIST [17] { + LIST [17] { elements: { COMPREHENSION [18] { iter_var: @c1:0 @@ -1598,7 +1598,7 @@ CALL [1] { } accu_var: @x1:0 accu_init: { - CREATE_LIST [20] { + LIST [20] { elements: { } } @@ -1633,7 +1633,7 @@ CALL [1] { } accu_var: @x0:0 accu_init: { - CREATE_LIST [27] { + LIST [27] { elements: { } } @@ -1660,7 +1660,7 @@ CALL [1] { } } } - CREATE_LIST [33] { + LIST [33] { elements: { IDENT [34] { name: @index1 @@ -1683,7 +1683,7 @@ Source: [1, 2].map(y, [1, 2, 3].filter(x, x == y)) == [[1], [2]] CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _?_:_ @@ -1705,7 +1705,7 @@ CALL [1] { IDENT [8] { name: @x1:0 } - CREATE_LIST [9] { + LIST [9] { elements: { IDENT [10] { name: @c1:0 @@ -1719,12 +1719,12 @@ CALL [1] { } } } - CREATE_LIST [12] { + LIST [12] { elements: { COMPREHENSION [13] { iter_var: @c1:0 iter_range: { - CREATE_LIST [14] { + LIST [14] { elements: { CONSTANT [15] { value: 1 } CONSTANT [16] { value: 2 } @@ -1734,7 +1734,7 @@ CALL [1] { } accu_var: @x1:0 accu_init: { - CREATE_LIST [18] { + LIST [18] { elements: { } } @@ -1763,7 +1763,7 @@ CALL [1] { COMPREHENSION [23] { iter_var: @c0:0 iter_range: { - CREATE_LIST [24] { + LIST [24] { elements: { CONSTANT [25] { value: 1 } CONSTANT [26] { value: 2 } @@ -1772,7 +1772,7 @@ CALL [1] { } accu_var: @x0:0 accu_init: { - CREATE_LIST [27] { + LIST [27] { elements: { } } @@ -1799,14 +1799,14 @@ CALL [1] { } } } - CREATE_LIST [33] { + LIST [33] { elements: { - CREATE_LIST [34] { + LIST [34] { elements: { CONSTANT [35] { value: 1 } } } - CREATE_LIST [36] { + LIST [36] { elements: { CONSTANT [37] { value: 2 } } @@ -1823,13 +1823,13 @@ Source: 1 in [1,2,3] && 2 in [1,2,3] && 3 in [3, [1,2,3]] && 1 in [1,2,3] CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: @in args: { CONSTANT [4] { value: 1 } - CREATE_LIST [5] { + LIST [5] { elements: { CONSTANT [6] { value: 1 } CONSTANT [7] { value: 2 } @@ -1838,7 +1838,7 @@ CALL [1] { } } } - CREATE_LIST [9] { + LIST [9] { elements: { CONSTANT [10] { value: 1 } CONSTANT [11] { value: 2 } @@ -1852,7 +1852,7 @@ CALL [1] { function: @in args: { CONSTANT [15] { value: 3 } - CREATE_LIST [16] { + LIST [16] { elements: { CONSTANT [17] { value: 3 } IDENT [18] { @@ -1902,9 +1902,9 @@ Source: 2 in {'a': 1, 2: {true: false}, 3: {true: false}} CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_MAP [3] { + MAP [3] { MAP_ENTRY [4] { key: { CONSTANT [5] { value: true } @@ -1920,7 +1920,7 @@ CALL [1] { function: @in args: { CONSTANT [8] { value: 2 } - CREATE_MAP [9] { + MAP [9] { MAP_ENTRY [10] { key: { CONSTANT [11] { value: "a" } @@ -1960,17 +1960,17 @@ Source: [1,2].map(i, [1, 2].map(i, [3,4])) == [[[3, 4], [3, 4]], [[3, 4], [3, 4] CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_LIST [3] { + LIST [3] { elements: { - CREATE_LIST [4] { + LIST [4] { elements: { CONSTANT [5] { value: 3 } CONSTANT [6] { value: 4 } } } - CREATE_LIST [7] { + LIST [7] { elements: { CONSTANT [8] { value: 3 } CONSTANT [9] { value: 4 } @@ -1978,7 +1978,7 @@ CALL [1] { } } } - CREATE_LIST [10] { + LIST [10] { elements: { CONSTANT [11] { value: 1 } CONSTANT [12] { value: 2 } @@ -1990,9 +1990,9 @@ CALL [1] { IDENT [14] { name: @x1:0 } - CREATE_LIST [15] { + LIST [15] { elements: { - CREATE_LIST [16] { + LIST [16] { elements: { CONSTANT [17] { value: 3 } CONSTANT [18] { value: 4 } @@ -2002,7 +2002,7 @@ CALL [1] { } } } - CREATE_LIST [19] { + LIST [19] { elements: { COMPREHENSION [20] { iter_var: @c1:0 @@ -2013,7 +2013,7 @@ CALL [1] { } accu_var: @x1:0 accu_init: { - CREATE_LIST [22] { + LIST [22] { elements: { } } @@ -2048,7 +2048,7 @@ CALL [1] { } accu_var: @x0:0 accu_init: { - CREATE_LIST [29] { + LIST [29] { elements: { } } @@ -2075,7 +2075,7 @@ CALL [1] { } } } - CREATE_LIST [35] { + LIST [35] { elements: { IDENT [36] { name: @index0 @@ -2095,7 +2095,7 @@ Source: [x - 1 > 3 ? x - 1 : 5].exists(x, x - 1 > 3) || x - 1 > 3 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _>_ @@ -2112,7 +2112,7 @@ CALL [1] { CONSTANT [7] { value: 3 } } } - CREATE_LIST [8] { + LIST [8] { elements: { CALL [9] { function: _?_:_ @@ -2215,7 +2215,7 @@ Source: ["foo", "bar"].map(x, [x + x, x + x]).map(x, [x + x, x + x]) CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _+_ @@ -2245,9 +2245,9 @@ CALL [1] { IDENT [10] { name: @x1:0 } - CREATE_LIST [11] { + LIST [11] { elements: { - CREATE_LIST [12] { + LIST [12] { elements: { IDENT [13] { name: @index0 @@ -2267,9 +2267,9 @@ CALL [1] { IDENT [16] { name: @x0:0 } - CREATE_LIST [17] { + LIST [17] { elements: { - CREATE_LIST [18] { + LIST [18] { elements: { IDENT [19] { name: @index1 @@ -2291,7 +2291,7 @@ CALL [1] { COMPREHENSION [22] { iter_var: @c1:0 iter_range: { - CREATE_LIST [23] { + LIST [23] { elements: { CONSTANT [24] { value: "foo" } CONSTANT [25] { value: "bar" } @@ -2300,7 +2300,7 @@ CALL [1] { } accu_var: @x1:0 accu_init: { - CREATE_LIST [26] { + LIST [26] { elements: { } } @@ -2322,7 +2322,7 @@ CALL [1] { } accu_var: @x0:0 accu_init: { - CREATE_LIST [30] { + LIST [30] { elements: { } } @@ -2349,9 +2349,9 @@ Source: has({'a': true}.a) && {'a':true}['a'] CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_MAP [3] { + MAP [3] { MAP_ENTRY [4] { key: { CONSTANT [5] { value: "a" } @@ -2390,10 +2390,10 @@ Source: has({'a': true}.a) && has({'a': true}.a) CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { - CREATE_MAP [4] { + MAP [4] { MAP_ENTRY [5] { key: { CONSTANT [6] { value: "a" } @@ -2425,7 +2425,7 @@ Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : 0) CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -2469,7 +2469,7 @@ Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : msg CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -2523,7 +2523,7 @@ Source: (has(msg.oneof_type.payload.single_int64) ? msg.oneof_type.payload.singl CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -2579,7 +2579,7 @@ Source: (has(msg.oneof_type) && has(msg.oneof_type.payload) && has(msg.oneof_typ CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -2678,9 +2678,9 @@ Source: [10, ?optional.none(), [?optional.none(), ?opt_x], [?optional.none(), ?o CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_LIST [3] { + LIST [3] { elements: { CALL [4] { function: optional.none @@ -2693,7 +2693,7 @@ CALL [1] { } optional_indices: [0, 1] } - CREATE_LIST [6] { + LIST [6] { elements: { CONSTANT [7] { value: 5 } } @@ -2703,7 +2703,7 @@ CALL [1] { CALL [8] { function: _==_ args: { - CREATE_LIST [9] { + LIST [9] { elements: { CONSTANT [10] { value: 10 } CALL [11] { @@ -2720,7 +2720,7 @@ CALL [1] { } optional_indices: [0] } - CREATE_LIST [14] { + LIST [14] { elements: { CONSTANT [15] { value: 10 } IDENT [16] { @@ -2741,12 +2741,12 @@ Source: {?'hello': optional.of('hello')}['hello'] + {?'hello': optional.of('hell CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _[_] args: { - CREATE_MAP [4] { + MAP [4] { MAP_ENTRY [5] { key: { CONSTANT [6] { value: "hello" } @@ -2792,9 +2792,9 @@ Source: {?'key': optional.of('test')}[?'bogus'].or({'key': 'test'}[?'bogus']).or CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_MAP [3] { + MAP [3] { MAP_ENTRY [4] { key: { CONSTANT [5] { value: "key" } @@ -2807,7 +2807,7 @@ CALL [1] { CALL [7] { function: _[?_] args: { - CREATE_MAP [8] { + MAP [8] { MAP_ENTRY [9] { key: { CONSTANT [10] { value: "key" } @@ -2880,9 +2880,9 @@ Source: TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: o CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_STRUCT [3] { + STRUCT [3] { name: TestAllTypes entries: { ENTRY [4] { @@ -2942,7 +2942,7 @@ Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('h' + 'e' + 'l' + 'l' + CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _+_ @@ -3001,7 +3001,7 @@ Source: 'hello world'.matches('h' + 'e' + 'l' + 'l' + 'o') CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _+_ @@ -3049,7 +3049,7 @@ Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('hello') CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _+_ @@ -3103,7 +3103,7 @@ Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('w' + 'o' + 'r' + 'l' + CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _+_ @@ -3184,7 +3184,7 @@ Source: non_pure_custom_func(msg.oneof_type.payload.single_int64) + non_pure_cus CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -3260,7 +3260,7 @@ Source: pure_custom_func(msg.oneof_type.payload.single_int64) + pure_custom_func CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_4.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_4.baseline index 34e6aaca1..538fe0062 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_4.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_4.baseline @@ -4,12 +4,12 @@ Source: size([1,2]) + size([1,2]) + 1 == 5 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: size args: { - CREATE_LIST [4] { + LIST [4] { elements: { CONSTANT [5] { value: 1 } CONSTANT [6] { value: 2 } @@ -50,12 +50,12 @@ Source: 2 + size([1,2]) + size([1,2]) + 1 == 7 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: size args: { - CREATE_LIST [4] { + LIST [4] { elements: { CONSTANT [5] { value: 1 } CONSTANT [6] { value: 2 } @@ -102,12 +102,12 @@ Source: size([0]) + size([0]) + size([1,2]) + size([1,2]) == 6 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: size args: { - CREATE_LIST [4] { + LIST [4] { elements: { CONSTANT [5] { value: 0 } } @@ -117,7 +117,7 @@ CALL [1] { CALL [6] { function: size args: { - CREATE_LIST [7] { + LIST [7] { elements: { CONSTANT [8] { value: 1 } CONSTANT [9] { value: 2 } @@ -168,12 +168,12 @@ Source: 5 + size([0]) + size([0]) + size([1,2]) + size([1,2]) + size([1,2,3]) + CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: size args: { - CREATE_LIST [4] { + LIST [4] { elements: { CONSTANT [5] { value: 0 } } @@ -183,7 +183,7 @@ CALL [1] { CALL [6] { function: size args: { - CREATE_LIST [7] { + LIST [7] { elements: { CONSTANT [8] { value: 1 } CONSTANT [9] { value: 2 } @@ -194,7 +194,7 @@ CALL [1] { CALL [10] { function: size args: { - CREATE_LIST [11] { + LIST [11] { elements: { CONSTANT [12] { value: 1 } CONSTANT [13] { value: 2 } @@ -271,7 +271,7 @@ Source: timestamp(int(timestamp(1000000000))).getFullYear() + timestamp(int(time CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: getFullYear @@ -468,12 +468,12 @@ Source: {"a": 2}["a"] + {"a": 2}["a"] * {"a": 2}["a"] == 6 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _[_] args: { - CREATE_MAP [4] { + MAP [4] { MAP_ENTRY [5] { key: { CONSTANT [6] { value: "a" } @@ -521,15 +521,15 @@ Source: {'a': {'b': 1}, 'c': {'b': 1}, 'd': {'e': {'b': 1}}, 'e': {'e': {'b': 1} CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_MAP [3] { + MAP [3] { MAP_ENTRY [4] { key: { CONSTANT [5] { value: "e" } } value: { - CREATE_MAP [6] { + MAP [6] { MAP_ENTRY [7] { key: { CONSTANT [8] { value: "b" } @@ -542,7 +542,7 @@ CALL [1] { } } } - CREATE_MAP [10] { + MAP [10] { MAP_ENTRY [11] { key: { CONSTANT [12] { value: "b" } @@ -554,7 +554,7 @@ CALL [1] { } } } - CREATE_MAP [14] { + MAP [14] { MAP_ENTRY [15] { key: { CONSTANT [16] { value: "a" } @@ -604,9 +604,9 @@ Source: [1, [1,2,3,4], 2, [1,2,3,4], 5, [1,2,3,4], 7, [[1,2], [1,2,3,4]], [1,2]] CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_LIST [3] { + LIST [3] { elements: { CONSTANT [4] { value: 1 } CONSTANT [5] { value: 2 } @@ -614,7 +614,7 @@ CALL [1] { CONSTANT [7] { value: 4 } } } - CREATE_LIST [8] { + LIST [8] { elements: { CONSTANT [9] { value: 1 } CONSTANT [10] { value: 2 } @@ -622,7 +622,7 @@ CALL [1] { } } } - CREATE_LIST [11] { + LIST [11] { elements: { CONSTANT [12] { value: 1 } IDENT [13] { @@ -637,7 +637,7 @@ CALL [1] { name: @index0 } CONSTANT [18] { value: 7 } - CREATE_LIST [19] { + LIST [19] { elements: { IDENT [20] { name: @index1 @@ -660,7 +660,7 @@ Source: msg.single_int64 + msg.single_int64 == 6 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -694,7 +694,7 @@ Source: msg.oneof_type.payload.single_int64 + msg.oneof_type.payload.single_int3 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -779,7 +779,7 @@ Source: true || msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.one CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -846,7 +846,7 @@ Source: msg.oneof_type.payload.map_int32_int64[1] + msg.oneof_type.payload.map_i CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _[_] @@ -898,7 +898,7 @@ Source: msg.oneof_type.payload.map_int32_int64[0] + msg.oneof_type.payload.map_i CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -962,7 +962,7 @@ Source: msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type. CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -1001,7 +1001,7 @@ Source: (msg.single_int64 > 0 ? msg.single_int64 : 0) == 3 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -1042,7 +1042,7 @@ Source: false ? false : (msg.single_int64) + ((msg.single_int64 + 1) * 2) == 11 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -1098,7 +1098,7 @@ Source: (msg.single_int64 > 0 ? (msg.single_int32 > 0 ? msg.single_int64 + msg.s CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -1167,14 +1167,14 @@ Source: size([[1].exists(i, i > 0)]) + size([[1].exists(j, j > 0)]) + size([[2]. CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_LIST [3] { + LIST [3] { elements: { COMPREHENSION [4] { iter_var: @c0:0 iter_range: { - CREATE_LIST [5] { + LIST [5] { elements: { CONSTANT [6] { value: 1 } } @@ -1226,12 +1226,12 @@ CALL [1] { } } } - CREATE_LIST [17] { + LIST [17] { elements: { COMPREHENSION [18] { iter_var: @c0:0 iter_range: { - CREATE_LIST [19] { + LIST [19] { elements: { CONSTANT [20] { value: 2 } } @@ -1342,14 +1342,14 @@ Source: [[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_LIST [3] { + LIST [3] { elements: { COMPREHENSION [4] { iter_var: @c0:0 iter_range: { - CREATE_LIST [5] { + LIST [5] { elements: { CONSTANT [6] { value: 1 } } @@ -1401,12 +1401,12 @@ CALL [1] { } } } - CREATE_LIST [17] { + LIST [17] { elements: { COMPREHENSION [18] { iter_var: @c0:1 iter_range: { - CREATE_LIST [19] { + LIST [19] { elements: { CONSTANT [20] { value: "a" } } @@ -1490,7 +1490,7 @@ CALL [1] { } } } - CREATE_LIST [39] { + LIST [39] { elements: { CONSTANT [40] { value: true } CONSTANT [41] { value: true } @@ -1508,16 +1508,16 @@ Source: [1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [[2, 3, 4], [2, 3, 4], [2, 3, CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_LIST [3] { + LIST [3] { elements: { CONSTANT [4] { value: 1 } CONSTANT [5] { value: 2 } CONSTANT [6] { value: 3 } } } - CREATE_LIST [7] { + LIST [7] { elements: { CONSTANT [8] { value: 2 } CONSTANT [9] { value: 3 } @@ -1533,7 +1533,7 @@ CALL [1] { } accu_var: @x1:0 accu_init: { - CREATE_LIST [13] { + LIST [13] { elements: { } } @@ -1548,7 +1548,7 @@ CALL [1] { IDENT [16] { name: @x1:0 } - CREATE_LIST [17] { + LIST [17] { elements: { CALL [18] { function: _+_ @@ -1584,7 +1584,7 @@ CALL [1] { } accu_var: @x0:0 accu_init: { - CREATE_LIST [25] { + LIST [25] { elements: { } } @@ -1599,7 +1599,7 @@ CALL [1] { IDENT [28] { name: @x0:0 } - CREATE_LIST [29] { + LIST [29] { elements: { IDENT [30] { name: @index2 @@ -1615,7 +1615,7 @@ CALL [1] { } } } - CREATE_LIST [32] { + LIST [32] { elements: { IDENT [33] { name: @index1 @@ -1638,12 +1638,12 @@ Source: [1, 2].map(y, [1, 2, 3].filter(x, x == y)) == [[1], [2]] CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { COMPREHENSION [3] { iter_var: @c1:0 iter_range: { - CREATE_LIST [4] { + LIST [4] { elements: { CONSTANT [5] { value: 1 } CONSTANT [6] { value: 2 } @@ -1653,7 +1653,7 @@ CALL [1] { } accu_var: @x1:0 accu_init: { - CREATE_LIST [8] { + LIST [8] { elements: { } } @@ -1682,7 +1682,7 @@ CALL [1] { IDENT [15] { name: @x1:0 } - CREATE_LIST [16] { + LIST [16] { elements: { IDENT [17] { name: @c1:0 @@ -1711,7 +1711,7 @@ CALL [1] { COMPREHENSION [21] { iter_var: @c0:0 iter_range: { - CREATE_LIST [22] { + LIST [22] { elements: { CONSTANT [23] { value: 1 } CONSTANT [24] { value: 2 } @@ -1720,7 +1720,7 @@ CALL [1] { } accu_var: @x0:0 accu_init: { - CREATE_LIST [25] { + LIST [25] { elements: { } } @@ -1735,7 +1735,7 @@ CALL [1] { IDENT [28] { name: @x0:0 } - CREATE_LIST [29] { + LIST [29] { elements: { IDENT [30] { name: @index0 @@ -1751,14 +1751,14 @@ CALL [1] { } } } - CREATE_LIST [32] { + LIST [32] { elements: { - CREATE_LIST [33] { + LIST [33] { elements: { CONSTANT [34] { value: 1 } } } - CREATE_LIST [35] { + LIST [35] { elements: { CONSTANT [36] { value: 2 } } @@ -1775,13 +1775,13 @@ Source: 1 in [1,2,3] && 2 in [1,2,3] && 3 in [3, [1,2,3]] && 1 in [1,2,3] CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: @in args: { CONSTANT [4] { value: 1 } - CREATE_LIST [5] { + LIST [5] { elements: { CONSTANT [6] { value: 1 } CONSTANT [7] { value: 2 } @@ -1790,7 +1790,7 @@ CALL [1] { } } } - CREATE_LIST [9] { + LIST [9] { elements: { CONSTANT [10] { value: 1 } CONSTANT [11] { value: 2 } @@ -1826,7 +1826,7 @@ CALL [1] { function: @in args: { CONSTANT [21] { value: 3 } - CREATE_LIST [22] { + LIST [22] { elements: { CONSTANT [23] { value: 3 } IDENT [24] { @@ -1851,9 +1851,9 @@ Source: 2 in {'a': 1, 2: {true: false}, 3: {true: false}} CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_MAP [3] { + MAP [3] { MAP_ENTRY [4] { key: { CONSTANT [5] { value: true } @@ -1869,7 +1869,7 @@ CALL [1] { function: @in args: { CONSTANT [8] { value: 2 } - CREATE_MAP [9] { + MAP [9] { MAP_ENTRY [10] { key: { CONSTANT [11] { value: "a" } @@ -1909,17 +1909,17 @@ Source: [1,2].map(i, [1, 2].map(i, [3,4])) == [[[3, 4], [3, 4]], [[3, 4], [3, 4] CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_LIST [3] { + LIST [3] { elements: { - CREATE_LIST [4] { + LIST [4] { elements: { CONSTANT [5] { value: 3 } CONSTANT [6] { value: 4 } } } - CREATE_LIST [7] { + LIST [7] { elements: { CONSTANT [8] { value: 3 } CONSTANT [9] { value: 4 } @@ -1927,7 +1927,7 @@ CALL [1] { } } } - CREATE_LIST [10] { + LIST [10] { elements: { CONSTANT [11] { value: 1 } CONSTANT [12] { value: 2 } @@ -1942,7 +1942,7 @@ CALL [1] { } accu_var: @x1:0 accu_init: { - CREATE_LIST [15] { + LIST [15] { elements: { } } @@ -1957,9 +1957,9 @@ CALL [1] { IDENT [18] { name: @x1:0 } - CREATE_LIST [19] { + LIST [19] { elements: { - CREATE_LIST [20] { + LIST [20] { elements: { CONSTANT [21] { value: 3 } CONSTANT [22] { value: 4 } @@ -1990,7 +1990,7 @@ CALL [1] { } accu_var: @x0:0 accu_init: { - CREATE_LIST [27] { + LIST [27] { elements: { } } @@ -2005,7 +2005,7 @@ CALL [1] { IDENT [30] { name: @x0:0 } - CREATE_LIST [31] { + LIST [31] { elements: { IDENT [32] { name: @index2 @@ -2021,7 +2021,7 @@ CALL [1] { } } } - CREATE_LIST [34] { + LIST [34] { elements: { IDENT [35] { name: @index0 @@ -2041,7 +2041,7 @@ Source: [x - 1 > 3 ? x - 1 : 5].exists(x, x - 1 > 3) || x - 1 > 3 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _>_ @@ -2061,7 +2061,7 @@ CALL [1] { COMPREHENSION [8] { iter_var: @c0:0 iter_range: { - CREATE_LIST [9] { + LIST [9] { elements: { CALL [10] { function: _?_:_ @@ -2155,7 +2155,7 @@ Source: ["foo", "bar"].map(x, [x + x, x + x]).map(x, [x + x, x + x]) CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _+_ @@ -2182,7 +2182,7 @@ CALL [1] { COMPREHENSION [9] { iter_var: @c1:0 iter_range: { - CREATE_LIST [10] { + LIST [10] { elements: { CONSTANT [11] { value: "foo" } CONSTANT [12] { value: "bar" } @@ -2191,7 +2191,7 @@ CALL [1] { } accu_var: @x1:0 accu_init: { - CREATE_LIST [13] { + LIST [13] { elements: { } } @@ -2206,9 +2206,9 @@ CALL [1] { IDENT [16] { name: @x1:0 } - CREATE_LIST [17] { + LIST [17] { elements: { - CREATE_LIST [18] { + LIST [18] { elements: { IDENT [19] { name: @index0 @@ -2240,7 +2240,7 @@ CALL [1] { } accu_var: @x0:0 accu_init: { - CREATE_LIST [24] { + LIST [24] { elements: { } } @@ -2255,9 +2255,9 @@ CALL [1] { IDENT [27] { name: @x0:0 } - CREATE_LIST [28] { + LIST [28] { elements: { - CREATE_LIST [29] { + LIST [29] { elements: { IDENT [30] { name: @index1 @@ -2286,9 +2286,9 @@ Source: has({'a': true}.a) && {'a':true}['a'] CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_MAP [3] { + MAP [3] { MAP_ENTRY [4] { key: { CONSTANT [5] { value: "a" } @@ -2327,10 +2327,10 @@ Source: has({'a': true}.a) && has({'a': true}.a) CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { - CREATE_MAP [4] { + MAP [4] { MAP_ENTRY [5] { key: { CONSTANT [6] { value: "a" } @@ -2362,7 +2362,7 @@ Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : 0) CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -2403,7 +2403,7 @@ Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : msg CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -2454,7 +2454,7 @@ Source: (has(msg.oneof_type.payload.single_int64) ? msg.oneof_type.payload.singl CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -2510,7 +2510,7 @@ Source: (has(msg.oneof_type) && has(msg.oneof_type.payload) && has(msg.oneof_typ CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -2606,9 +2606,9 @@ Source: [10, ?optional.none(), [?optional.none(), ?opt_x], [?optional.none(), ?o CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_LIST [3] { + LIST [3] { elements: { CALL [4] { function: optional.none @@ -2621,7 +2621,7 @@ CALL [1] { } optional_indices: [0, 1] } - CREATE_LIST [6] { + LIST [6] { elements: { CONSTANT [7] { value: 5 } } @@ -2631,7 +2631,7 @@ CALL [1] { CALL [8] { function: _==_ args: { - CREATE_LIST [9] { + LIST [9] { elements: { CONSTANT [10] { value: 10 } CALL [11] { @@ -2648,7 +2648,7 @@ CALL [1] { } optional_indices: [0] } - CREATE_LIST [14] { + LIST [14] { elements: { CONSTANT [15] { value: 10 } IDENT [16] { @@ -2669,12 +2669,12 @@ Source: {?'hello': optional.of('hello')}['hello'] + {?'hello': optional.of('hell CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _[_] args: { - CREATE_MAP [4] { + MAP [4] { MAP_ENTRY [5] { key: { CONSTANT [6] { value: "hello" } @@ -2720,9 +2720,9 @@ Source: {?'key': optional.of('test')}[?'bogus'].or({'key': 'test'}[?'bogus']).or CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_MAP [3] { + MAP [3] { MAP_ENTRY [4] { key: { CONSTANT [5] { value: "key" } @@ -2738,7 +2738,7 @@ CALL [1] { CALL [8] { function: _[?_] args: { - CREATE_MAP [9] { + MAP [9] { MAP_ENTRY [10] { key: { CONSTANT [11] { value: "key" } @@ -2805,9 +2805,9 @@ Source: TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: o CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_STRUCT [3] { + STRUCT [3] { name: TestAllTypes entries: { ENTRY [4] { @@ -2867,7 +2867,7 @@ Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('h' + 'e' + 'l' + 'l' + CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _+_ @@ -2923,7 +2923,7 @@ Source: 'hello world'.matches('h' + 'e' + 'l' + 'l' + 'o') CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _+_ @@ -2971,7 +2971,7 @@ Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('hello') CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _+_ @@ -3025,7 +3025,7 @@ Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('w' + 'o' + 'r' + 'l' + CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _+_ @@ -3106,7 +3106,7 @@ Source: non_pure_custom_func(msg.oneof_type.payload.single_int64) + non_pure_cus CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -3182,7 +3182,7 @@ Source: pure_custom_func(msg.oneof_type.payload.single_int64) + pure_custom_func CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: pure_custom_func diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_5.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_5.baseline index 36fe2713b..ae1f4743b 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_5.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_5.baseline @@ -4,12 +4,12 @@ Source: size([1,2]) + size([1,2]) + 1 == 5 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: size args: { - CREATE_LIST [4] { + LIST [4] { elements: { CONSTANT [5] { value: 1 } CONSTANT [6] { value: 2 } @@ -50,12 +50,12 @@ Source: 2 + size([1,2]) + size([1,2]) + 1 == 7 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: size args: { - CREATE_LIST [4] { + LIST [4] { elements: { CONSTANT [5] { value: 1 } CONSTANT [6] { value: 2 } @@ -102,12 +102,12 @@ Source: size([0]) + size([0]) + size([1,2]) + size([1,2]) == 6 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: size args: { - CREATE_LIST [4] { + LIST [4] { elements: { CONSTANT [5] { value: 0 } } @@ -117,7 +117,7 @@ CALL [1] { CALL [6] { function: size args: { - CREATE_LIST [7] { + LIST [7] { elements: { CONSTANT [8] { value: 1 } CONSTANT [9] { value: 2 } @@ -168,12 +168,12 @@ Source: 5 + size([0]) + size([0]) + size([1,2]) + size([1,2]) + size([1,2,3]) + CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: size args: { - CREATE_LIST [4] { + LIST [4] { elements: { CONSTANT [5] { value: 0 } } @@ -183,7 +183,7 @@ CALL [1] { CALL [6] { function: size args: { - CREATE_LIST [7] { + LIST [7] { elements: { CONSTANT [8] { value: 1 } CONSTANT [9] { value: 2 } @@ -194,7 +194,7 @@ CALL [1] { CALL [10] { function: size args: { - CREATE_LIST [11] { + LIST [11] { elements: { CONSTANT [12] { value: 1 } CONSTANT [13] { value: 2 } @@ -271,7 +271,7 @@ Source: timestamp(int(timestamp(1000000000))).getFullYear() + timestamp(int(time CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: getFullYear @@ -465,12 +465,12 @@ Source: {"a": 2}["a"] + {"a": 2}["a"] * {"a": 2}["a"] == 6 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _[_] args: { - CREATE_MAP [4] { + MAP [4] { MAP_ENTRY [5] { key: { CONSTANT [6] { value: "a" } @@ -518,15 +518,15 @@ Source: {'a': {'b': 1}, 'c': {'b': 1}, 'd': {'e': {'b': 1}}, 'e': {'e': {'b': 1} CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_MAP [3] { + MAP [3] { MAP_ENTRY [4] { key: { CONSTANT [5] { value: "e" } } value: { - CREATE_MAP [6] { + MAP [6] { MAP_ENTRY [7] { key: { CONSTANT [8] { value: "b" } @@ -539,7 +539,7 @@ CALL [1] { } } } - CREATE_MAP [10] { + MAP [10] { MAP_ENTRY [11] { key: { CONSTANT [12] { value: "b" } @@ -551,7 +551,7 @@ CALL [1] { } } } - CREATE_MAP [14] { + MAP [14] { MAP_ENTRY [15] { key: { CONSTANT [16] { value: "a" } @@ -601,9 +601,9 @@ Source: [1, [1,2,3,4], 2, [1,2,3,4], 5, [1,2,3,4], 7, [[1,2], [1,2,3,4]], [1,2]] CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_LIST [3] { + LIST [3] { elements: { CONSTANT [4] { value: 1 } CONSTANT [5] { value: 2 } @@ -611,7 +611,7 @@ CALL [1] { CONSTANT [7] { value: 4 } } } - CREATE_LIST [8] { + LIST [8] { elements: { CONSTANT [9] { value: 1 } CONSTANT [10] { value: 2 } @@ -619,7 +619,7 @@ CALL [1] { } } } - CREATE_LIST [11] { + LIST [11] { elements: { CONSTANT [12] { value: 1 } IDENT [13] { @@ -634,7 +634,7 @@ CALL [1] { name: @index0 } CONSTANT [18] { value: 7 } - CREATE_LIST [19] { + LIST [19] { elements: { IDENT [20] { name: @index1 @@ -657,7 +657,7 @@ Source: msg.single_int64 + msg.single_int64 == 6 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -691,7 +691,7 @@ Source: msg.oneof_type.payload.single_int64 + msg.oneof_type.payload.single_int3 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -773,7 +773,7 @@ Source: true || msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.one CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -834,7 +834,7 @@ Source: msg.oneof_type.payload.map_int32_int64[1] + msg.oneof_type.payload.map_i CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _[_] @@ -886,7 +886,7 @@ Source: msg.oneof_type.payload.map_int32_int64[0] + msg.oneof_type.payload.map_i CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -950,7 +950,7 @@ Source: msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type. CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -986,7 +986,7 @@ Source: (msg.single_int64 > 0 ? msg.single_int64 : 0) == 3 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -1027,7 +1027,7 @@ Source: false ? false : (msg.single_int64) + ((msg.single_int64 + 1) * 2) == 11 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -1080,7 +1080,7 @@ Source: (msg.single_int64 > 0 ? (msg.single_int32 > 0 ? msg.single_int64 + msg.s CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -1149,17 +1149,17 @@ Source: size([[1].exists(i, i > 0)]) + size([[1].exists(j, j > 0)]) + size([[2]. CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: size args: { - CREATE_LIST [4] { + LIST [4] { elements: { COMPREHENSION [5] { iter_var: @c0:0 iter_range: { - CREATE_LIST [6] { + LIST [6] { elements: { CONSTANT [7] { value: 1 } } @@ -1216,12 +1216,12 @@ CALL [1] { CALL [18] { function: size args: { - CREATE_LIST [19] { + LIST [19] { elements: { COMPREHENSION [20] { iter_var: @c0:0 iter_range: { - CREATE_LIST [21] { + LIST [21] { elements: { CONSTANT [22] { value: 2 } } @@ -1318,14 +1318,14 @@ Source: [[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_LIST [3] { + LIST [3] { elements: { COMPREHENSION [4] { iter_var: @c0:0 iter_range: { - CREATE_LIST [5] { + LIST [5] { elements: { CONSTANT [6] { value: 1 } } @@ -1377,12 +1377,12 @@ CALL [1] { } } } - CREATE_LIST [17] { + LIST [17] { elements: { COMPREHENSION [18] { iter_var: @c0:1 iter_range: { - CREATE_LIST [19] { + LIST [19] { elements: { CONSTANT [20] { value: "a" } } @@ -1466,7 +1466,7 @@ CALL [1] { } } } - CREATE_LIST [39] { + LIST [39] { elements: { CONSTANT [40] { value: true } CONSTANT [41] { value: true } @@ -1484,23 +1484,23 @@ Source: [1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [[2, 3, 4], [2, 3, 4], [2, 3, CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_LIST [3] { + LIST [3] { elements: { CONSTANT [4] { value: 1 } CONSTANT [5] { value: 2 } CONSTANT [6] { value: 3 } } } - CREATE_LIST [7] { + LIST [7] { elements: { CONSTANT [8] { value: 2 } CONSTANT [9] { value: 3 } CONSTANT [10] { value: 4 } } } - CREATE_LIST [11] { + LIST [11] { elements: { COMPREHENSION [12] { iter_var: @c1:0 @@ -1511,7 +1511,7 @@ CALL [1] { } accu_var: @x1:0 accu_init: { - CREATE_LIST [14] { + LIST [14] { elements: { } } @@ -1526,7 +1526,7 @@ CALL [1] { IDENT [17] { name: @x1:0 } - CREATE_LIST [18] { + LIST [18] { elements: { CALL [19] { function: _+_ @@ -1564,7 +1564,7 @@ CALL [1] { } accu_var: @x0:0 accu_init: { - CREATE_LIST [26] { + LIST [26] { elements: { } } @@ -1591,7 +1591,7 @@ CALL [1] { } } } - CREATE_LIST [32] { + LIST [32] { elements: { IDENT [33] { name: @index1 @@ -1614,14 +1614,14 @@ Source: [1, 2].map(y, [1, 2, 3].filter(x, x == y)) == [[1], [2]] CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_LIST [3] { + LIST [3] { elements: { COMPREHENSION [4] { iter_var: @c1:0 iter_range: { - CREATE_LIST [5] { + LIST [5] { elements: { CONSTANT [6] { value: 1 } CONSTANT [7] { value: 2 } @@ -1631,7 +1631,7 @@ CALL [1] { } accu_var: @x1:0 accu_init: { - CREATE_LIST [9] { + LIST [9] { elements: { } } @@ -1660,7 +1660,7 @@ CALL [1] { IDENT [16] { name: @x1:0 } - CREATE_LIST [17] { + LIST [17] { elements: { IDENT [18] { name: @c1:0 @@ -1691,7 +1691,7 @@ CALL [1] { COMPREHENSION [22] { iter_var: @c0:0 iter_range: { - CREATE_LIST [23] { + LIST [23] { elements: { CONSTANT [24] { value: 1 } CONSTANT [25] { value: 2 } @@ -1700,7 +1700,7 @@ CALL [1] { } accu_var: @x0:0 accu_init: { - CREATE_LIST [26] { + LIST [26] { elements: { } } @@ -1727,14 +1727,14 @@ CALL [1] { } } } - CREATE_LIST [32] { + LIST [32] { elements: { - CREATE_LIST [33] { + LIST [33] { elements: { CONSTANT [34] { value: 1 } } } - CREATE_LIST [35] { + LIST [35] { elements: { CONSTANT [36] { value: 2 } } @@ -1751,13 +1751,13 @@ Source: 1 in [1,2,3] && 2 in [1,2,3] && 3 in [3, [1,2,3]] && 1 in [1,2,3] CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: @in args: { CONSTANT [4] { value: 1 } - CREATE_LIST [5] { + LIST [5] { elements: { CONSTANT [6] { value: 1 } CONSTANT [7] { value: 2 } @@ -1766,7 +1766,7 @@ CALL [1] { } } } - CREATE_LIST [9] { + LIST [9] { elements: { CONSTANT [10] { value: 1 } CONSTANT [11] { value: 2 } @@ -1802,7 +1802,7 @@ CALL [1] { function: @in args: { CONSTANT [21] { value: 3 } - CREATE_LIST [22] { + LIST [22] { elements: { CONSTANT [23] { value: 3 } IDENT [24] { @@ -1827,9 +1827,9 @@ Source: 2 in {'a': 1, 2: {true: false}, 3: {true: false}} CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_MAP [3] { + MAP [3] { MAP_ENTRY [4] { key: { CONSTANT [5] { value: true } @@ -1845,7 +1845,7 @@ CALL [1] { function: @in args: { CONSTANT [8] { value: 2 } - CREATE_MAP [9] { + MAP [9] { MAP_ENTRY [10] { key: { CONSTANT [11] { value: "a" } @@ -1885,17 +1885,17 @@ Source: [1,2].map(i, [1, 2].map(i, [3,4])) == [[[3, 4], [3, 4]], [[3, 4], [3, 4] CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_LIST [3] { + LIST [3] { elements: { - CREATE_LIST [4] { + LIST [4] { elements: { CONSTANT [5] { value: 3 } CONSTANT [6] { value: 4 } } } - CREATE_LIST [7] { + LIST [7] { elements: { CONSTANT [8] { value: 3 } CONSTANT [9] { value: 4 } @@ -1903,13 +1903,13 @@ CALL [1] { } } } - CREATE_LIST [10] { + LIST [10] { elements: { CONSTANT [11] { value: 1 } CONSTANT [12] { value: 2 } } } - CREATE_LIST [13] { + LIST [13] { elements: { COMPREHENSION [14] { iter_var: @c1:0 @@ -1920,7 +1920,7 @@ CALL [1] { } accu_var: @x1:0 accu_init: { - CREATE_LIST [16] { + LIST [16] { elements: { } } @@ -1935,9 +1935,9 @@ CALL [1] { IDENT [19] { name: @x1:0 } - CREATE_LIST [20] { + LIST [20] { elements: { - CREATE_LIST [21] { + LIST [21] { elements: { CONSTANT [22] { value: 3 } CONSTANT [23] { value: 4 } @@ -1970,7 +1970,7 @@ CALL [1] { } accu_var: @x0:0 accu_init: { - CREATE_LIST [28] { + LIST [28] { elements: { } } @@ -1997,7 +1997,7 @@ CALL [1] { } } } - CREATE_LIST [34] { + LIST [34] { elements: { IDENT [35] { name: @index0 @@ -2017,7 +2017,7 @@ Source: [x - 1 > 3 ? x - 1 : 5].exists(x, x - 1 > 3) || x - 1 > 3 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _>_ @@ -2042,7 +2042,7 @@ CALL [1] { COMPREHENSION [9] { iter_var: @c0:0 iter_range: { - CREATE_LIST [10] { + LIST [10] { elements: { CALL [11] { function: _?_:_ @@ -2128,7 +2128,7 @@ Source: ["foo", "bar"].map(x, [x + x, x + x]).map(x, [x + x, x + x]) CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _+_ @@ -2160,7 +2160,7 @@ CALL [1] { COMPREHENSION [10] { iter_var: @c1:0 iter_range: { - CREATE_LIST [11] { + LIST [11] { elements: { CONSTANT [12] { value: "foo" } CONSTANT [13] { value: "bar" } @@ -2169,7 +2169,7 @@ CALL [1] { } accu_var: @x1:0 accu_init: { - CREATE_LIST [14] { + LIST [14] { elements: { } } @@ -2184,9 +2184,9 @@ CALL [1] { IDENT [17] { name: @x1:0 } - CREATE_LIST [18] { + LIST [18] { elements: { - CREATE_LIST [19] { + LIST [19] { elements: { IDENT [20] { name: @index0 @@ -2210,7 +2210,7 @@ CALL [1] { } accu_var: @x0:0 accu_init: { - CREATE_LIST [23] { + LIST [23] { elements: { } } @@ -2225,9 +2225,9 @@ CALL [1] { IDENT [26] { name: @x0:0 } - CREATE_LIST [27] { + LIST [27] { elements: { - CREATE_LIST [28] { + LIST [28] { elements: { IDENT [29] { name: @index1 @@ -2256,9 +2256,9 @@ Source: has({'a': true}.a) && {'a':true}['a'] CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_MAP [3] { + MAP [3] { MAP_ENTRY [4] { key: { CONSTANT [5] { value: "a" } @@ -2297,10 +2297,10 @@ Source: has({'a': true}.a) && has({'a': true}.a) CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { - CREATE_MAP [4] { + MAP [4] { MAP_ENTRY [5] { key: { CONSTANT [6] { value: "a" } @@ -2332,7 +2332,7 @@ Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : 0) CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -2373,7 +2373,7 @@ Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : msg CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -2424,7 +2424,7 @@ Source: (has(msg.oneof_type.payload.single_int64) ? msg.oneof_type.payload.singl CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -2477,7 +2477,7 @@ Source: (has(msg.oneof_type) && has(msg.oneof_type.payload) && has(msg.oneof_typ CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -2570,9 +2570,9 @@ Source: [10, ?optional.none(), [?optional.none(), ?opt_x], [?optional.none(), ?o CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_LIST [3] { + LIST [3] { elements: { CALL [4] { function: optional.none @@ -2585,7 +2585,7 @@ CALL [1] { } optional_indices: [0, 1] } - CREATE_LIST [6] { + LIST [6] { elements: { CONSTANT [7] { value: 5 } } @@ -2595,7 +2595,7 @@ CALL [1] { CALL [8] { function: _==_ args: { - CREATE_LIST [9] { + LIST [9] { elements: { CONSTANT [10] { value: 10 } CALL [11] { @@ -2612,7 +2612,7 @@ CALL [1] { } optional_indices: [0] } - CREATE_LIST [14] { + LIST [14] { elements: { CONSTANT [15] { value: 10 } IDENT [16] { @@ -2633,12 +2633,12 @@ Source: {?'hello': optional.of('hello')}['hello'] + {?'hello': optional.of('hell CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _[_] args: { - CREATE_MAP [4] { + MAP [4] { MAP_ENTRY [5] { key: { CONSTANT [6] { value: "hello" } @@ -2684,9 +2684,9 @@ Source: {?'key': optional.of('test')}[?'bogus'].or({'key': 'test'}[?'bogus']).or CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_MAP [3] { + MAP [3] { MAP_ENTRY [4] { key: { CONSTANT [5] { value: "key" } @@ -2705,7 +2705,7 @@ CALL [1] { CALL [9] { function: _[?_] args: { - CREATE_MAP [10] { + MAP [10] { MAP_ENTRY [11] { key: { CONSTANT [12] { value: "key" } @@ -2769,9 +2769,9 @@ Source: TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: o CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_STRUCT [3] { + STRUCT [3] { name: TestAllTypes entries: { ENTRY [4] { @@ -2831,7 +2831,7 @@ Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('h' + 'e' + 'l' + 'l' + CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _+_ @@ -2923,7 +2923,7 @@ Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('hello') CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _+_ @@ -2977,7 +2977,7 @@ Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('w' + 'o' + 'r' + 'l' + CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _+_ @@ -3055,7 +3055,7 @@ Source: non_pure_custom_func(msg.oneof_type.payload.single_int64) + non_pure_cus CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -3131,7 +3131,7 @@ Source: pure_custom_func(msg.oneof_type.payload.single_int64) + pure_custom_func CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: pure_custom_func diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_6.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_6.baseline index affa76d8c..0612d72aa 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_6.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_6.baseline @@ -4,12 +4,12 @@ Source: size([1,2]) + size([1,2]) + 1 == 5 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: size args: { - CREATE_LIST [4] { + LIST [4] { elements: { CONSTANT [5] { value: 1 } CONSTANT [6] { value: 2 } @@ -50,12 +50,12 @@ Source: 2 + size([1,2]) + size([1,2]) + 1 == 7 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: size args: { - CREATE_LIST [4] { + LIST [4] { elements: { CONSTANT [5] { value: 1 } CONSTANT [6] { value: 2 } @@ -102,12 +102,12 @@ Source: size([0]) + size([0]) + size([1,2]) + size([1,2]) == 6 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: size args: { - CREATE_LIST [4] { + LIST [4] { elements: { CONSTANT [5] { value: 0 } } @@ -117,7 +117,7 @@ CALL [1] { CALL [6] { function: size args: { - CREATE_LIST [7] { + LIST [7] { elements: { CONSTANT [8] { value: 1 } CONSTANT [9] { value: 2 } @@ -168,12 +168,12 @@ Source: 5 + size([0]) + size([0]) + size([1,2]) + size([1,2]) + size([1,2,3]) + CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: size args: { - CREATE_LIST [4] { + LIST [4] { elements: { CONSTANT [5] { value: 0 } } @@ -183,7 +183,7 @@ CALL [1] { CALL [6] { function: size args: { - CREATE_LIST [7] { + LIST [7] { elements: { CONSTANT [8] { value: 1 } CONSTANT [9] { value: 2 } @@ -194,7 +194,7 @@ CALL [1] { CALL [10] { function: size args: { - CREATE_LIST [11] { + LIST [11] { elements: { CONSTANT [12] { value: 1 } CONSTANT [13] { value: 2 } @@ -271,7 +271,7 @@ Source: timestamp(int(timestamp(1000000000))).getFullYear() + timestamp(int(time CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: getFullYear @@ -465,12 +465,12 @@ Source: {"a": 2}["a"] + {"a": 2}["a"] * {"a": 2}["a"] == 6 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _[_] args: { - CREATE_MAP [4] { + MAP [4] { MAP_ENTRY [5] { key: { CONSTANT [6] { value: "a" } @@ -518,15 +518,15 @@ Source: {'a': {'b': 1}, 'c': {'b': 1}, 'd': {'e': {'b': 1}}, 'e': {'e': {'b': 1} CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_MAP [3] { + MAP [3] { MAP_ENTRY [4] { key: { CONSTANT [5] { value: "e" } } value: { - CREATE_MAP [6] { + MAP [6] { MAP_ENTRY [7] { key: { CONSTANT [8] { value: "b" } @@ -539,7 +539,7 @@ CALL [1] { } } } - CREATE_MAP [10] { + MAP [10] { MAP_ENTRY [11] { key: { CONSTANT [12] { value: "b" } @@ -551,7 +551,7 @@ CALL [1] { } } } - CREATE_MAP [14] { + MAP [14] { MAP_ENTRY [15] { key: { CONSTANT [16] { value: "a" } @@ -601,9 +601,9 @@ Source: [1, [1,2,3,4], 2, [1,2,3,4], 5, [1,2,3,4], 7, [[1,2], [1,2,3,4]], [1,2]] CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_LIST [3] { + LIST [3] { elements: { CONSTANT [4] { value: 1 } CONSTANT [5] { value: 2 } @@ -611,7 +611,7 @@ CALL [1] { CONSTANT [7] { value: 4 } } } - CREATE_LIST [8] { + LIST [8] { elements: { CONSTANT [9] { value: 1 } CONSTANT [10] { value: 2 } @@ -619,7 +619,7 @@ CALL [1] { } } } - CREATE_LIST [11] { + LIST [11] { elements: { CONSTANT [12] { value: 1 } IDENT [13] { @@ -634,7 +634,7 @@ CALL [1] { name: @index0 } CONSTANT [18] { value: 7 } - CREATE_LIST [19] { + LIST [19] { elements: { IDENT [20] { name: @index1 @@ -657,7 +657,7 @@ Source: msg.single_int64 + msg.single_int64 == 6 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -691,7 +691,7 @@ Source: msg.oneof_type.payload.single_int64 + msg.oneof_type.payload.single_int3 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -770,7 +770,7 @@ Source: true || msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.one CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -828,7 +828,7 @@ Source: msg.oneof_type.payload.map_int32_int64[1] + msg.oneof_type.payload.map_i CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _[_] @@ -880,7 +880,7 @@ Source: msg.oneof_type.payload.map_int32_int64[0] + msg.oneof_type.payload.map_i CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -944,7 +944,7 @@ Source: msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type. CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -980,7 +980,7 @@ Source: (msg.single_int64 > 0 ? msg.single_int64 : 0) == 3 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -1021,7 +1021,7 @@ Source: false ? false : (msg.single_int64) + ((msg.single_int64 + 1) * 2) == 11 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -1074,7 +1074,7 @@ Source: (msg.single_int64 > 0 ? (msg.single_int32 > 0 ? msg.single_int64 + msg.s CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -1143,17 +1143,17 @@ Source: size([[1].exists(i, i > 0)]) + size([[1].exists(j, j > 0)]) + size([[2]. CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: size args: { - CREATE_LIST [4] { + LIST [4] { elements: { COMPREHENSION [5] { iter_var: @c0:0 iter_range: { - CREATE_LIST [6] { + LIST [6] { elements: { CONSTANT [7] { value: 1 } } @@ -1210,12 +1210,12 @@ CALL [1] { CALL [18] { function: size args: { - CREATE_LIST [19] { + LIST [19] { elements: { COMPREHENSION [20] { iter_var: @c0:0 iter_range: { - CREATE_LIST [21] { + LIST [21] { elements: { CONSTANT [22] { value: 2 } } @@ -1312,14 +1312,14 @@ Source: [[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_LIST [3] { + LIST [3] { elements: { COMPREHENSION [4] { iter_var: @c0:0 iter_range: { - CREATE_LIST [5] { + LIST [5] { elements: { CONSTANT [6] { value: 1 } } @@ -1371,12 +1371,12 @@ CALL [1] { } } } - CREATE_LIST [17] { + LIST [17] { elements: { COMPREHENSION [18] { iter_var: @c0:1 iter_range: { - CREATE_LIST [19] { + LIST [19] { elements: { CONSTANT [20] { value: "a" } } @@ -1460,7 +1460,7 @@ CALL [1] { } } } - CREATE_LIST [39] { + LIST [39] { elements: { CONSTANT [40] { value: true } CONSTANT [41] { value: true } @@ -1478,16 +1478,16 @@ Source: [1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [[2, 3, 4], [2, 3, 4], [2, 3, CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_LIST [3] { + LIST [3] { elements: { CONSTANT [4] { value: 1 } CONSTANT [5] { value: 2 } CONSTANT [6] { value: 3 } } } - CREATE_LIST [7] { + LIST [7] { elements: { CONSTANT [8] { value: 2 } CONSTANT [9] { value: 3 } @@ -1500,7 +1500,7 @@ CALL [1] { IDENT [12] { name: @x0:0 } - CREATE_LIST [13] { + LIST [13] { elements: { COMPREHENSION [14] { iter_var: @c1:0 @@ -1511,7 +1511,7 @@ CALL [1] { } accu_var: @x1:0 accu_init: { - CREATE_LIST [16] { + LIST [16] { elements: { } } @@ -1526,7 +1526,7 @@ CALL [1] { IDENT [19] { name: @x1:0 } - CREATE_LIST [20] { + LIST [20] { elements: { CALL [21] { function: _+_ @@ -1566,7 +1566,7 @@ CALL [1] { } accu_var: @x0:0 accu_init: { - CREATE_LIST [28] { + LIST [28] { elements: { } } @@ -1585,7 +1585,7 @@ CALL [1] { } } } - CREATE_LIST [32] { + LIST [32] { elements: { IDENT [33] { name: @index1 @@ -1608,7 +1608,7 @@ Source: [1, 2].map(y, [1, 2, 3].filter(x, x == y)) == [[1], [2]] CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _+_ @@ -1616,12 +1616,12 @@ CALL [1] { IDENT [4] { name: @x0:0 } - CREATE_LIST [5] { + LIST [5] { elements: { COMPREHENSION [6] { iter_var: @c1:0 iter_range: { - CREATE_LIST [7] { + LIST [7] { elements: { CONSTANT [8] { value: 1 } CONSTANT [9] { value: 2 } @@ -1631,7 +1631,7 @@ CALL [1] { } accu_var: @x1:0 accu_init: { - CREATE_LIST [11] { + LIST [11] { elements: { } } @@ -1660,7 +1660,7 @@ CALL [1] { IDENT [18] { name: @x1:0 } - CREATE_LIST [19] { + LIST [19] { elements: { IDENT [20] { name: @c1:0 @@ -1693,7 +1693,7 @@ CALL [1] { COMPREHENSION [24] { iter_var: @c0:0 iter_range: { - CREATE_LIST [25] { + LIST [25] { elements: { CONSTANT [26] { value: 1 } CONSTANT [27] { value: 2 } @@ -1702,7 +1702,7 @@ CALL [1] { } accu_var: @x0:0 accu_init: { - CREATE_LIST [28] { + LIST [28] { elements: { } } @@ -1721,14 +1721,14 @@ CALL [1] { } } } - CREATE_LIST [32] { + LIST [32] { elements: { - CREATE_LIST [33] { + LIST [33] { elements: { CONSTANT [34] { value: 1 } } } - CREATE_LIST [35] { + LIST [35] { elements: { CONSTANT [36] { value: 2 } } @@ -1745,13 +1745,13 @@ Source: 1 in [1,2,3] && 2 in [1,2,3] && 3 in [3, [1,2,3]] && 1 in [1,2,3] CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: @in args: { CONSTANT [4] { value: 1 } - CREATE_LIST [5] { + LIST [5] { elements: { CONSTANT [6] { value: 1 } CONSTANT [7] { value: 2 } @@ -1760,7 +1760,7 @@ CALL [1] { } } } - CREATE_LIST [9] { + LIST [9] { elements: { CONSTANT [10] { value: 1 } CONSTANT [11] { value: 2 } @@ -1796,7 +1796,7 @@ CALL [1] { function: @in args: { CONSTANT [21] { value: 3 } - CREATE_LIST [22] { + LIST [22] { elements: { CONSTANT [23] { value: 3 } IDENT [24] { @@ -1821,9 +1821,9 @@ Source: 2 in {'a': 1, 2: {true: false}, 3: {true: false}} CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_MAP [3] { + MAP [3] { MAP_ENTRY [4] { key: { CONSTANT [5] { value: true } @@ -1839,7 +1839,7 @@ CALL [1] { function: @in args: { CONSTANT [8] { value: 2 } - CREATE_MAP [9] { + MAP [9] { MAP_ENTRY [10] { key: { CONSTANT [11] { value: "a" } @@ -1879,17 +1879,17 @@ Source: [1,2].map(i, [1, 2].map(i, [3,4])) == [[[3, 4], [3, 4]], [[3, 4], [3, 4] CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_LIST [3] { + LIST [3] { elements: { - CREATE_LIST [4] { + LIST [4] { elements: { CONSTANT [5] { value: 3 } CONSTANT [6] { value: 4 } } } - CREATE_LIST [7] { + LIST [7] { elements: { CONSTANT [8] { value: 3 } CONSTANT [9] { value: 4 } @@ -1897,7 +1897,7 @@ CALL [1] { } } } - CREATE_LIST [10] { + LIST [10] { elements: { CONSTANT [11] { value: 1 } CONSTANT [12] { value: 2 } @@ -1909,7 +1909,7 @@ CALL [1] { IDENT [14] { name: @x0:0 } - CREATE_LIST [15] { + LIST [15] { elements: { COMPREHENSION [16] { iter_var: @c1:0 @@ -1920,7 +1920,7 @@ CALL [1] { } accu_var: @x1:0 accu_init: { - CREATE_LIST [18] { + LIST [18] { elements: { } } @@ -1935,9 +1935,9 @@ CALL [1] { IDENT [21] { name: @x1:0 } - CREATE_LIST [22] { + LIST [22] { elements: { - CREATE_LIST [23] { + LIST [23] { elements: { CONSTANT [24] { value: 3 } CONSTANT [25] { value: 4 } @@ -1972,7 +1972,7 @@ CALL [1] { } accu_var: @x0:0 accu_init: { - CREATE_LIST [30] { + LIST [30] { elements: { } } @@ -1991,7 +1991,7 @@ CALL [1] { } } } - CREATE_LIST [34] { + LIST [34] { elements: { IDENT [35] { name: @index0 @@ -2011,7 +2011,7 @@ Source: [x - 1 > 3 ? x - 1 : 5].exists(x, x - 1 > 3) || x - 1 > 3 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _>_ @@ -2036,7 +2036,7 @@ CALL [1] { COMPREHENSION [9] { iter_var: @c0:0 iter_range: { - CREATE_LIST [10] { + LIST [10] { elements: { CALL [11] { function: _?_:_ @@ -2122,7 +2122,7 @@ Source: ["foo", "bar"].map(x, [x + x, x + x]).map(x, [x + x, x + x]) CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _+_ @@ -2154,7 +2154,7 @@ CALL [1] { COMPREHENSION [10] { iter_var: @c1:0 iter_range: { - CREATE_LIST [11] { + LIST [11] { elements: { CONSTANT [12] { value: "foo" } CONSTANT [13] { value: "bar" } @@ -2163,7 +2163,7 @@ CALL [1] { } accu_var: @x1:0 accu_init: { - CREATE_LIST [14] { + LIST [14] { elements: { } } @@ -2178,9 +2178,9 @@ CALL [1] { IDENT [17] { name: @x1:0 } - CREATE_LIST [18] { + LIST [18] { elements: { - CREATE_LIST [19] { + LIST [19] { elements: { IDENT [20] { name: @index0 @@ -2204,7 +2204,7 @@ CALL [1] { } accu_var: @x0:0 accu_init: { - CREATE_LIST [23] { + LIST [23] { elements: { } } @@ -2219,9 +2219,9 @@ CALL [1] { IDENT [26] { name: @x0:0 } - CREATE_LIST [27] { + LIST [27] { elements: { - CREATE_LIST [28] { + LIST [28] { elements: { IDENT [29] { name: @index1 @@ -2250,9 +2250,9 @@ Source: has({'a': true}.a) && {'a':true}['a'] CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_MAP [3] { + MAP [3] { MAP_ENTRY [4] { key: { CONSTANT [5] { value: "a" } @@ -2291,10 +2291,10 @@ Source: has({'a': true}.a) && has({'a': true}.a) CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { - CREATE_MAP [4] { + MAP [4] { MAP_ENTRY [5] { key: { CONSTANT [6] { value: "a" } @@ -2326,7 +2326,7 @@ Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : 0) CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -2367,7 +2367,7 @@ Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : msg CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -2418,7 +2418,7 @@ Source: (has(msg.oneof_type.payload.single_int64) ? msg.oneof_type.payload.singl CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -2471,7 +2471,7 @@ Source: (has(msg.oneof_type) && has(msg.oneof_type.payload) && has(msg.oneof_typ CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -2564,9 +2564,9 @@ Source: [10, ?optional.none(), [?optional.none(), ?opt_x], [?optional.none(), ?o CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_LIST [3] { + LIST [3] { elements: { CALL [4] { function: optional.none @@ -2579,7 +2579,7 @@ CALL [1] { } optional_indices: [0, 1] } - CREATE_LIST [6] { + LIST [6] { elements: { CONSTANT [7] { value: 5 } } @@ -2589,7 +2589,7 @@ CALL [1] { CALL [8] { function: _==_ args: { - CREATE_LIST [9] { + LIST [9] { elements: { CONSTANT [10] { value: 10 } CALL [11] { @@ -2606,7 +2606,7 @@ CALL [1] { } optional_indices: [0] } - CREATE_LIST [14] { + LIST [14] { elements: { CONSTANT [15] { value: 10 } IDENT [16] { @@ -2627,12 +2627,12 @@ Source: {?'hello': optional.of('hello')}['hello'] + {?'hello': optional.of('hell CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _[_] args: { - CREATE_MAP [4] { + MAP [4] { MAP_ENTRY [5] { key: { CONSTANT [6] { value: "hello" } @@ -2678,9 +2678,9 @@ Source: {?'key': optional.of('test')}[?'bogus'].or({'key': 'test'}[?'bogus']).or CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_MAP [3] { + MAP [3] { MAP_ENTRY [4] { key: { CONSTANT [5] { value: "key" } @@ -2704,7 +2704,7 @@ CALL [1] { CALL [10] { function: _[?_] args: { - CREATE_MAP [11] { + MAP [11] { MAP_ENTRY [12] { key: { CONSTANT [13] { value: "key" } @@ -2760,9 +2760,9 @@ Source: TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: o CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_STRUCT [3] { + STRUCT [3] { name: TestAllTypes entries: { ENTRY [4] { @@ -2822,7 +2822,7 @@ Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('h' + 'e' + 'l' + 'l' + CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _+_ @@ -3022,7 +3022,7 @@ Source: non_pure_custom_func(msg.oneof_type.payload.single_int64) + non_pure_cus CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -3098,7 +3098,7 @@ Source: pure_custom_func(msg.oneof_type.payload.single_int64) + pure_custom_func CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: pure_custom_func diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_7.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_7.baseline index d962803ee..eee2b9b4a 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_7.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_7.baseline @@ -4,12 +4,12 @@ Source: size([1,2]) + size([1,2]) + 1 == 5 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: size args: { - CREATE_LIST [4] { + LIST [4] { elements: { CONSTANT [5] { value: 1 } CONSTANT [6] { value: 2 } @@ -50,12 +50,12 @@ Source: 2 + size([1,2]) + size([1,2]) + 1 == 7 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: size args: { - CREATE_LIST [4] { + LIST [4] { elements: { CONSTANT [5] { value: 1 } CONSTANT [6] { value: 2 } @@ -102,12 +102,12 @@ Source: size([0]) + size([0]) + size([1,2]) + size([1,2]) == 6 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: size args: { - CREATE_LIST [4] { + LIST [4] { elements: { CONSTANT [5] { value: 0 } } @@ -117,7 +117,7 @@ CALL [1] { CALL [6] { function: size args: { - CREATE_LIST [7] { + LIST [7] { elements: { CONSTANT [8] { value: 1 } CONSTANT [9] { value: 2 } @@ -168,12 +168,12 @@ Source: 5 + size([0]) + size([0]) + size([1,2]) + size([1,2]) + size([1,2,3]) + CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: size args: { - CREATE_LIST [4] { + LIST [4] { elements: { CONSTANT [5] { value: 0 } } @@ -183,7 +183,7 @@ CALL [1] { CALL [6] { function: size args: { - CREATE_LIST [7] { + LIST [7] { elements: { CONSTANT [8] { value: 1 } CONSTANT [9] { value: 2 } @@ -194,7 +194,7 @@ CALL [1] { CALL [10] { function: size args: { - CREATE_LIST [11] { + LIST [11] { elements: { CONSTANT [12] { value: 1 } CONSTANT [13] { value: 2 } @@ -268,7 +268,7 @@ Source: timestamp(int(timestamp(1000000000))).getFullYear() + timestamp(int(time CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: getFullYear @@ -462,12 +462,12 @@ Source: {"a": 2}["a"] + {"a": 2}["a"] * {"a": 2}["a"] == 6 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _[_] args: { - CREATE_MAP [4] { + MAP [4] { MAP_ENTRY [5] { key: { CONSTANT [6] { value: "a" } @@ -515,15 +515,15 @@ Source: {'a': {'b': 1}, 'c': {'b': 1}, 'd': {'e': {'b': 1}}, 'e': {'e': {'b': 1} CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_MAP [3] { + MAP [3] { MAP_ENTRY [4] { key: { CONSTANT [5] { value: "e" } } value: { - CREATE_MAP [6] { + MAP [6] { MAP_ENTRY [7] { key: { CONSTANT [8] { value: "b" } @@ -536,7 +536,7 @@ CALL [1] { } } } - CREATE_MAP [10] { + MAP [10] { MAP_ENTRY [11] { key: { CONSTANT [12] { value: "b" } @@ -548,7 +548,7 @@ CALL [1] { } } } - CREATE_MAP [14] { + MAP [14] { MAP_ENTRY [15] { key: { CONSTANT [16] { value: "a" } @@ -598,9 +598,9 @@ Source: [1, [1,2,3,4], 2, [1,2,3,4], 5, [1,2,3,4], 7, [[1,2], [1,2,3,4]], [1,2]] CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_LIST [3] { + LIST [3] { elements: { CONSTANT [4] { value: 1 } CONSTANT [5] { value: 2 } @@ -608,7 +608,7 @@ CALL [1] { CONSTANT [7] { value: 4 } } } - CREATE_LIST [8] { + LIST [8] { elements: { CONSTANT [9] { value: 1 } CONSTANT [10] { value: 2 } @@ -616,7 +616,7 @@ CALL [1] { } } } - CREATE_LIST [11] { + LIST [11] { elements: { CONSTANT [12] { value: 1 } IDENT [13] { @@ -631,7 +631,7 @@ CALL [1] { name: @index0 } CONSTANT [18] { value: 7 } - CREATE_LIST [19] { + LIST [19] { elements: { IDENT [20] { name: @index1 @@ -654,7 +654,7 @@ Source: msg.single_int64 + msg.single_int64 == 6 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -688,7 +688,7 @@ Source: msg.oneof_type.payload.single_int64 + msg.oneof_type.payload.single_int3 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -767,7 +767,7 @@ Source: true || msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.one CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -825,7 +825,7 @@ Source: msg.oneof_type.payload.map_int32_int64[1] + msg.oneof_type.payload.map_i CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _[_] @@ -877,7 +877,7 @@ Source: msg.oneof_type.payload.map_int32_int64[0] + msg.oneof_type.payload.map_i CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -941,7 +941,7 @@ Source: msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type. CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -977,7 +977,7 @@ Source: (msg.single_int64 > 0 ? msg.single_int64 : 0) == 3 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -1018,7 +1018,7 @@ Source: false ? false : (msg.single_int64) + ((msg.single_int64 + 1) * 2) == 11 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -1071,7 +1071,7 @@ Source: (msg.single_int64 > 0 ? (msg.single_int32 > 0 ? msg.single_int64 + msg.s CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -1140,17 +1140,17 @@ Source: size([[1].exists(i, i > 0)]) + size([[1].exists(j, j > 0)]) + size([[2]. CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: size args: { - CREATE_LIST [4] { + LIST [4] { elements: { COMPREHENSION [5] { iter_var: @c0:0 iter_range: { - CREATE_LIST [6] { + LIST [6] { elements: { CONSTANT [7] { value: 1 } } @@ -1207,12 +1207,12 @@ CALL [1] { CALL [18] { function: size args: { - CREATE_LIST [19] { + LIST [19] { elements: { COMPREHENSION [20] { iter_var: @c0:0 iter_range: { - CREATE_LIST [21] { + LIST [21] { elements: { CONSTANT [22] { value: 2 } } @@ -1309,14 +1309,14 @@ Source: [[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_LIST [3] { + LIST [3] { elements: { COMPREHENSION [4] { iter_var: @c0:0 iter_range: { - CREATE_LIST [5] { + LIST [5] { elements: { CONSTANT [6] { value: 1 } } @@ -1368,12 +1368,12 @@ CALL [1] { } } } - CREATE_LIST [17] { + LIST [17] { elements: { COMPREHENSION [18] { iter_var: @c0:1 iter_range: { - CREATE_LIST [19] { + LIST [19] { elements: { CONSTANT [20] { value: "a" } } @@ -1457,7 +1457,7 @@ CALL [1] { } } } - CREATE_LIST [39] { + LIST [39] { elements: { CONSTANT [40] { value: true } CONSTANT [41] { value: true } @@ -1475,16 +1475,16 @@ Source: [1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [[2, 3, 4], [2, 3, 4], [2, 3, CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_LIST [3] { + LIST [3] { elements: { CONSTANT [4] { value: 1 } CONSTANT [5] { value: 2 } CONSTANT [6] { value: 3 } } } - CREATE_LIST [7] { + LIST [7] { elements: { CONSTANT [8] { value: 2 } CONSTANT [9] { value: 3 } @@ -1500,7 +1500,7 @@ CALL [1] { } accu_var: @x0:0 accu_init: { - CREATE_LIST [13] { + LIST [13] { elements: { } } @@ -1515,7 +1515,7 @@ CALL [1] { IDENT [16] { name: @x0:0 } - CREATE_LIST [17] { + LIST [17] { elements: { COMPREHENSION [18] { iter_var: @c1:0 @@ -1526,7 +1526,7 @@ CALL [1] { } accu_var: @x1:0 accu_init: { - CREATE_LIST [20] { + LIST [20] { elements: { } } @@ -1541,7 +1541,7 @@ CALL [1] { IDENT [23] { name: @x1:0 } - CREATE_LIST [24] { + LIST [24] { elements: { CALL [25] { function: _+_ @@ -1582,7 +1582,7 @@ CALL [1] { IDENT [31] { name: @index2 } - CREATE_LIST [32] { + LIST [32] { elements: { IDENT [33] { name: @index1 @@ -1605,12 +1605,12 @@ Source: [1, 2].map(y, [1, 2, 3].filter(x, x == y)) == [[1], [2]] CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { COMPREHENSION [3] { iter_var: @c0:0 iter_range: { - CREATE_LIST [4] { + LIST [4] { elements: { CONSTANT [5] { value: 1 } CONSTANT [6] { value: 2 } @@ -1619,7 +1619,7 @@ CALL [1] { } accu_var: @x0:0 accu_init: { - CREATE_LIST [7] { + LIST [7] { elements: { } } @@ -1634,12 +1634,12 @@ CALL [1] { IDENT [10] { name: @x0:0 } - CREATE_LIST [11] { + LIST [11] { elements: { COMPREHENSION [12] { iter_var: @c1:0 iter_range: { - CREATE_LIST [13] { + LIST [13] { elements: { CONSTANT [14] { value: 1 } CONSTANT [15] { value: 2 } @@ -1649,7 +1649,7 @@ CALL [1] { } accu_var: @x1:0 accu_init: { - CREATE_LIST [17] { + LIST [17] { elements: { } } @@ -1678,7 +1678,7 @@ CALL [1] { IDENT [24] { name: @x1:0 } - CREATE_LIST [25] { + LIST [25] { elements: { IDENT [26] { name: @c1:0 @@ -1718,14 +1718,14 @@ CALL [1] { IDENT [31] { name: @index0 } - CREATE_LIST [32] { + LIST [32] { elements: { - CREATE_LIST [33] { + LIST [33] { elements: { CONSTANT [34] { value: 1 } } } - CREATE_LIST [35] { + LIST [35] { elements: { CONSTANT [36] { value: 2 } } @@ -1742,13 +1742,13 @@ Source: 1 in [1,2,3] && 2 in [1,2,3] && 3 in [3, [1,2,3]] && 1 in [1,2,3] CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: @in args: { CONSTANT [4] { value: 1 } - CREATE_LIST [5] { + LIST [5] { elements: { CONSTANT [6] { value: 1 } CONSTANT [7] { value: 2 } @@ -1757,7 +1757,7 @@ CALL [1] { } } } - CREATE_LIST [9] { + LIST [9] { elements: { CONSTANT [10] { value: 1 } CONSTANT [11] { value: 2 } @@ -1793,7 +1793,7 @@ CALL [1] { function: @in args: { CONSTANT [21] { value: 3 } - CREATE_LIST [22] { + LIST [22] { elements: { CONSTANT [23] { value: 3 } IDENT [24] { @@ -1818,9 +1818,9 @@ Source: 2 in {'a': 1, 2: {true: false}, 3: {true: false}} CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_MAP [3] { + MAP [3] { MAP_ENTRY [4] { key: { CONSTANT [5] { value: true } @@ -1836,7 +1836,7 @@ CALL [1] { function: @in args: { CONSTANT [8] { value: 2 } - CREATE_MAP [9] { + MAP [9] { MAP_ENTRY [10] { key: { CONSTANT [11] { value: "a" } @@ -1876,17 +1876,17 @@ Source: [1,2].map(i, [1, 2].map(i, [3,4])) == [[[3, 4], [3, 4]], [[3, 4], [3, 4] CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_LIST [3] { + LIST [3] { elements: { - CREATE_LIST [4] { + LIST [4] { elements: { CONSTANT [5] { value: 3 } CONSTANT [6] { value: 4 } } } - CREATE_LIST [7] { + LIST [7] { elements: { CONSTANT [8] { value: 3 } CONSTANT [9] { value: 4 } @@ -1894,7 +1894,7 @@ CALL [1] { } } } - CREATE_LIST [10] { + LIST [10] { elements: { CONSTANT [11] { value: 1 } CONSTANT [12] { value: 2 } @@ -1909,7 +1909,7 @@ CALL [1] { } accu_var: @x0:0 accu_init: { - CREATE_LIST [15] { + LIST [15] { elements: { } } @@ -1924,7 +1924,7 @@ CALL [1] { IDENT [18] { name: @x0:0 } - CREATE_LIST [19] { + LIST [19] { elements: { COMPREHENSION [20] { iter_var: @c1:0 @@ -1935,7 +1935,7 @@ CALL [1] { } accu_var: @x1:0 accu_init: { - CREATE_LIST [22] { + LIST [22] { elements: { } } @@ -1950,9 +1950,9 @@ CALL [1] { IDENT [25] { name: @x1:0 } - CREATE_LIST [26] { + LIST [26] { elements: { - CREATE_LIST [27] { + LIST [27] { elements: { CONSTANT [28] { value: 3 } CONSTANT [29] { value: 4 } @@ -1988,7 +1988,7 @@ CALL [1] { IDENT [33] { name: @index2 } - CREATE_LIST [34] { + LIST [34] { elements: { IDENT [35] { name: @index0 @@ -2008,7 +2008,7 @@ Source: [x - 1 > 3 ? x - 1 : 5].exists(x, x - 1 > 3) || x - 1 > 3 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _>_ @@ -2033,7 +2033,7 @@ CALL [1] { COMPREHENSION [9] { iter_var: @c0:0 iter_range: { - CREATE_LIST [10] { + LIST [10] { elements: { CALL [11] { function: _?_:_ @@ -2119,7 +2119,7 @@ Source: ["foo", "bar"].map(x, [x + x, x + x]).map(x, [x + x, x + x]) CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _+_ @@ -2151,7 +2151,7 @@ CALL [1] { COMPREHENSION [10] { iter_var: @c1:0 iter_range: { - CREATE_LIST [11] { + LIST [11] { elements: { CONSTANT [12] { value: "foo" } CONSTANT [13] { value: "bar" } @@ -2160,7 +2160,7 @@ CALL [1] { } accu_var: @x1:0 accu_init: { - CREATE_LIST [14] { + LIST [14] { elements: { } } @@ -2175,9 +2175,9 @@ CALL [1] { IDENT [17] { name: @x1:0 } - CREATE_LIST [18] { + LIST [18] { elements: { - CREATE_LIST [19] { + LIST [19] { elements: { IDENT [20] { name: @index0 @@ -2201,7 +2201,7 @@ CALL [1] { } accu_var: @x0:0 accu_init: { - CREATE_LIST [23] { + LIST [23] { elements: { } } @@ -2216,9 +2216,9 @@ CALL [1] { IDENT [26] { name: @x0:0 } - CREATE_LIST [27] { + LIST [27] { elements: { - CREATE_LIST [28] { + LIST [28] { elements: { IDENT [29] { name: @index1 @@ -2247,9 +2247,9 @@ Source: has({'a': true}.a) && {'a':true}['a'] CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_MAP [3] { + MAP [3] { MAP_ENTRY [4] { key: { CONSTANT [5] { value: "a" } @@ -2288,10 +2288,10 @@ Source: has({'a': true}.a) && has({'a': true}.a) CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { - CREATE_MAP [4] { + MAP [4] { MAP_ENTRY [5] { key: { CONSTANT [6] { value: "a" } @@ -2323,7 +2323,7 @@ Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : 0) CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -2364,7 +2364,7 @@ Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : msg CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -2415,7 +2415,7 @@ Source: (has(msg.oneof_type.payload.single_int64) ? msg.oneof_type.payload.singl CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -2468,7 +2468,7 @@ Source: (has(msg.oneof_type) && has(msg.oneof_type.payload) && has(msg.oneof_typ CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -2561,9 +2561,9 @@ Source: [10, ?optional.none(), [?optional.none(), ?opt_x], [?optional.none(), ?o CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_LIST [3] { + LIST [3] { elements: { CALL [4] { function: optional.none @@ -2576,7 +2576,7 @@ CALL [1] { } optional_indices: [0, 1] } - CREATE_LIST [6] { + LIST [6] { elements: { CONSTANT [7] { value: 5 } } @@ -2586,7 +2586,7 @@ CALL [1] { CALL [8] { function: _==_ args: { - CREATE_LIST [9] { + LIST [9] { elements: { CONSTANT [10] { value: 10 } CALL [11] { @@ -2603,7 +2603,7 @@ CALL [1] { } optional_indices: [0] } - CREATE_LIST [14] { + LIST [14] { elements: { CONSTANT [15] { value: 10 } IDENT [16] { @@ -2624,12 +2624,12 @@ Source: {?'hello': optional.of('hello')}['hello'] + {?'hello': optional.of('hell CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _[_] args: { - CREATE_MAP [4] { + MAP [4] { MAP_ENTRY [5] { key: { CONSTANT [6] { value: "hello" } @@ -2675,9 +2675,9 @@ Source: {?'key': optional.of('test')}[?'bogus'].or({'key': 'test'}[?'bogus']).or CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_MAP [3] { + MAP [3] { MAP_ENTRY [4] { key: { CONSTANT [5] { value: "key" } @@ -2701,7 +2701,7 @@ CALL [1] { CALL [10] { function: _[?_] args: { - CREATE_MAP [11] { + MAP [11] { MAP_ENTRY [12] { key: { CONSTANT [13] { value: "key" } @@ -2757,9 +2757,9 @@ Source: TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: o CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_STRUCT [3] { + STRUCT [3] { name: TestAllTypes entries: { ENTRY [4] { @@ -2819,7 +2819,7 @@ Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('h' + 'e' + 'l' + 'l' + CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _+_ @@ -3019,7 +3019,7 @@ Source: non_pure_custom_func(msg.oneof_type.payload.single_int64) + non_pure_cus CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -3095,7 +3095,7 @@ Source: pure_custom_func(msg.oneof_type.payload.single_int64) + pure_custom_func CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: pure_custom_func diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_8.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_8.baseline index feab00f27..8e9897902 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_8.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_8.baseline @@ -4,12 +4,12 @@ Source: size([1,2]) + size([1,2]) + 1 == 5 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: size args: { - CREATE_LIST [4] { + LIST [4] { elements: { CONSTANT [5] { value: 1 } CONSTANT [6] { value: 2 } @@ -50,12 +50,12 @@ Source: 2 + size([1,2]) + size([1,2]) + 1 == 7 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: size args: { - CREATE_LIST [4] { + LIST [4] { elements: { CONSTANT [5] { value: 1 } CONSTANT [6] { value: 2 } @@ -102,12 +102,12 @@ Source: size([0]) + size([0]) + size([1,2]) + size([1,2]) == 6 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: size args: { - CREATE_LIST [4] { + LIST [4] { elements: { CONSTANT [5] { value: 0 } } @@ -117,7 +117,7 @@ CALL [1] { CALL [6] { function: size args: { - CREATE_LIST [7] { + LIST [7] { elements: { CONSTANT [8] { value: 1 } CONSTANT [9] { value: 2 } @@ -168,12 +168,12 @@ Source: 5 + size([0]) + size([0]) + size([1,2]) + size([1,2]) + size([1,2,3]) + CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: size args: { - CREATE_LIST [4] { + LIST [4] { elements: { CONSTANT [5] { value: 0 } } @@ -183,7 +183,7 @@ CALL [1] { CALL [6] { function: size args: { - CREATE_LIST [7] { + LIST [7] { elements: { CONSTANT [8] { value: 1 } CONSTANT [9] { value: 2 } @@ -194,7 +194,7 @@ CALL [1] { CALL [10] { function: size args: { - CREATE_LIST [11] { + LIST [11] { elements: { CONSTANT [12] { value: 1 } CONSTANT [13] { value: 2 } @@ -268,7 +268,7 @@ Source: timestamp(int(timestamp(1000000000))).getFullYear() + timestamp(int(time CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: getFullYear @@ -462,12 +462,12 @@ Source: {"a": 2}["a"] + {"a": 2}["a"] * {"a": 2}["a"] == 6 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _[_] args: { - CREATE_MAP [4] { + MAP [4] { MAP_ENTRY [5] { key: { CONSTANT [6] { value: "a" } @@ -515,15 +515,15 @@ Source: {'a': {'b': 1}, 'c': {'b': 1}, 'd': {'e': {'b': 1}}, 'e': {'e': {'b': 1} CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_MAP [3] { + MAP [3] { MAP_ENTRY [4] { key: { CONSTANT [5] { value: "e" } } value: { - CREATE_MAP [6] { + MAP [6] { MAP_ENTRY [7] { key: { CONSTANT [8] { value: "b" } @@ -536,7 +536,7 @@ CALL [1] { } } } - CREATE_MAP [10] { + MAP [10] { MAP_ENTRY [11] { key: { CONSTANT [12] { value: "b" } @@ -548,7 +548,7 @@ CALL [1] { } } } - CREATE_MAP [14] { + MAP [14] { MAP_ENTRY [15] { key: { CONSTANT [16] { value: "a" } @@ -598,9 +598,9 @@ Source: [1, [1,2,3,4], 2, [1,2,3,4], 5, [1,2,3,4], 7, [[1,2], [1,2,3,4]], [1,2]] CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_LIST [3] { + LIST [3] { elements: { CONSTANT [4] { value: 1 } CONSTANT [5] { value: 2 } @@ -608,7 +608,7 @@ CALL [1] { CONSTANT [7] { value: 4 } } } - CREATE_LIST [8] { + LIST [8] { elements: { CONSTANT [9] { value: 1 } CONSTANT [10] { value: 2 } @@ -616,7 +616,7 @@ CALL [1] { } } } - CREATE_LIST [11] { + LIST [11] { elements: { CONSTANT [12] { value: 1 } IDENT [13] { @@ -631,7 +631,7 @@ CALL [1] { name: @index0 } CONSTANT [18] { value: 7 } - CREATE_LIST [19] { + LIST [19] { elements: { IDENT [20] { name: @index1 @@ -654,7 +654,7 @@ Source: msg.single_int64 + msg.single_int64 == 6 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -688,7 +688,7 @@ Source: msg.oneof_type.payload.single_int64 + msg.oneof_type.payload.single_int3 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -767,7 +767,7 @@ Source: true || msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.one CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -825,7 +825,7 @@ Source: msg.oneof_type.payload.map_int32_int64[1] + msg.oneof_type.payload.map_i CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _[_] @@ -877,7 +877,7 @@ Source: msg.oneof_type.payload.map_int32_int64[0] + msg.oneof_type.payload.map_i CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -941,7 +941,7 @@ Source: msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type. CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -977,7 +977,7 @@ Source: (msg.single_int64 > 0 ? msg.single_int64 : 0) == 3 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -1018,7 +1018,7 @@ Source: false ? false : (msg.single_int64) + ((msg.single_int64 + 1) * 2) == 11 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -1071,7 +1071,7 @@ Source: (msg.single_int64 > 0 ? (msg.single_int32 > 0 ? msg.single_int64 + msg.s CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -1140,17 +1140,17 @@ Source: size([[1].exists(i, i > 0)]) + size([[1].exists(j, j > 0)]) + size([[2]. CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: size args: { - CREATE_LIST [4] { + LIST [4] { elements: { COMPREHENSION [5] { iter_var: @c0:0 iter_range: { - CREATE_LIST [6] { + LIST [6] { elements: { CONSTANT [7] { value: 1 } } @@ -1207,12 +1207,12 @@ CALL [1] { CALL [18] { function: size args: { - CREATE_LIST [19] { + LIST [19] { elements: { COMPREHENSION [20] { iter_var: @c0:0 iter_range: { - CREATE_LIST [21] { + LIST [21] { elements: { CONSTANT [22] { value: 2 } } @@ -1309,14 +1309,14 @@ Source: [[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_LIST [3] { + LIST [3] { elements: { COMPREHENSION [4] { iter_var: @c0:0 iter_range: { - CREATE_LIST [5] { + LIST [5] { elements: { CONSTANT [6] { value: 1 } } @@ -1368,12 +1368,12 @@ CALL [1] { } } } - CREATE_LIST [17] { + LIST [17] { elements: { COMPREHENSION [18] { iter_var: @c0:1 iter_range: { - CREATE_LIST [19] { + LIST [19] { elements: { CONSTANT [20] { value: "a" } } @@ -1457,7 +1457,7 @@ CALL [1] { } } } - CREATE_LIST [39] { + LIST [39] { elements: { CONSTANT [40] { value: true } CONSTANT [41] { value: true } @@ -1475,16 +1475,16 @@ Source: [1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [[2, 3, 4], [2, 3, 4], [2, 3, CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_LIST [3] { + LIST [3] { elements: { CONSTANT [4] { value: 1 } CONSTANT [5] { value: 2 } CONSTANT [6] { value: 3 } } } - CREATE_LIST [7] { + LIST [7] { elements: { CONSTANT [8] { value: 2 } CONSTANT [9] { value: 3 } @@ -1505,7 +1505,7 @@ CALL [1] { } accu_var: @x0:0 accu_init: { - CREATE_LIST [14] { + LIST [14] { elements: { } } @@ -1520,7 +1520,7 @@ CALL [1] { IDENT [17] { name: @x0:0 } - CREATE_LIST [18] { + LIST [18] { elements: { COMPREHENSION [19] { iter_var: @c1:0 @@ -1531,7 +1531,7 @@ CALL [1] { } accu_var: @x1:0 accu_init: { - CREATE_LIST [21] { + LIST [21] { elements: { } } @@ -1546,7 +1546,7 @@ CALL [1] { IDENT [24] { name: @x1:0 } - CREATE_LIST [25] { + LIST [25] { elements: { CALL [26] { function: _+_ @@ -1579,7 +1579,7 @@ CALL [1] { } } } - CREATE_LIST [31] { + LIST [31] { elements: { IDENT [32] { name: @index1 @@ -1605,7 +1605,7 @@ CALL [31] { COMPREHENSION [30] { iter_var: @c0:0 iter_range: { - CREATE_LIST [1] { + LIST [1] { elements: { CONSTANT [2] { value: 1 } CONSTANT [3] { value: 2 } @@ -1614,7 +1614,7 @@ CALL [31] { } accu_var: @x0:0 accu_init: { - CREATE_LIST [24] { + LIST [24] { elements: { } } @@ -1629,12 +1629,12 @@ CALL [31] { IDENT [26] { name: @x0:0 } - CREATE_LIST [27] { + LIST [27] { elements: { COMPREHENSION [23] { iter_var: @c1:0 iter_range: { - CREATE_LIST [6] { + LIST [6] { elements: { CONSTANT [7] { value: 1 } CONSTANT [8] { value: 2 } @@ -1644,7 +1644,7 @@ CALL [31] { } accu_var: @x1:0 accu_init: { - CREATE_LIST [15] { + LIST [15] { elements: { } } @@ -1673,7 +1673,7 @@ CALL [31] { IDENT [17] { name: @x1:0 } - CREATE_LIST [18] { + LIST [18] { elements: { IDENT [11] { name: @c1:0 @@ -1705,14 +1705,14 @@ CALL [31] { } } } - CREATE_LIST [32] { + LIST [32] { elements: { - CREATE_LIST [33] { + LIST [33] { elements: { CONSTANT [34] { value: 1 } } } - CREATE_LIST [35] { + LIST [35] { elements: { CONSTANT [36] { value: 2 } } @@ -1727,13 +1727,13 @@ Source: 1 in [1,2,3] && 2 in [1,2,3] && 3 in [3, [1,2,3]] && 1 in [1,2,3] CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: @in args: { CONSTANT [4] { value: 1 } - CREATE_LIST [5] { + LIST [5] { elements: { CONSTANT [6] { value: 1 } CONSTANT [7] { value: 2 } @@ -1742,7 +1742,7 @@ CALL [1] { } } } - CREATE_LIST [9] { + LIST [9] { elements: { CONSTANT [10] { value: 1 } CONSTANT [11] { value: 2 } @@ -1778,7 +1778,7 @@ CALL [1] { function: @in args: { CONSTANT [21] { value: 3 } - CREATE_LIST [22] { + LIST [22] { elements: { CONSTANT [23] { value: 3 } IDENT [24] { @@ -1803,9 +1803,9 @@ Source: 2 in {'a': 1, 2: {true: false}, 3: {true: false}} CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_MAP [3] { + MAP [3] { MAP_ENTRY [4] { key: { CONSTANT [5] { value: true } @@ -1821,7 +1821,7 @@ CALL [1] { function: @in args: { CONSTANT [8] { value: 2 } - CREATE_MAP [9] { + MAP [9] { MAP_ENTRY [10] { key: { CONSTANT [11] { value: "a" } @@ -1861,17 +1861,17 @@ Source: [1,2].map(i, [1, 2].map(i, [3,4])) == [[[3, 4], [3, 4]], [[3, 4], [3, 4] CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_LIST [3] { + LIST [3] { elements: { - CREATE_LIST [4] { + LIST [4] { elements: { CONSTANT [5] { value: 3 } CONSTANT [6] { value: 4 } } } - CREATE_LIST [7] { + LIST [7] { elements: { CONSTANT [8] { value: 3 } CONSTANT [9] { value: 4 } @@ -1879,7 +1879,7 @@ CALL [1] { } } } - CREATE_LIST [10] { + LIST [10] { elements: { CONSTANT [11] { value: 1 } CONSTANT [12] { value: 2 } @@ -1899,7 +1899,7 @@ CALL [1] { } accu_var: @x0:0 accu_init: { - CREATE_LIST [16] { + LIST [16] { elements: { } } @@ -1914,7 +1914,7 @@ CALL [1] { IDENT [19] { name: @x0:0 } - CREATE_LIST [20] { + LIST [20] { elements: { COMPREHENSION [21] { iter_var: @c1:0 @@ -1925,7 +1925,7 @@ CALL [1] { } accu_var: @x1:0 accu_init: { - CREATE_LIST [23] { + LIST [23] { elements: { } } @@ -1940,9 +1940,9 @@ CALL [1] { IDENT [26] { name: @x1:0 } - CREATE_LIST [27] { + LIST [27] { elements: { - CREATE_LIST [28] { + LIST [28] { elements: { CONSTANT [29] { value: 3 } CONSTANT [30] { value: 4 } @@ -1970,7 +1970,7 @@ CALL [1] { } } } - CREATE_LIST [33] { + LIST [33] { elements: { IDENT [34] { name: @index0 @@ -1990,7 +1990,7 @@ Source: [x - 1 > 3 ? x - 1 : 5].exists(x, x - 1 > 3) || x - 1 > 3 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _>_ @@ -2015,7 +2015,7 @@ CALL [1] { COMPREHENSION [9] { iter_var: @c0:0 iter_range: { - CREATE_LIST [10] { + LIST [10] { elements: { CALL [11] { function: _?_:_ @@ -2101,7 +2101,7 @@ Source: ["foo", "bar"].map(x, [x + x, x + x]).map(x, [x + x, x + x]) CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _+_ @@ -2133,7 +2133,7 @@ CALL [1] { COMPREHENSION [10] { iter_var: @c1:0 iter_range: { - CREATE_LIST [11] { + LIST [11] { elements: { CONSTANT [12] { value: "foo" } CONSTANT [13] { value: "bar" } @@ -2142,7 +2142,7 @@ CALL [1] { } accu_var: @x1:0 accu_init: { - CREATE_LIST [14] { + LIST [14] { elements: { } } @@ -2157,9 +2157,9 @@ CALL [1] { IDENT [17] { name: @x1:0 } - CREATE_LIST [18] { + LIST [18] { elements: { - CREATE_LIST [19] { + LIST [19] { elements: { IDENT [20] { name: @index0 @@ -2183,7 +2183,7 @@ CALL [1] { } accu_var: @x0:0 accu_init: { - CREATE_LIST [23] { + LIST [23] { elements: { } } @@ -2198,9 +2198,9 @@ CALL [1] { IDENT [26] { name: @x0:0 } - CREATE_LIST [27] { + LIST [27] { elements: { - CREATE_LIST [28] { + LIST [28] { elements: { IDENT [29] { name: @index1 @@ -2229,9 +2229,9 @@ Source: has({'a': true}.a) && {'a':true}['a'] CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_MAP [3] { + MAP [3] { MAP_ENTRY [4] { key: { CONSTANT [5] { value: "a" } @@ -2270,10 +2270,10 @@ Source: has({'a': true}.a) && has({'a': true}.a) CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { - CREATE_MAP [4] { + MAP [4] { MAP_ENTRY [5] { key: { CONSTANT [6] { value: "a" } @@ -2305,7 +2305,7 @@ Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : 0) CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -2346,7 +2346,7 @@ Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : msg CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -2397,7 +2397,7 @@ Source: (has(msg.oneof_type.payload.single_int64) ? msg.oneof_type.payload.singl CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -2450,7 +2450,7 @@ Source: (has(msg.oneof_type) && has(msg.oneof_type.payload) && has(msg.oneof_typ CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -2543,9 +2543,9 @@ Source: [10, ?optional.none(), [?optional.none(), ?opt_x], [?optional.none(), ?o CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_LIST [3] { + LIST [3] { elements: { CALL [4] { function: optional.none @@ -2558,7 +2558,7 @@ CALL [1] { } optional_indices: [0, 1] } - CREATE_LIST [6] { + LIST [6] { elements: { CONSTANT [7] { value: 5 } } @@ -2568,7 +2568,7 @@ CALL [1] { CALL [8] { function: _==_ args: { - CREATE_LIST [9] { + LIST [9] { elements: { CONSTANT [10] { value: 10 } CALL [11] { @@ -2585,7 +2585,7 @@ CALL [1] { } optional_indices: [0] } - CREATE_LIST [14] { + LIST [14] { elements: { CONSTANT [15] { value: 10 } IDENT [16] { @@ -2606,12 +2606,12 @@ Source: {?'hello': optional.of('hello')}['hello'] + {?'hello': optional.of('hell CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _[_] args: { - CREATE_MAP [4] { + MAP [4] { MAP_ENTRY [5] { key: { CONSTANT [6] { value: "hello" } @@ -2657,9 +2657,9 @@ Source: {?'key': optional.of('test')}[?'bogus'].or({'key': 'test'}[?'bogus']).or CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_MAP [3] { + MAP [3] { MAP_ENTRY [4] { key: { CONSTANT [5] { value: "key" } @@ -2683,7 +2683,7 @@ CALL [1] { CALL [10] { function: _[?_] args: { - CREATE_MAP [11] { + MAP [11] { MAP_ENTRY [12] { key: { CONSTANT [13] { value: "key" } @@ -2739,9 +2739,9 @@ Source: TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: o CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_STRUCT [3] { + STRUCT [3] { name: TestAllTypes entries: { ENTRY [4] { @@ -2801,7 +2801,7 @@ Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('h' + 'e' + 'l' + 'l' + CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _+_ @@ -3001,7 +3001,7 @@ Source: non_pure_custom_func(msg.oneof_type.payload.single_int64) + non_pure_cus CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -3077,7 +3077,7 @@ Source: pure_custom_func(msg.oneof_type.payload.single_int64) + pure_custom_func CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: pure_custom_func diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_9.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_9.baseline index 03f9e8cad..fd8be83cf 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_9.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_9.baseline @@ -4,12 +4,12 @@ Source: size([1,2]) + size([1,2]) + 1 == 5 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: size args: { - CREATE_LIST [4] { + LIST [4] { elements: { CONSTANT [5] { value: 1 } CONSTANT [6] { value: 2 } @@ -50,12 +50,12 @@ Source: 2 + size([1,2]) + size([1,2]) + 1 == 7 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: size args: { - CREATE_LIST [4] { + LIST [4] { elements: { CONSTANT [5] { value: 1 } CONSTANT [6] { value: 2 } @@ -102,12 +102,12 @@ Source: size([0]) + size([0]) + size([1,2]) + size([1,2]) == 6 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: size args: { - CREATE_LIST [4] { + LIST [4] { elements: { CONSTANT [5] { value: 0 } } @@ -117,7 +117,7 @@ CALL [1] { CALL [6] { function: size args: { - CREATE_LIST [7] { + LIST [7] { elements: { CONSTANT [8] { value: 1 } CONSTANT [9] { value: 2 } @@ -168,12 +168,12 @@ Source: 5 + size([0]) + size([0]) + size([1,2]) + size([1,2]) + size([1,2,3]) + CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: size args: { - CREATE_LIST [4] { + LIST [4] { elements: { CONSTANT [5] { value: 0 } } @@ -183,7 +183,7 @@ CALL [1] { CALL [6] { function: size args: { - CREATE_LIST [7] { + LIST [7] { elements: { CONSTANT [8] { value: 1 } CONSTANT [9] { value: 2 } @@ -194,7 +194,7 @@ CALL [1] { CALL [10] { function: size args: { - CREATE_LIST [11] { + LIST [11] { elements: { CONSTANT [12] { value: 1 } CONSTANT [13] { value: 2 } @@ -268,7 +268,7 @@ Source: timestamp(int(timestamp(1000000000))).getFullYear() + timestamp(int(time CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: getFullYear @@ -462,12 +462,12 @@ Source: {"a": 2}["a"] + {"a": 2}["a"] * {"a": 2}["a"] == 6 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _[_] args: { - CREATE_MAP [4] { + MAP [4] { MAP_ENTRY [5] { key: { CONSTANT [6] { value: "a" } @@ -515,15 +515,15 @@ Source: {'a': {'b': 1}, 'c': {'b': 1}, 'd': {'e': {'b': 1}}, 'e': {'e': {'b': 1} CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_MAP [3] { + MAP [3] { MAP_ENTRY [4] { key: { CONSTANT [5] { value: "e" } } value: { - CREATE_MAP [6] { + MAP [6] { MAP_ENTRY [7] { key: { CONSTANT [8] { value: "b" } @@ -536,7 +536,7 @@ CALL [1] { } } } - CREATE_MAP [10] { + MAP [10] { MAP_ENTRY [11] { key: { CONSTANT [12] { value: "b" } @@ -548,7 +548,7 @@ CALL [1] { } } } - CREATE_MAP [14] { + MAP [14] { MAP_ENTRY [15] { key: { CONSTANT [16] { value: "a" } @@ -598,9 +598,9 @@ Source: [1, [1,2,3,4], 2, [1,2,3,4], 5, [1,2,3,4], 7, [[1,2], [1,2,3,4]], [1,2]] CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_LIST [3] { + LIST [3] { elements: { CONSTANT [4] { value: 1 } CONSTANT [5] { value: 2 } @@ -608,7 +608,7 @@ CALL [1] { CONSTANT [7] { value: 4 } } } - CREATE_LIST [8] { + LIST [8] { elements: { CONSTANT [9] { value: 1 } CONSTANT [10] { value: 2 } @@ -616,7 +616,7 @@ CALL [1] { } } } - CREATE_LIST [11] { + LIST [11] { elements: { CONSTANT [12] { value: 1 } IDENT [13] { @@ -631,7 +631,7 @@ CALL [1] { name: @index0 } CONSTANT [18] { value: 7 } - CREATE_LIST [19] { + LIST [19] { elements: { IDENT [20] { name: @index1 @@ -654,7 +654,7 @@ Source: msg.single_int64 + msg.single_int64 == 6 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -688,7 +688,7 @@ Source: msg.oneof_type.payload.single_int64 + msg.oneof_type.payload.single_int3 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -767,7 +767,7 @@ Source: true || msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.one CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -825,7 +825,7 @@ Source: msg.oneof_type.payload.map_int32_int64[1] + msg.oneof_type.payload.map_i CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _[_] @@ -877,7 +877,7 @@ Source: msg.oneof_type.payload.map_int32_int64[0] + msg.oneof_type.payload.map_i CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -965,7 +965,7 @@ Source: (msg.single_int64 > 0 ? msg.single_int64 : 0) == 3 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -1006,7 +1006,7 @@ Source: false ? false : (msg.single_int64) + ((msg.single_int64 + 1) * 2) == 11 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -1059,7 +1059,7 @@ Source: (msg.single_int64 > 0 ? (msg.single_int32 > 0 ? msg.single_int64 + msg.s CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -1128,17 +1128,17 @@ Source: size([[1].exists(i, i > 0)]) + size([[1].exists(j, j > 0)]) + size([[2]. CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: size args: { - CREATE_LIST [4] { + LIST [4] { elements: { COMPREHENSION [5] { iter_var: @c0:0 iter_range: { - CREATE_LIST [6] { + LIST [6] { elements: { CONSTANT [7] { value: 1 } } @@ -1195,12 +1195,12 @@ CALL [1] { CALL [18] { function: size args: { - CREATE_LIST [19] { + LIST [19] { elements: { COMPREHENSION [20] { iter_var: @c0:0 iter_range: { - CREATE_LIST [21] { + LIST [21] { elements: { CONSTANT [22] { value: 2 } } @@ -1297,14 +1297,14 @@ Source: [[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_LIST [3] { + LIST [3] { elements: { COMPREHENSION [4] { iter_var: @c0:0 iter_range: { - CREATE_LIST [5] { + LIST [5] { elements: { CONSTANT [6] { value: 1 } } @@ -1356,12 +1356,12 @@ CALL [1] { } } } - CREATE_LIST [17] { + LIST [17] { elements: { COMPREHENSION [18] { iter_var: @c0:1 iter_range: { - CREATE_LIST [19] { + LIST [19] { elements: { CONSTANT [20] { value: "a" } } @@ -1445,7 +1445,7 @@ CALL [1] { } } } - CREATE_LIST [39] { + LIST [39] { elements: { CONSTANT [40] { value: true } CONSTANT [41] { value: true } @@ -1463,16 +1463,16 @@ Source: [1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [[2, 3, 4], [2, 3, 4], [2, 3, CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_LIST [3] { + LIST [3] { elements: { CONSTANT [4] { value: 1 } CONSTANT [5] { value: 2 } CONSTANT [6] { value: 3 } } } - CREATE_LIST [7] { + LIST [7] { elements: { CONSTANT [8] { value: 2 } CONSTANT [9] { value: 3 } @@ -1493,7 +1493,7 @@ CALL [1] { } accu_var: @x0:0 accu_init: { - CREATE_LIST [14] { + LIST [14] { elements: { } } @@ -1508,7 +1508,7 @@ CALL [1] { IDENT [17] { name: @x0:0 } - CREATE_LIST [18] { + LIST [18] { elements: { COMPREHENSION [19] { iter_var: @c1:0 @@ -1519,7 +1519,7 @@ CALL [1] { } accu_var: @x1:0 accu_init: { - CREATE_LIST [21] { + LIST [21] { elements: { } } @@ -1534,7 +1534,7 @@ CALL [1] { IDENT [24] { name: @x1:0 } - CREATE_LIST [25] { + LIST [25] { elements: { CALL [26] { function: _+_ @@ -1567,7 +1567,7 @@ CALL [1] { } } } - CREATE_LIST [31] { + LIST [31] { elements: { IDENT [32] { name: @index1 @@ -1593,7 +1593,7 @@ CALL [31] { COMPREHENSION [30] { iter_var: @c0:0 iter_range: { - CREATE_LIST [1] { + LIST [1] { elements: { CONSTANT [2] { value: 1 } CONSTANT [3] { value: 2 } @@ -1602,7 +1602,7 @@ CALL [31] { } accu_var: @x0:0 accu_init: { - CREATE_LIST [24] { + LIST [24] { elements: { } } @@ -1617,12 +1617,12 @@ CALL [31] { IDENT [26] { name: @x0:0 } - CREATE_LIST [27] { + LIST [27] { elements: { COMPREHENSION [23] { iter_var: @c1:0 iter_range: { - CREATE_LIST [6] { + LIST [6] { elements: { CONSTANT [7] { value: 1 } CONSTANT [8] { value: 2 } @@ -1632,7 +1632,7 @@ CALL [31] { } accu_var: @x1:0 accu_init: { - CREATE_LIST [15] { + LIST [15] { elements: { } } @@ -1661,7 +1661,7 @@ CALL [31] { IDENT [17] { name: @x1:0 } - CREATE_LIST [18] { + LIST [18] { elements: { IDENT [11] { name: @c1:0 @@ -1693,14 +1693,14 @@ CALL [31] { } } } - CREATE_LIST [32] { + LIST [32] { elements: { - CREATE_LIST [33] { + LIST [33] { elements: { CONSTANT [34] { value: 1 } } } - CREATE_LIST [35] { + LIST [35] { elements: { CONSTANT [36] { value: 2 } } @@ -1715,13 +1715,13 @@ Source: 1 in [1,2,3] && 2 in [1,2,3] && 3 in [3, [1,2,3]] && 1 in [1,2,3] CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: @in args: { CONSTANT [4] { value: 1 } - CREATE_LIST [5] { + LIST [5] { elements: { CONSTANT [6] { value: 1 } CONSTANT [7] { value: 2 } @@ -1730,7 +1730,7 @@ CALL [1] { } } } - CREATE_LIST [9] { + LIST [9] { elements: { CONSTANT [10] { value: 1 } CONSTANT [11] { value: 2 } @@ -1766,7 +1766,7 @@ CALL [1] { function: @in args: { CONSTANT [21] { value: 3 } - CREATE_LIST [22] { + LIST [22] { elements: { CONSTANT [23] { value: 3 } IDENT [24] { @@ -1791,9 +1791,9 @@ Source: 2 in {'a': 1, 2: {true: false}, 3: {true: false}} CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_MAP [3] { + MAP [3] { MAP_ENTRY [4] { key: { CONSTANT [5] { value: true } @@ -1809,7 +1809,7 @@ CALL [1] { function: @in args: { CONSTANT [8] { value: 2 } - CREATE_MAP [9] { + MAP [9] { MAP_ENTRY [10] { key: { CONSTANT [11] { value: "a" } @@ -1849,17 +1849,17 @@ Source: [1,2].map(i, [1, 2].map(i, [3,4])) == [[[3, 4], [3, 4]], [[3, 4], [3, 4] CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_LIST [3] { + LIST [3] { elements: { - CREATE_LIST [4] { + LIST [4] { elements: { CONSTANT [5] { value: 3 } CONSTANT [6] { value: 4 } } } - CREATE_LIST [7] { + LIST [7] { elements: { CONSTANT [8] { value: 3 } CONSTANT [9] { value: 4 } @@ -1867,7 +1867,7 @@ CALL [1] { } } } - CREATE_LIST [10] { + LIST [10] { elements: { CONSTANT [11] { value: 1 } CONSTANT [12] { value: 2 } @@ -1887,7 +1887,7 @@ CALL [1] { } accu_var: @x0:0 accu_init: { - CREATE_LIST [16] { + LIST [16] { elements: { } } @@ -1902,7 +1902,7 @@ CALL [1] { IDENT [19] { name: @x0:0 } - CREATE_LIST [20] { + LIST [20] { elements: { COMPREHENSION [21] { iter_var: @c1:0 @@ -1913,7 +1913,7 @@ CALL [1] { } accu_var: @x1:0 accu_init: { - CREATE_LIST [23] { + LIST [23] { elements: { } } @@ -1928,9 +1928,9 @@ CALL [1] { IDENT [26] { name: @x1:0 } - CREATE_LIST [27] { + LIST [27] { elements: { - CREATE_LIST [28] { + LIST [28] { elements: { CONSTANT [29] { value: 3 } CONSTANT [30] { value: 4 } @@ -1958,7 +1958,7 @@ CALL [1] { } } } - CREATE_LIST [33] { + LIST [33] { elements: { IDENT [34] { name: @index0 @@ -1978,7 +1978,7 @@ Source: [x - 1 > 3 ? x - 1 : 5].exists(x, x - 1 > 3) || x - 1 > 3 CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _>_ @@ -2003,7 +2003,7 @@ CALL [1] { COMPREHENSION [9] { iter_var: @c0:0 iter_range: { - CREATE_LIST [10] { + LIST [10] { elements: { CALL [11] { function: _?_:_ @@ -2089,7 +2089,7 @@ Source: ["foo", "bar"].map(x, [x + x, x + x]).map(x, [x + x, x + x]) CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _+_ @@ -2121,7 +2121,7 @@ CALL [1] { COMPREHENSION [10] { iter_var: @c1:0 iter_range: { - CREATE_LIST [11] { + LIST [11] { elements: { CONSTANT [12] { value: "foo" } CONSTANT [13] { value: "bar" } @@ -2130,7 +2130,7 @@ CALL [1] { } accu_var: @x1:0 accu_init: { - CREATE_LIST [14] { + LIST [14] { elements: { } } @@ -2145,9 +2145,9 @@ CALL [1] { IDENT [17] { name: @x1:0 } - CREATE_LIST [18] { + LIST [18] { elements: { - CREATE_LIST [19] { + LIST [19] { elements: { IDENT [20] { name: @index0 @@ -2171,7 +2171,7 @@ CALL [1] { } accu_var: @x0:0 accu_init: { - CREATE_LIST [23] { + LIST [23] { elements: { } } @@ -2186,9 +2186,9 @@ CALL [1] { IDENT [26] { name: @x0:0 } - CREATE_LIST [27] { + LIST [27] { elements: { - CREATE_LIST [28] { + LIST [28] { elements: { IDENT [29] { name: @index1 @@ -2217,9 +2217,9 @@ Source: has({'a': true}.a) && {'a':true}['a'] CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_MAP [3] { + MAP [3] { MAP_ENTRY [4] { key: { CONSTANT [5] { value: "a" } @@ -2258,10 +2258,10 @@ Source: has({'a': true}.a) && has({'a': true}.a) CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { - CREATE_MAP [4] { + MAP [4] { MAP_ENTRY [5] { key: { CONSTANT [6] { value: "a" } @@ -2293,7 +2293,7 @@ Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : 0) CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { IDENT [4] { @@ -2334,7 +2334,7 @@ Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : msg CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -2385,7 +2385,7 @@ Source: (has(msg.oneof_type.payload.single_int64) ? msg.oneof_type.payload.singl CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -2438,7 +2438,7 @@ Source: (has(msg.oneof_type) && has(msg.oneof_type.payload) && has(msg.oneof_typ CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -2531,9 +2531,9 @@ Source: [10, ?optional.none(), [?optional.none(), ?opt_x], [?optional.none(), ?o CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_LIST [3] { + LIST [3] { elements: { CALL [4] { function: optional.none @@ -2546,7 +2546,7 @@ CALL [1] { } optional_indices: [0, 1] } - CREATE_LIST [6] { + LIST [6] { elements: { CONSTANT [7] { value: 5 } } @@ -2556,7 +2556,7 @@ CALL [1] { CALL [8] { function: _==_ args: { - CREATE_LIST [9] { + LIST [9] { elements: { CONSTANT [10] { value: 10 } CALL [11] { @@ -2573,7 +2573,7 @@ CALL [1] { } optional_indices: [0] } - CREATE_LIST [14] { + LIST [14] { elements: { CONSTANT [15] { value: 10 } IDENT [16] { @@ -2594,12 +2594,12 @@ Source: {?'hello': optional.of('hello')}['hello'] + {?'hello': optional.of('hell CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _[_] args: { - CREATE_MAP [4] { + MAP [4] { MAP_ENTRY [5] { key: { CONSTANT [6] { value: "hello" } @@ -2645,9 +2645,9 @@ Source: {?'key': optional.of('test')}[?'bogus'].or({'key': 'test'}[?'bogus']).or CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_MAP [3] { + MAP [3] { MAP_ENTRY [4] { key: { CONSTANT [5] { value: "key" } @@ -2671,7 +2671,7 @@ CALL [1] { CALL [10] { function: _[?_] args: { - CREATE_MAP [11] { + MAP [11] { MAP_ENTRY [12] { key: { CONSTANT [13] { value: "key" } @@ -2727,9 +2727,9 @@ Source: TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: o CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { - CREATE_STRUCT [3] { + STRUCT [3] { name: TestAllTypes entries: { ENTRY [4] { @@ -2789,7 +2789,7 @@ Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('h' + 'e' + 'l' + 'l' + CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: _+_ @@ -2989,7 +2989,7 @@ Source: non_pure_custom_func(msg.oneof_type.payload.single_int64) + non_pure_cus CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { SELECT [3] { SELECT [4] { @@ -3065,7 +3065,7 @@ Source: pure_custom_func(msg.oneof_type.payload.single_int64) + pure_custom_func CALL [1] { function: cel.@block args: { - CREATE_LIST [2] { + LIST [2] { elements: { CALL [3] { function: pure_custom_func diff --git a/optimizer/src/test/resources/subexpression_ast_cascaded_binds.baseline b/optimizer/src/test/resources/subexpression_ast_cascaded_binds.baseline index aea45bde5..17f8eb774 100644 --- a/optimizer/src/test/resources/subexpression_ast_cascaded_binds.baseline +++ b/optimizer/src/test/resources/subexpression_ast_cascaded_binds.baseline @@ -10,7 +10,7 @@ CALL [1] { COMPREHENSION [3] { iter_var: #unused iter_range: { - CREATE_LIST [4] { + LIST [4] { elements: { } } @@ -20,7 +20,7 @@ CALL [1] { CALL [5] { function: size args: { - CREATE_LIST [6] { + LIST [6] { elements: { CONSTANT [7] { value: 1 } CONSTANT [8] { value: 2 } @@ -69,7 +69,7 @@ CALL [1] { COMPREHENSION [3] { iter_var: #unused iter_range: { - CREATE_LIST [4] { + LIST [4] { elements: { } } @@ -79,7 +79,7 @@ CALL [1] { CALL [5] { function: size args: { - CREATE_LIST [6] { + LIST [6] { elements: { CONSTANT [7] { value: 1 } CONSTANT [8] { value: 2 } @@ -131,7 +131,7 @@ CALL [1] { COMPREHENSION [2] { iter_var: #unused iter_range: { - CREATE_LIST [3] { + LIST [3] { elements: { } } @@ -141,7 +141,7 @@ CALL [1] { CALL [4] { function: size args: { - CREATE_LIST [5] { + LIST [5] { elements: { CONSTANT [6] { value: 1 } CONSTANT [7] { value: 2 } @@ -168,7 +168,7 @@ CALL [1] { COMPREHENSION [12] { iter_var: #unused iter_range: { - CREATE_LIST [13] { + LIST [13] { elements: { } } @@ -178,7 +178,7 @@ CALL [1] { CALL [14] { function: size args: { - CREATE_LIST [15] { + LIST [15] { elements: { CONSTANT [16] { value: 0 } } @@ -232,7 +232,7 @@ CALL [1] { COMPREHENSION [2] { iter_var: #unused iter_range: { - CREATE_LIST [3] { + LIST [3] { elements: { } } @@ -242,7 +242,7 @@ CALL [1] { CALL [4] { function: size args: { - CREATE_LIST [5] { + LIST [5] { elements: { CONSTANT [6] { value: 1 } CONSTANT [7] { value: 2 } @@ -270,7 +270,7 @@ CALL [1] { COMPREHENSION [13] { iter_var: #unused iter_range: { - CREATE_LIST [14] { + LIST [14] { elements: { } } @@ -280,7 +280,7 @@ CALL [1] { CALL [15] { function: size args: { - CREATE_LIST [16] { + LIST [16] { elements: { CONSTANT [17] { value: 1 } CONSTANT [18] { value: 2 } @@ -307,7 +307,7 @@ CALL [1] { COMPREHENSION [23] { iter_var: #unused iter_range: { - CREATE_LIST [24] { + LIST [24] { elements: { } } @@ -317,7 +317,7 @@ CALL [1] { CALL [25] { function: size args: { - CREATE_LIST [26] { + LIST [26] { elements: { CONSTANT [27] { value: 0 } } @@ -389,7 +389,7 @@ CALL [1] { COMPREHENSION [2] { iter_var: #unused iter_range: { - CREATE_LIST [3] { + LIST [3] { elements: { } } @@ -435,7 +435,7 @@ CALL [1] { COMPREHENSION [12] { iter_var: #unused iter_range: { - CREATE_LIST [13] { + LIST [13] { elements: { } } @@ -474,7 +474,7 @@ CALL [1] { COMPREHENSION [21] { iter_var: #unused iter_range: { - CREATE_LIST [22] { + LIST [22] { elements: { } } @@ -523,7 +523,7 @@ CALL [1] { COMPREHENSION [32] { iter_var: #unused iter_range: { - CREATE_LIST [33] { + LIST [33] { elements: { } } @@ -659,7 +659,7 @@ CALL [1] { COMPREHENSION [2] { iter_var: #unused iter_range: { - CREATE_LIST [3] { + LIST [3] { elements: { } } @@ -669,7 +669,7 @@ CALL [1] { CALL [4] { function: _[_] args: { - CREATE_MAP [5] { + MAP [5] { MAP_ENTRY [6] { key: { CONSTANT [7] { value: "a" } @@ -722,14 +722,14 @@ Source: {'a': {'b': 1}, 'c': {'b': 1}, 'd': {'e': {'b': 1}}, 'e': {'e': {'b': 1} COMPREHENSION [1] { iter_var: #unused iter_range: { - CREATE_LIST [2] { + LIST [2] { elements: { } } } accu_var: @r0 accu_init: { - CREATE_MAP [3] { + MAP [3] { MAP_ENTRY [4] { key: { CONSTANT [5] { value: "b" } @@ -752,14 +752,14 @@ COMPREHENSION [1] { COMPREHENSION [9] { iter_var: #unused iter_range: { - CREATE_LIST [10] { + LIST [10] { elements: { } } } accu_var: @r1 accu_init: { - CREATE_MAP [11] { + MAP [11] { MAP_ENTRY [12] { key: { CONSTANT [13] { value: "e" } @@ -781,7 +781,7 @@ COMPREHENSION [1] { } } result: { - CREATE_MAP [17] { + MAP [17] { MAP_ENTRY [18] { key: { CONSTANT [19] { value: "a" } @@ -833,14 +833,14 @@ Source: [1, [1,2,3,4], 2, [1,2,3,4], 5, [1,2,3,4], 7, [[1,2], [1,2,3,4]], [1,2]] COMPREHENSION [1] { iter_var: #unused iter_range: { - CREATE_LIST [2] { + LIST [2] { elements: { } } } accu_var: @r0 accu_init: { - CREATE_LIST [3] { + LIST [3] { elements: { CONSTANT [4] { value: 1 } CONSTANT [5] { value: 2 } @@ -861,14 +861,14 @@ COMPREHENSION [1] { COMPREHENSION [10] { iter_var: #unused iter_range: { - CREATE_LIST [11] { + LIST [11] { elements: { } } } accu_var: @r1 accu_init: { - CREATE_LIST [12] { + LIST [12] { elements: { CONSTANT [13] { value: 1 } CONSTANT [14] { value: 2 } @@ -884,7 +884,7 @@ COMPREHENSION [1] { } } result: { - CREATE_LIST [17] { + LIST [17] { elements: { CONSTANT [18] { value: 1 } IDENT [19] { @@ -899,7 +899,7 @@ COMPREHENSION [1] { name: @r0 } CONSTANT [24] { value: 7 } - CREATE_LIST [25] { + LIST [25] { elements: { IDENT [26] { name: @r1 @@ -927,7 +927,7 @@ CALL [1] { COMPREHENSION [2] { iter_var: #unused iter_range: { - CREATE_LIST [3] { + LIST [3] { elements: { } } @@ -974,7 +974,7 @@ CALL [1] { COMPREHENSION [2] { iter_var: #unused iter_range: { - CREATE_LIST [3] { + LIST [3] { elements: { } } @@ -1007,7 +1007,7 @@ CALL [1] { COMPREHENSION [11] { iter_var: #unused iter_range: { - CREATE_LIST [12] { + LIST [12] { elements: { } } @@ -1081,7 +1081,7 @@ Source: true || msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.one COMPREHENSION [1] { iter_var: #unused iter_range: { - CREATE_LIST [2] { + LIST [2] { elements: { } } @@ -1155,7 +1155,7 @@ CALL [1] { COMPREHENSION [2] { iter_var: #unused iter_range: { - CREATE_LIST [3] { + LIST [3] { elements: { } } @@ -1220,7 +1220,7 @@ CALL [1] { COMPREHENSION [2] { iter_var: #unused iter_range: { - CREATE_LIST [3] { + LIST [3] { elements: { } } @@ -1321,7 +1321,7 @@ CALL [1] { COMPREHENSION [2] { iter_var: #unused iter_range: { - CREATE_LIST [3] { + LIST [3] { elements: { } } @@ -1380,7 +1380,7 @@ CALL [1] { COMPREHENSION [5] { iter_var: #unused iter_range: { - CREATE_LIST [6] { + LIST [6] { elements: { } } @@ -1441,7 +1441,7 @@ CALL [1] { COMPREHENSION [2] { iter_var: #unused iter_range: { - CREATE_LIST [3] { + LIST [3] { elements: { } } @@ -1478,7 +1478,7 @@ CALL [1] { COMPREHENSION [12] { iter_var: #unused iter_range: { - CREATE_LIST [13] { + LIST [13] { elements: { } } @@ -1545,7 +1545,7 @@ CALL [1] { COMPREHENSION [2] { iter_var: #unused iter_range: { - CREATE_LIST [3] { + LIST [3] { elements: { } } @@ -1555,12 +1555,12 @@ CALL [1] { CALL [4] { function: size args: { - CREATE_LIST [5] { + LIST [5] { elements: { COMPREHENSION [6] { iter_var: @c0:0 iter_range: { - CREATE_LIST [7] { + LIST [7] { elements: { CONSTANT [8] { value: 2 } } @@ -1633,7 +1633,7 @@ CALL [1] { COMPREHENSION [23] { iter_var: #unused iter_range: { - CREATE_LIST [24] { + LIST [24] { elements: { } } @@ -1643,12 +1643,12 @@ CALL [1] { CALL [25] { function: size args: { - CREATE_LIST [26] { + LIST [26] { elements: { COMPREHENSION [27] { iter_var: @c0:0 iter_range: { - CREATE_LIST [28] { + LIST [28] { elements: { CONSTANT [29] { value: 1 } } @@ -1749,19 +1749,19 @@ CALL [1] { COMPREHENSION [2] { iter_var: #unused iter_range: { - CREATE_LIST [3] { + LIST [3] { elements: { } } } accu_var: @r1 accu_init: { - CREATE_LIST [4] { + LIST [4] { elements: { COMPREHENSION [5] { iter_var: @c0:1 iter_range: { - CREATE_LIST [6] { + LIST [6] { elements: { CONSTANT [7] { value: "a" } } @@ -1832,19 +1832,19 @@ CALL [1] { COMPREHENSION [22] { iter_var: #unused iter_range: { - CREATE_LIST [23] { + LIST [23] { elements: { } } } accu_var: @r0 accu_init: { - CREATE_LIST [24] { + LIST [24] { elements: { COMPREHENSION [25] { iter_var: @c0:0 iter_range: { - CREATE_LIST [26] { + LIST [26] { elements: { CONSTANT [27] { value: 1 } } @@ -1931,7 +1931,7 @@ CALL [1] { } } } - CREATE_LIST [45] { + LIST [45] { elements: { CONSTANT [46] { value: true } CONSTANT [47] { value: true } @@ -1950,14 +1950,14 @@ CALL [1] { COMPREHENSION [2] { iter_var: #unused iter_range: { - CREATE_LIST [3] { + LIST [3] { elements: { } } } accu_var: @r0 accu_init: { - CREATE_LIST [4] { + LIST [4] { elements: { CONSTANT [5] { value: 1 } CONSTANT [6] { value: 2 } @@ -1983,7 +1983,7 @@ CALL [1] { } accu_var: @x0:0 accu_init: { - CREATE_LIST [12] { + LIST [12] { elements: { } } @@ -1998,7 +1998,7 @@ CALL [1] { IDENT [15] { name: @x0:0 } - CREATE_LIST [16] { + LIST [16] { elements: { COMPREHENSION [17] { iter_var: @c1:0 @@ -2009,7 +2009,7 @@ CALL [1] { } accu_var: @x1:0 accu_init: { - CREATE_LIST [19] { + LIST [19] { elements: { } } @@ -2024,7 +2024,7 @@ CALL [1] { IDENT [22] { name: @x1:0 } - CREATE_LIST [23] { + LIST [23] { elements: { CALL [24] { function: _+_ @@ -2062,14 +2062,14 @@ CALL [1] { COMPREHENSION [29] { iter_var: #unused iter_range: { - CREATE_LIST [30] { + LIST [30] { elements: { } } } accu_var: @r1 accu_init: { - CREATE_LIST [31] { + LIST [31] { elements: { CONSTANT [32] { value: 2 } CONSTANT [33] { value: 3 } @@ -2086,7 +2086,7 @@ CALL [1] { } } result: { - CREATE_LIST [37] { + LIST [37] { elements: { IDENT [38] { name: @r1 @@ -2112,7 +2112,7 @@ CALL [31] { COMPREHENSION [30] { iter_var: @c0:0 iter_range: { - CREATE_LIST [1] { + LIST [1] { elements: { CONSTANT [2] { value: 1 } CONSTANT [3] { value: 2 } @@ -2121,7 +2121,7 @@ CALL [31] { } accu_var: @x0:0 accu_init: { - CREATE_LIST [24] { + LIST [24] { elements: { } } @@ -2136,12 +2136,12 @@ CALL [31] { IDENT [26] { name: @x0:0 } - CREATE_LIST [27] { + LIST [27] { elements: { COMPREHENSION [23] { iter_var: @c1:0 iter_range: { - CREATE_LIST [6] { + LIST [6] { elements: { CONSTANT [7] { value: 1 } CONSTANT [8] { value: 2 } @@ -2151,7 +2151,7 @@ CALL [31] { } accu_var: @x1:0 accu_init: { - CREATE_LIST [15] { + LIST [15] { elements: { } } @@ -2180,7 +2180,7 @@ CALL [31] { IDENT [17] { name: @x1:0 } - CREATE_LIST [18] { + LIST [18] { elements: { IDENT [11] { name: @c1:0 @@ -2212,14 +2212,14 @@ CALL [31] { } } } - CREATE_LIST [32] { + LIST [32] { elements: { - CREATE_LIST [33] { + LIST [33] { elements: { CONSTANT [34] { value: 1 } } } - CREATE_LIST [35] { + LIST [35] { elements: { CONSTANT [36] { value: 2 } } @@ -2234,14 +2234,14 @@ Source: 1 in [1,2,3] && 2 in [1,2,3] && 3 in [3, [1,2,3]] && 1 in [1,2,3] COMPREHENSION [1] { iter_var: #unused iter_range: { - CREATE_LIST [2] { + LIST [2] { elements: { } } } accu_var: @r0 accu_init: { - CREATE_LIST [3] { + LIST [3] { elements: { CONSTANT [4] { value: 1 } CONSTANT [5] { value: 2 } @@ -2261,7 +2261,7 @@ COMPREHENSION [1] { COMPREHENSION [9] { iter_var: #unused iter_range: { - CREATE_LIST [10] { + LIST [10] { elements: { } } @@ -2314,7 +2314,7 @@ COMPREHENSION [1] { function: @in args: { CONSTANT [24] { value: 3 } - CREATE_LIST [25] { + LIST [25] { elements: { CONSTANT [26] { value: 3 } IDENT [27] { @@ -2345,14 +2345,14 @@ CALL [1] { COMPREHENSION [3] { iter_var: #unused iter_range: { - CREATE_LIST [4] { + LIST [4] { elements: { } } } accu_var: @r0 accu_init: { - CREATE_MAP [5] { + MAP [5] { MAP_ENTRY [6] { key: { CONSTANT [7] { value: true } @@ -2372,7 +2372,7 @@ CALL [1] { } } result: { - CREATE_MAP [11] { + MAP [11] { MAP_ENTRY [12] { key: { CONSTANT [13] { value: "a" } @@ -2412,14 +2412,14 @@ Source: [1,2].map(i, [1, 2].map(i, [3,4])) == [[[3, 4], [3, 4]], [[3, 4], [3, 4] COMPREHENSION [1] { iter_var: #unused iter_range: { - CREATE_LIST [2] { + LIST [2] { elements: { } } } accu_var: @r1 accu_init: { - CREATE_LIST [3] { + LIST [3] { elements: { CONSTANT [4] { value: 3 } CONSTANT [5] { value: 4 } @@ -2441,14 +2441,14 @@ COMPREHENSION [1] { COMPREHENSION [9] { iter_var: #unused iter_range: { - CREATE_LIST [10] { + LIST [10] { elements: { } } } accu_var: @r0 accu_init: { - CREATE_LIST [11] { + LIST [11] { elements: { CONSTANT [12] { value: 1 } CONSTANT [13] { value: 2 } @@ -2473,7 +2473,7 @@ COMPREHENSION [1] { } accu_var: @x0:0 accu_init: { - CREATE_LIST [18] { + LIST [18] { elements: { } } @@ -2488,7 +2488,7 @@ COMPREHENSION [1] { IDENT [21] { name: @x0:0 } - CREATE_LIST [22] { + LIST [22] { elements: { COMPREHENSION [23] { iter_var: @c1:0 @@ -2499,7 +2499,7 @@ COMPREHENSION [1] { } accu_var: @x1:0 accu_init: { - CREATE_LIST [25] { + LIST [25] { elements: { } } @@ -2514,7 +2514,7 @@ COMPREHENSION [1] { IDENT [28] { name: @x1:0 } - CREATE_LIST [29] { + LIST [29] { elements: { IDENT [30] { name: @r1 @@ -2546,14 +2546,14 @@ COMPREHENSION [1] { COMPREHENSION [33] { iter_var: #unused iter_range: { - CREATE_LIST [34] { + LIST [34] { elements: { } } } accu_var: @r2 accu_init: { - CREATE_LIST [35] { + LIST [35] { elements: { IDENT [36] { name: @r1 @@ -2573,7 +2573,7 @@ COMPREHENSION [1] { } } result: { - CREATE_LIST [40] { + LIST [40] { elements: { IDENT [41] { name: @r2 @@ -2595,7 +2595,7 @@ Source: [x - 1 > 3 ? x - 1 : 5].exists(x, x - 1 > 3) || x - 1 > 3 COMPREHENSION [1] { iter_var: #unused iter_range: { - CREATE_LIST [2] { + LIST [2] { elements: { } } @@ -2624,7 +2624,7 @@ COMPREHENSION [1] { COMPREHENSION [8] { iter_var: #unused iter_range: { - CREATE_LIST [9] { + LIST [9] { elements: { } } @@ -2656,7 +2656,7 @@ COMPREHENSION [1] { COMPREHENSION [16] { iter_var: @c0:0 iter_range: { - CREATE_LIST [17] { + LIST [17] { elements: { CALL [18] { function: _?_:_ @@ -2741,7 +2741,7 @@ COMPREHENSION [1] { COMPREHENSION [2] { iter_var: @c1:0 iter_range: { - CREATE_LIST [3] { + LIST [3] { elements: { CONSTANT [4] { value: "foo" } CONSTANT [5] { value: "bar" } @@ -2750,7 +2750,7 @@ COMPREHENSION [1] { } accu_var: @x1:0 accu_init: { - CREATE_LIST [6] { + LIST [6] { elements: { } } @@ -2765,12 +2765,12 @@ COMPREHENSION [1] { IDENT [9] { name: @x1:0 } - CREATE_LIST [10] { + LIST [10] { elements: { COMPREHENSION [11] { iter_var: #unused iter_range: { - CREATE_LIST [12] { + LIST [12] { elements: { } } @@ -2798,7 +2798,7 @@ COMPREHENSION [1] { } } result: { - CREATE_LIST [18] { + LIST [18] { elements: { IDENT [19] { name: @r0 @@ -2824,7 +2824,7 @@ COMPREHENSION [1] { } accu_var: @x0:0 accu_init: { - CREATE_LIST [22] { + LIST [22] { elements: { } } @@ -2839,12 +2839,12 @@ COMPREHENSION [1] { IDENT [25] { name: @x0:0 } - CREATE_LIST [26] { + LIST [26] { elements: { COMPREHENSION [27] { iter_var: #unused iter_range: { - CREATE_LIST [28] { + LIST [28] { elements: { } } @@ -2872,7 +2872,7 @@ COMPREHENSION [1] { } } result: { - CREATE_LIST [34] { + LIST [34] { elements: { IDENT [35] { name: @r1 @@ -2901,14 +2901,14 @@ Source: has({'a': true}.a) && {'a':true}['a'] COMPREHENSION [1] { iter_var: #unused iter_range: { - CREATE_LIST [2] { + LIST [2] { elements: { } } } accu_var: @r0 accu_init: { - CREATE_MAP [3] { + MAP [3] { MAP_ENTRY [4] { key: { CONSTANT [5] { value: "a" } @@ -2955,7 +2955,7 @@ Source: has({'a': true}.a) && has({'a': true}.a) COMPREHENSION [1] { iter_var: #unused iter_range: { - CREATE_LIST [2] { + LIST [2] { elements: { } } @@ -2963,7 +2963,7 @@ COMPREHENSION [1] { accu_var: @r0 accu_init: { SELECT [3] { - CREATE_MAP [4] { + MAP [4] { MAP_ENTRY [5] { key: { CONSTANT [6] { value: "a" } @@ -3006,7 +3006,7 @@ CALL [1] { COMPREHENSION [2] { iter_var: #unused iter_range: { - CREATE_LIST [3] { + LIST [3] { elements: { } } @@ -3060,7 +3060,7 @@ CALL [1] { COMPREHENSION [2] { iter_var: #unused iter_range: { - CREATE_LIST [3] { + LIST [3] { elements: { } } @@ -3085,7 +3085,7 @@ CALL [1] { COMPREHENSION [8] { iter_var: #unused iter_range: { - CREATE_LIST [9] { + LIST [9] { elements: { } } @@ -3147,7 +3147,7 @@ CALL [1] { COMPREHENSION [2] { iter_var: #unused iter_range: { - CREATE_LIST [3] { + LIST [3] { elements: { } } @@ -3174,7 +3174,7 @@ CALL [1] { COMPREHENSION [9] { iter_var: #unused iter_range: { - CREATE_LIST [10] { + LIST [10] { elements: { } } @@ -3231,7 +3231,7 @@ Source: (has(msg.oneof_type) && has(msg.oneof_type.payload) && has(msg.oneof_typ COMPREHENSION [1] { iter_var: #unused iter_range: { - CREATE_LIST [2] { + LIST [2] { elements: { } } @@ -3256,7 +3256,7 @@ COMPREHENSION [1] { COMPREHENSION [7] { iter_var: #unused iter_range: { - CREATE_LIST [8] { + LIST [8] { elements: { } } @@ -3309,7 +3309,7 @@ COMPREHENSION [1] { COMPREHENSION [22] { iter_var: #unused iter_range: { - CREATE_LIST [23] { + LIST [23] { elements: { } } @@ -3381,7 +3381,7 @@ CALL [1] { COMPREHENSION [2] { iter_var: #unused iter_range: { - CREATE_LIST [3] { + LIST [3] { elements: { } } @@ -3406,14 +3406,14 @@ CALL [1] { COMPREHENSION [7] { iter_var: #unused iter_range: { - CREATE_LIST [8] { + LIST [8] { elements: { } } } accu_var: @r1 accu_init: { - CREATE_LIST [9] { + LIST [9] { elements: { IDENT [10] { name: @r0 @@ -3434,7 +3434,7 @@ CALL [1] { } } result: { - CREATE_LIST [14] { + LIST [14] { elements: { CONSTANT [15] { value: 10 } IDENT [16] { @@ -3456,14 +3456,14 @@ CALL [1] { COMPREHENSION [19] { iter_var: #unused iter_range: { - CREATE_LIST [20] { + LIST [20] { elements: { } } } accu_var: @r2 accu_init: { - CREATE_LIST [21] { + LIST [21] { elements: { CONSTANT [22] { value: 5 } } @@ -3478,7 +3478,7 @@ CALL [1] { } } result: { - CREATE_LIST [25] { + LIST [25] { elements: { CONSTANT [26] { value: 10 } IDENT [27] { @@ -3502,7 +3502,7 @@ CALL [1] { COMPREHENSION [2] { iter_var: #unused iter_range: { - CREATE_LIST [3] { + LIST [3] { elements: { } } @@ -3512,7 +3512,7 @@ CALL [1] { CALL [4] { function: _[_] args: { - CREATE_MAP [5] { + MAP [5] { MAP_ENTRY [6] { key: { CONSTANT [7] { value: "hello" } @@ -3566,14 +3566,14 @@ CALL [1] { COMPREHENSION [2] { iter_var: #unused iter_range: { - CREATE_LIST [3] { + LIST [3] { elements: { } } } accu_var: @r0 accu_init: { - CREATE_MAP [4] { + MAP [4] { MAP_ENTRY [5] { key: { CONSTANT [6] { value: "key" } @@ -3602,7 +3602,7 @@ CALL [1] { CALL [12] { function: _[?_] args: { - CREATE_MAP [13] { + MAP [13] { MAP_ENTRY [14] { key: { CONSTANT [15] { value: "key" } @@ -3661,14 +3661,14 @@ CALL [1] { COMPREHENSION [2] { iter_var: #unused iter_range: { - CREATE_LIST [3] { + LIST [3] { elements: { } } } accu_var: @r0 accu_init: { - CREATE_STRUCT [4] { + STRUCT [4] { name: TestAllTypes entries: { ENTRY [5] { @@ -3733,7 +3733,7 @@ Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('h' + 'e' + 'l' + 'l' + COMPREHENSION [1] { iter_var: #unused iter_range: { - CREATE_LIST [2] { + LIST [2] { elements: { } } @@ -3949,7 +3949,7 @@ CALL [1] { COMPREHENSION [2] { iter_var: #unused iter_range: { - CREATE_LIST [3] { + LIST [3] { elements: { } } @@ -3976,7 +3976,7 @@ CALL [1] { COMPREHENSION [9] { iter_var: #unused iter_range: { - CREATE_LIST [10] { + LIST [10] { elements: { } } @@ -4059,7 +4059,7 @@ CALL [1] { COMPREHENSION [2] { iter_var: #unused iter_range: { - CREATE_LIST [3] { + LIST [3] { elements: { } } @@ -4086,7 +4086,7 @@ CALL [1] { COMPREHENSION [9] { iter_var: #unused iter_range: { - CREATE_LIST [10] { + LIST [10] { elements: { } } From 8c3fb025f1692c2694782c45a46fdcadb5c9a82c Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Tue, 30 Apr 2024 14:54:56 -0700 Subject: [PATCH 106/486] Remove create modifiers from list,struct,map methods PiperOrigin-RevId: 629537717 --- .../test/java/dev/cel/bundle/CelImplTest.java | 2 +- .../java/dev/cel/checker/ExprChecker.java | 22 +-- .../main/java/dev/cel/common/ast/CelExpr.java | 93 ++++++++----- .../dev/cel/common/ast/CelExprConverter.java | 10 +- .../dev/cel/common/ast/CelExprFactory.java | 6 +- .../dev/cel/common/ast/CelExprFormatter.java | 6 +- .../common/ast/CelExprV1Alpha1Converter.java | 10 +- .../dev/cel/common/ast/CelExprVisitor.java | 6 +- .../dev/cel/common/ast/CelMutableExpr.java | 54 ++++---- .../common/ast/CelMutableExprConverter.java | 27 ++-- .../java/dev/cel/common/ast/Expression.java | 10 +- .../navigation/CelNavigableExprVisitor.java | 6 +- .../navigation/ExprPropertyCalculator.java | 6 +- .../cel/common/ast/CelExprConverterTest.java | 20 +-- .../java/dev/cel/common/ast/CelExprTest.java | 56 ++++---- .../ast/CelExprV1Alpha1ConverterTest.java | 20 +-- .../cel/common/ast/CelExprVisitorTest.java | 38 +++--- .../ast/CelMutableExprConverterTest.java | 36 ++--- .../cel/common/ast/CelMutableExprTest.java | 128 +++++++++--------- .../CelNavigableExprVisitorTest.java | 31 ++--- .../CelNavigableMutableExprTest.java | 12 +- .../dev/cel/extensions/CelMathExtensions.java | 4 +- .../java/dev/cel/optimizer/AstMutator.java | 8 +- .../dev/cel/optimizer/MutableExprVisitor.java | 6 +- .../optimizers/ConstantFoldingOptimizer.java | 20 ++- .../optimizers/SubexpressionOptimizer.java | 4 +- .../dev/cel/optimizer/AstMutatorTest.java | 2 +- .../dev/cel/parser/CelMacroExprFactory.java | 16 +-- .../src/main/java/dev/cel/parser/Parser.java | 6 +- .../cel/parser/CelMacroExprFactoryTest.java | 10 +- .../dev/cel/parser/CelUnparserImplTest.java | 4 +- .../dev/cel/runtime/DefaultInterpreter.java | 10 +- .../java/dev/cel/runtime/CelRuntimeTest.java | 6 +- .../HomogeneousLiteralValidator.java | 6 +- 34 files changed, 357 insertions(+), 344 deletions(-) diff --git a/bundle/src/test/java/dev/cel/bundle/CelImplTest.java b/bundle/src/test/java/dev/cel/bundle/CelImplTest.java index de36d93b9..fc4304657 100644 --- a/bundle/src/test/java/dev/cel/bundle/CelImplTest.java +++ b/bundle/src/test/java/dev/cel/bundle/CelImplTest.java @@ -486,7 +486,7 @@ public void compile_withOptionalTypes() throws Exception { CelAbstractSyntaxTree ast = cel.compile("[?a]").getAst(); - CelList createList = ast.getExpr().createList(); + CelList createList = ast.getExpr().list(); assertThat(createList.optionalIndices()).containsExactly(0); assertThat(createList.elements()).containsExactly(CelExpr.ofIdent(2, "a")); } diff --git a/checker/src/main/java/dev/cel/checker/ExprChecker.java b/checker/src/main/java/dev/cel/checker/ExprChecker.java index 777dd8119..dd5d79f35 100644 --- a/checker/src/main/java/dev/cel/checker/ExprChecker.java +++ b/checker/src/main/java/dev/cel/checker/ExprChecker.java @@ -181,11 +181,11 @@ public CelExpr visit(CelExpr expr) { case CALL: return visit(expr, expr.call()); case LIST: - return visit(expr, expr.createList()); + return visit(expr, expr.list()); case STRUCT: - return visit(expr, expr.createStruct()); + return visit(expr, expr.struct()); case MAP: - return visit(expr, expr.createMap()); + return visit(expr, expr.map()); case COMPREHENSION: return visit(expr, expr.comprehension()); default: @@ -848,32 +848,32 @@ private static CelExpr replaceCallSubtree(CelExpr expr, CelExpr target) { } private static CelExpr replaceListElementSubtree(CelExpr expr, CelExpr element, int index) { - CelExpr.CelList newList = expr.createList().toBuilder().setElement(index, element).build(); - return expr.toBuilder().setCreateList(newList).build(); + CelExpr.CelList newList = expr.list().toBuilder().setElement(index, element).build(); + return expr.toBuilder().setList(newList).build(); } private static CelExpr replaceStructEntryValueSubtree(CelExpr expr, CelExpr newValue, int index) { - CelExpr.CelStruct createStruct = expr.createStruct(); + CelExpr.CelStruct createStruct = expr.struct(); CelExpr.CelStruct.Entry newEntry = createStruct.entries().get(index).toBuilder().setValue(newValue).build(); createStruct = createStruct.toBuilder().setEntry(index, newEntry).build(); - return expr.toBuilder().setCreateStruct(createStruct).build(); + return expr.toBuilder().setStruct(createStruct).build(); } private static CelExpr replaceMapEntryKeySubtree(CelExpr expr, CelExpr newKey, int index) { - CelExpr.CelMap createMap = expr.createMap(); + CelExpr.CelMap createMap = expr.map(); CelExpr.CelMap.Entry newEntry = createMap.entries().get(index).toBuilder().setKey(newKey).build(); createMap = createMap.toBuilder().setEntry(index, newEntry).build(); - return expr.toBuilder().setCreateMap(createMap).build(); + return expr.toBuilder().setMap(createMap).build(); } private static CelExpr replaceMapEntryValueSubtree(CelExpr expr, CelExpr newValue, int index) { - CelExpr.CelMap createMap = expr.createMap(); + CelExpr.CelMap createMap = expr.map(); CelExpr.CelMap.Entry newEntry = createMap.entries().get(index).toBuilder().setValue(newValue).build(); createMap = createMap.toBuilder().setEntry(index, newEntry).build(); - return expr.toBuilder().setCreateMap(createMap).build(); + return expr.toBuilder().setMap(createMap).build(); } private static CelExpr replaceComprehensionAccuInitSubtree(CelExpr expr, CelExpr newAccuInit) { diff --git a/common/src/main/java/dev/cel/common/ast/CelExpr.java b/common/src/main/java/dev/cel/common/ast/CelExpr.java index bac1410bf..0868daa13 100644 --- a/common/src/main/java/dev/cel/common/ast/CelExpr.java +++ b/common/src/main/java/dev/cel/common/ast/CelExpr.java @@ -90,33 +90,60 @@ public CelCall call() { return exprKind().call(); } + /** + * @deprecated Use {@link #list()} instead. + */ + @Deprecated + @InlineMe(replacement = "this.list()") + public final CelList createList() { + return list(); + } + /** * {@inheritDoc} * * @throws UnsupportedOperationException if expression is not {@link Kind#LIST}. */ @Override - public CelList createList() { + public CelList list() { return exprKind().createList(); } + /** + * @deprecated Use {@link #list()} instead. + */ + @Deprecated + @InlineMe(replacement = "this.struct()") + public final CelStruct createStruct() { + return struct(); + } + /** * {@inheritDoc} * * @throws UnsupportedOperationException if expression is not {@link Kind#STRUCT}. */ @Override - public CelStruct createStruct() { + public CelStruct struct() { return exprKind().createStruct(); } + /** + * @deprecated Use {@link #list()} instead. + */ + @Deprecated + @InlineMe(replacement = "this.map()") + public final CelMap createMap() { + return map(); + } + /** * {@inheritDoc} * * @throws UnsupportedOperationException if expression is not {@link Kind#createMap}. */ @Override - public CelMap createMap() { + public CelMap map() { return exprKind().createMap(); } @@ -171,30 +198,30 @@ public CelCall callOrDefault() { } /** - * Gets the underlying createList expression or a default instance of one if expression is not - * {@link Kind#LIST}. + * Gets the underlying list expression or a default instance of one if expression is not {@link + * Kind#LIST}. */ - public CelList createListOrDefault() { + public CelList listOrDefault() { return exprKind().getKind().equals(ExprKind.Kind.LIST) ? exprKind().createList() : CelList.newBuilder().build(); } /** - * Gets the underlying createStruct expression or a default instance of one if expression is not - * {@link Kind#STRUCT}. + * Gets the underlying struct expression or a default instance of one if expression is not {@link + * Kind#STRUCT}. */ - public CelStruct createStructOrDefault() { + public CelStruct structOrDefault() { return exprKind().getKind().equals(ExprKind.Kind.STRUCT) ? exprKind().createStruct() : CelStruct.newBuilder().build(); } /** - * Gets the underlying createMap expression or a default instance of one if expression is not - * {@link Kind#MAP}. + * Gets the underlying map expression or a default instance of one if expression is not {@link + * Kind#MAP}. */ - public CelMap createMapOrDefault() { + public CelMap mapOrDefault() { return exprKind().getKind().equals(ExprKind.Kind.MAP) ? exprKind().createMap() : CelMap.newBuilder().build(); @@ -259,30 +286,30 @@ public CelCall call() { } /** - * Gets the underlying createList expression. + * Gets the underlying list expression. * * @throws UnsupportedOperationException if expression is not {@link Kind#LIST}. */ - public CelList createList() { - return exprKind().createList(); + public CelList list() { + return exprKind().list(); } /** - * Gets the underlying createStruct expression. + * Gets the underlying struct expression. * * @throws UnsupportedOperationException if expression is not {@link Kind#STRUCT}. */ - public CelStruct createStruct() { - return exprKind().createStruct(); + public CelStruct struct() { + return exprKind().struct(); } /** - * Gets the underlying createMap expression. + * Gets the underlying map expression. * - * @throws UnsupportedOperationException if expression is not {@link Kind#createMap}. + * @throws UnsupportedOperationException if expression is not {@link Kind#MAP}. */ - public CelMap createMap() { - return exprKind().createMap(); + public CelMap map() { + return exprKind().map(); } /** @@ -315,18 +342,18 @@ public Builder setSelect(CelSelect select) { } @CanIgnoreReturnValue - public Builder setCreateList(CelList createList) { - return setExprKind(AutoOneOf_CelExpr_ExprKind.list(createList)); + public Builder setList(CelList list) { + return setExprKind(AutoOneOf_CelExpr_ExprKind.list(list)); } @CanIgnoreReturnValue - public Builder setCreateStruct(CelStruct createStruct) { - return setExprKind(AutoOneOf_CelExpr_ExprKind.struct(createStruct)); + public Builder setStruct(CelStruct struct) { + return setExprKind(AutoOneOf_CelExpr_ExprKind.struct(struct)); } @CanIgnoreReturnValue - public Builder setCreateMap(CelMap createMap) { - return setExprKind(AutoOneOf_CelExpr_ExprKind.map(createMap)); + public Builder setMap(CelMap map) { + return setExprKind(AutoOneOf_CelExpr_ExprKind.map(map)); } @CanIgnoreReturnValue @@ -1040,7 +1067,7 @@ public static CelExpr ofCall( .build(); } - public static CelExpr ofCreateList( + public static CelExpr ofList( long id, ImmutableList elements, ImmutableList optionalIndices) { return newBuilder() .setId(id) @@ -1053,7 +1080,7 @@ public static CelExpr ofCreateList( .build(); } - public static CelExpr ofCreateStruct( + public static CelExpr ofStruct( long id, String messageName, ImmutableList entries) { return newBuilder() .setId(id) @@ -1063,7 +1090,7 @@ public static CelExpr ofCreateStruct( .build(); } - public static CelExpr ofCreateMap(long id, ImmutableList entries) { + public static CelExpr ofMap(long id, ImmutableList entries) { return newBuilder() .setId(id) .setExprKind( @@ -1071,7 +1098,7 @@ public static CelExpr ofCreateMap(long id, ImmutableList entries) .build(); } - public static CelStruct.Entry ofCreateStructEntry( + public static CelStruct.Entry ofStructEntry( long id, String fieldKey, CelExpr value, boolean isOptionalEntry) { return CelStruct.Entry.newBuilder() .setId(id) @@ -1081,7 +1108,7 @@ public static CelStruct.Entry ofCreateStructEntry( .build(); } - public static CelMap.Entry ofCreateMapEntry( + public static CelMap.Entry ofMapEntry( long id, CelExpr mapKey, CelExpr value, boolean isOptionalEntry) { return CelMap.Entry.newBuilder() .setId(id) diff --git a/common/src/main/java/dev/cel/common/ast/CelExprConverter.java b/common/src/main/java/dev/cel/common/ast/CelExprConverter.java index cc7942415..994ea3210 100644 --- a/common/src/main/java/dev/cel/common/ast/CelExprConverter.java +++ b/common/src/main/java/dev/cel/common/ast/CelExprConverter.java @@ -121,7 +121,7 @@ public static CelExpr fromExpr(Expr expr) { fromExprList(callExpr.getArgsList())); case LIST_EXPR: CreateList createListExpr = expr.getListExpr(); - return CelExpr.ofCreateList( + return CelExpr.ofList( expr.getId(), fromExprList(createListExpr.getElementsList()), ImmutableList.copyOf(createListExpr.getOptionalIndicesList())); @@ -209,14 +209,14 @@ private static CelExpr exprStructToCelStruct(long id, CreateStruct structExpr) { "Unexpected struct key kind case: " + structExprEntry.getKeyKindCase()); } entries.add( - CelExpr.ofCreateStructEntry( + CelExpr.ofStructEntry( structExprEntry.getId(), structExprEntry.getFieldKey(), fromExpr(structExprEntry.getValue()), structExprEntry.getOptionalEntry())); } - return CelExpr.ofCreateStruct(id, structExpr.getMessageName(), entries.build()); + return CelExpr.ofStruct(id, structExpr.getMessageName(), entries.build()); } else { ImmutableList.Builder entries = ImmutableList.builder(); for (Entry mapExprEntry : structExpr.getEntriesList()) { @@ -225,14 +225,14 @@ private static CelExpr exprStructToCelStruct(long id, CreateStruct structExpr) { "Unexpected map key kind case: " + mapExprEntry.getKeyKindCase()); } entries.add( - CelExpr.ofCreateMapEntry( + CelExpr.ofMapEntry( mapExprEntry.getId(), fromExpr(mapExprEntry.getMapKey()), fromExpr(mapExprEntry.getValue()), mapExprEntry.getOptionalEntry())); } - return CelExpr.ofCreateMap(id, entries.build()); + return CelExpr.ofMap(id, entries.build()); } } diff --git a/common/src/main/java/dev/cel/common/ast/CelExprFactory.java b/common/src/main/java/dev/cel/common/ast/CelExprFactory.java index 6e8a08619..814efc82b 100644 --- a/common/src/main/java/dev/cel/common/ast/CelExprFactory.java +++ b/common/src/main/java/dev/cel/common/ast/CelExprFactory.java @@ -96,7 +96,7 @@ public final CelExpr newList(CelExpr... elements) { public final CelExpr newList(Iterable elements) { return CelExpr.newBuilder() .setId(nextExprId()) - .setCreateList(CelExpr.CelList.newBuilder().addElements(elements).build()) + .setList(CelExpr.CelList.newBuilder().addElements(elements).build()) .build(); } @@ -109,7 +109,7 @@ public final CelExpr newMap(CelExpr.CelMap.Entry... entries) { public final CelExpr newMap(Iterable entries) { return CelExpr.newBuilder() .setId(nextExprId()) - .setCreateMap(CelExpr.CelMap.newBuilder().addEntries(entries).build()) + .setMap(CelExpr.CelMap.newBuilder().addEntries(entries).build()) .build(); } @@ -132,7 +132,7 @@ public final CelExpr newMessage(String typeName, Iterable entries = ImmutableList.builder(); for (Entry mapExprEntry : structExpr.getEntriesList()) { @@ -225,14 +225,14 @@ private static CelExpr exprStructToCelStruct(long id, CreateStruct structExpr) { "Unexpected map key kind case: " + mapExprEntry.getKeyKindCase()); } entries.add( - CelExpr.ofCreateMapEntry( + CelExpr.ofMapEntry( mapExprEntry.getId(), fromExpr(mapExprEntry.getMapKey()), fromExpr(mapExprEntry.getValue()), mapExprEntry.getOptionalEntry())); } - return CelExpr.ofCreateMap(id, entries.build()); + return CelExpr.ofMap(id, entries.build()); } } diff --git a/common/src/main/java/dev/cel/common/ast/CelExprVisitor.java b/common/src/main/java/dev/cel/common/ast/CelExprVisitor.java index e35b19aca..2dc1074eb 100644 --- a/common/src/main/java/dev/cel/common/ast/CelExprVisitor.java +++ b/common/src/main/java/dev/cel/common/ast/CelExprVisitor.java @@ -61,13 +61,13 @@ public void visit(CelExpr expr) { visit(expr, expr.call()); break; case LIST: - visit(expr, expr.createList()); + visit(expr, expr.list()); break; case STRUCT: - visit(expr, expr.createStruct()); + visit(expr, expr.struct()); break; case MAP: - visit(expr, expr.createMap()); + visit(expr, expr.map()); break; case COMPREHENSION: visit(expr, expr.comprehension()); diff --git a/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java b/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java index 1ea48d420..d267d7b8b 100644 --- a/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java +++ b/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java @@ -85,19 +85,19 @@ public CelMutableCall call() { } @Override - public CelMutableList createList() { + public CelMutableList list() { checkExprKind(Kind.LIST); return (CelMutableList) exprValue; } @Override - public CelMutableStruct createStruct() { + public CelMutableStruct struct() { checkExprKind(Kind.STRUCT); return (CelMutableStruct) exprValue; } @Override - public CelMutableMap createMap() { + public CelMutableMap map() { checkExprKind(Kind.MAP); return (CelMutableMap) exprValue; } @@ -128,19 +128,19 @@ public void setCall(CelMutableCall call) { this.exprValue = checkNotNull(call); } - public void setCreateList(CelMutableList createList) { + public void setList(CelMutableList list) { this.exprKind = ExprKind.Kind.LIST; - this.exprValue = checkNotNull(createList); + this.exprValue = checkNotNull(list); } - public void setCreateStruct(CelMutableStruct createStruct) { + public void setStruct(CelMutableStruct struct) { this.exprKind = ExprKind.Kind.STRUCT; - this.exprValue = checkNotNull(createStruct); + this.exprValue = checkNotNull(struct); } - public void setCreateMap(CelMutableMap createMap) { + public void setMap(CelMutableMap map) { this.exprKind = ExprKind.Kind.MAP; - this.exprValue = checkNotNull(createMap); + this.exprValue = checkNotNull(map); } public void setComprehension(CelMutableComprehension comprehension) { @@ -973,27 +973,27 @@ public static CelMutableExpr ofCall(long id, CelMutableCall mutableCall) { return new CelMutableExpr(id, mutableCall); } - public static CelMutableExpr ofCreateList(CelMutableList mutableCreateList) { - return ofCreateList(0, mutableCreateList); + public static CelMutableExpr ofList(CelMutableList mutableCreateList) { + return ofList(0, mutableCreateList); } - public static CelMutableExpr ofCreateList(long id, CelMutableList mutableCreateList) { + public static CelMutableExpr ofList(long id, CelMutableList mutableCreateList) { return new CelMutableExpr(id, mutableCreateList); } - public static CelMutableExpr ofCreateStruct(CelMutableStruct mutableCreateStruct) { - return ofCreateStruct(0, mutableCreateStruct); + public static CelMutableExpr ofStruct(CelMutableStruct mutableCreateStruct) { + return ofStruct(0, mutableCreateStruct); } - public static CelMutableExpr ofCreateStruct(long id, CelMutableStruct mutableCreateStruct) { + public static CelMutableExpr ofStruct(long id, CelMutableStruct mutableCreateStruct) { return new CelMutableExpr(id, mutableCreateStruct); } - public static CelMutableExpr ofCreateMap(CelMutableMap mutableCreateMap) { - return ofCreateMap(0, mutableCreateMap); + public static CelMutableExpr ofMap(CelMutableMap mutableCreateMap) { + return ofMap(0, mutableCreateMap); } - public static CelMutableExpr ofCreateMap(long id, CelMutableMap mutableCreateMap) { + public static CelMutableExpr ofMap(long id, CelMutableMap mutableCreateMap) { return new CelMutableExpr(id, mutableCreateMap); } @@ -1029,17 +1029,17 @@ private CelMutableExpr(long id, CelMutableCall mutableCall) { private CelMutableExpr(long id, CelMutableList mutableCreateList) { this.id = id; - setCreateList(mutableCreateList); + setList(mutableCreateList); } private CelMutableExpr(long id, CelMutableStruct mutableCreateStruct) { this.id = id; - setCreateStruct(mutableCreateStruct); + setStruct(mutableCreateStruct); } private CelMutableExpr(long id, CelMutableMap mutableCreateMap) { this.id = id; - setCreateMap(mutableCreateMap); + setMap(mutableCreateMap); } private CelMutableExpr(long id, CelMutableComprehension mutableComprehension) { @@ -1078,13 +1078,13 @@ private CelMutableExpr(CelMutableExpr other) { this.exprValue = other.call().deepCopy(); break; case LIST: - this.exprValue = other.createList().deepCopy(); + this.exprValue = other.list().deepCopy(); break; case STRUCT: - this.exprValue = other.createStruct().deepCopy(); + this.exprValue = other.struct().deepCopy(); break; case MAP: - this.exprValue = other.createMap().deepCopy(); + this.exprValue = other.map().deepCopy(); break; case COMPREHENSION: this.exprValue = other.comprehension().deepCopy(); @@ -1107,11 +1107,11 @@ private Object exprValue() { case CALL: return call(); case LIST: - return createList(); + return list(); case STRUCT: - return createStruct(); + return struct(); case MAP: - return createMap(); + return map(); case COMPREHENSION: return comprehension(); } diff --git a/common/src/main/java/dev/cel/common/ast/CelMutableExprConverter.java b/common/src/main/java/dev/cel/common/ast/CelMutableExprConverter.java index a7c51342d..57d4e9dc8 100644 --- a/common/src/main/java/dev/cel/common/ast/CelMutableExprConverter.java +++ b/common/src/main/java/dev/cel/common/ast/CelMutableExprConverter.java @@ -66,17 +66,16 @@ public static CelMutableExpr fromCelExpr(CelExpr celExpr) { return CelMutableExpr.ofCall(celExpr.id(), mutableCall); case LIST: - CelList createList = celExpr.createList(); - return CelMutableExpr.ofCreateList( + CelList createList = celExpr.list(); + return CelMutableExpr.ofList( celExpr.id(), CelMutableList.create( fromCelExprList(createList.elements()), createList.optionalIndices())); case STRUCT: - return CelMutableExpr.ofCreateStruct( - celExpr.id(), fromCelStructToMutableStruct(celExpr.createStruct())); + return CelMutableExpr.ofStruct( + celExpr.id(), fromCelStructToMutableStruct(celExpr.struct())); case MAP: - return CelMutableExpr.ofCreateMap( - celExpr.id(), fromCelMapToMutableMap(celExpr.createMap())); + return CelMutableExpr.ofMap(celExpr.id(), fromCelMapToMutableMap(celExpr.map())); case COMPREHENSION: CelComprehension celComprehension = celExprKind.comprehension(); CelMutableComprehension mutableComprehension = @@ -154,22 +153,22 @@ public static CelExpr fromMutableExpr(CelMutableExpr mutableExpr) { mutableCall.target().map(CelMutableExprConverter::fromMutableExpr); return CelExpr.ofCall(id, targetExpr, mutableCall.function(), args); case LIST: - CelMutableList mutableCreateList = mutableExpr.createList(); - return CelExpr.ofCreateList( + CelMutableList mutableCreateList = mutableExpr.list(); + return CelExpr.ofList( id, fromMutableExprList(mutableCreateList.elements()), ImmutableList.copyOf(mutableCreateList.optionalIndices())); case STRUCT: - CelMutableStruct mutableCreateStruct = mutableExpr.createStruct(); + CelMutableStruct mutableCreateStruct = mutableExpr.struct(); return CelExpr.newBuilder() .setId(id) - .setCreateStruct(fromMutableStructToCelStruct(mutableCreateStruct)) + .setStruct(fromMutableStructToCelStruct(mutableCreateStruct)) .build(); case MAP: - CelMutableMap mutableCreateMap = mutableExpr.createMap(); + CelMutableMap mutableCreateMap = mutableExpr.map(); return CelExpr.newBuilder() .setId(id) - .setCreateMap(fromMutableMapToCelMap(mutableCreateMap)) + .setMap(fromMutableMapToCelMap(mutableCreateMap)) .build(); case COMPREHENSION: CelMutableComprehension mutableComprehension = mutableExpr.comprehension(); @@ -202,7 +201,7 @@ private static CelStruct fromMutableStructToCelStruct(CelMutableStruct mutableCr List entries = new ArrayList<>(); for (CelMutableStruct.Entry mutableStructEntry : mutableCreateStruct.entries()) { entries.add( - CelExpr.ofCreateStructEntry( + CelExpr.ofStructEntry( mutableStructEntry.id(), mutableStructEntry.fieldKey(), fromMutableExpr(mutableStructEntry.value()), @@ -219,7 +218,7 @@ private static CelMap fromMutableMapToCelMap(CelMutableMap mutableCreateMap) { List entries = new ArrayList<>(); for (CelMutableMap.Entry mutableMapEntry : mutableCreateMap.entries()) { entries.add( - CelExpr.ofCreateMapEntry( + CelExpr.ofMapEntry( mutableMapEntry.id(), fromMutableExpr(mutableMapEntry.key()), fromMutableExpr(mutableMapEntry.value()), diff --git a/common/src/main/java/dev/cel/common/ast/Expression.java b/common/src/main/java/dev/cel/common/ast/Expression.java index 16852a15c..ed06af8b9 100644 --- a/common/src/main/java/dev/cel/common/ast/Expression.java +++ b/common/src/main/java/dev/cel/common/ast/Expression.java @@ -54,16 +54,16 @@ public interface Expression { Call call(); /** Gets the underlying identifier expression. */ - List createList(); + List list(); /** Gets the underlying select expression. */ Select select(); - /** Gets the underlying createStruct expression. */ - Struct> createStruct(); + /** Gets the underlying struct expression. */ + Struct> struct(); - /** Gets the underlying createMap expression. */ - Map> createMap(); + /** Gets the underlying map expression. */ + Map> map(); /** Gets the underlying comprehension expression. */ Comprehension comprehension(); diff --git a/common/src/main/java/dev/cel/common/navigation/CelNavigableExprVisitor.java b/common/src/main/java/dev/cel/common/navigation/CelNavigableExprVisitor.java index 41e9802a0..b59acdd13 100644 --- a/common/src/main/java/dev/cel/common/navigation/CelNavigableExprVisitor.java +++ b/common/src/main/java/dev/cel/common/navigation/CelNavigableExprVisitor.java @@ -106,16 +106,16 @@ private void visit(T navigableExpr) { visit(navigableExpr, navigableExpr.expr().call()); break; case LIST: - visit(navigableExpr, navigableExpr.expr().createList()); + visit(navigableExpr, navigableExpr.expr().list()); break; case SELECT: visit(navigableExpr, navigableExpr.expr().select()); break; case STRUCT: - visitStruct(navigableExpr, navigableExpr.expr().createStruct()); + visitStruct(navigableExpr, navigableExpr.expr().struct()); break; case MAP: - visitMap(navigableExpr, navigableExpr.expr().createMap()); + visitMap(navigableExpr, navigableExpr.expr().map()); break; case COMPREHENSION: visit(navigableExpr, navigableExpr.expr().comprehension()); diff --git a/common/src/main/java/dev/cel/common/navigation/ExprPropertyCalculator.java b/common/src/main/java/dev/cel/common/navigation/ExprPropertyCalculator.java index 7c59682f8..b35682ef3 100644 --- a/common/src/main/java/dev/cel/common/navigation/ExprPropertyCalculator.java +++ b/common/src/main/java/dev/cel/common/navigation/ExprPropertyCalculator.java @@ -55,16 +55,16 @@ private ExprProperty visit(E expr) { visitedProperty = visit(expr.call()); break; case LIST: - visitedProperty = visit(expr.createList()); + visitedProperty = visit(expr.list()); break; case SELECT: visitedProperty = visit(expr.select()); break; case STRUCT: - visitedProperty = visitStruct(expr.createStruct()); + visitedProperty = visitStruct(expr.struct()); break; case MAP: - visitedProperty = visitMap(expr.createMap()); + visitedProperty = visitMap(expr.map()); break; case COMPREHENSION: visitedProperty = visit(expr.comprehension()); diff --git a/common/src/test/java/dev/cel/common/ast/CelExprConverterTest.java b/common/src/test/java/dev/cel/common/ast/CelExprConverterTest.java index 424031dd4..8cac69522 100644 --- a/common/src/test/java/dev/cel/common/ast/CelExprConverterTest.java +++ b/common/src/test/java/dev/cel/common/ast/CelExprConverterTest.java @@ -191,7 +191,7 @@ public void convertExprList_toCelList() { assertThat(celExpr) .isEqualTo( - CelExpr.ofCreateList( + CelExpr.ofList( 1, ImmutableList.of( CelExpr.ofConstant(2, CelConstant.ofValue(10)), @@ -221,11 +221,11 @@ public void convertExprStructExpr_toCelStruct() { assertThat(celExpr) .isEqualTo( - CelExpr.ofCreateStruct( + CelExpr.ofStruct( 1, "messageName", ImmutableList.of( - CelExpr.ofCreateStructEntry( + CelExpr.ofStructEntry( 2, "fieldKey", CelExpr.ofConstant(3, CelConstant.ofValue(10)), true)))); } @@ -299,10 +299,10 @@ public void convertExprStructExpr_toCelMap() { assertThat(celExpr) .isEqualTo( - CelExpr.ofCreateMap( + CelExpr.ofMap( 1, ImmutableList.of( - CelExpr.ofCreateMapEntry( + CelExpr.ofMapEntry( 2, CelExpr.ofConstant(3, CelConstant.ofValue(15)), CelExpr.ofConstant(4, CelConstant.ofValue(10)), @@ -453,7 +453,7 @@ public void convertCelCall_toExprCall() { @Test public void convertCelList_toExprList() { CelExpr celExpr = - CelExpr.ofCreateList( + CelExpr.ofList( 1, ImmutableList.of( CelExpr.ofConstant(2, CelConstant.ofValue(10)), @@ -478,11 +478,11 @@ public void convertCelList_toExprList() { @Test public void convertCelStructExpr_toExprStruct_withFieldKey() { CelExpr celExpr = - CelExpr.ofCreateStruct( + CelExpr.ofStruct( 1, "messageName", ImmutableList.of( - CelExpr.ofCreateStructEntry( + CelExpr.ofStructEntry( 2, "fieldKey", CelExpr.ofConstant(3, CelConstant.ofValue(10)), true))); Expr expr = CelExprConverter.fromCelExpr(celExpr); @@ -508,10 +508,10 @@ public void convertCelStructExpr_toExprStruct_withFieldKey() { @Test public void convertCelMapExpr_toExprStruct() { CelExpr celExpr = - CelExpr.ofCreateMap( + CelExpr.ofMap( 1, ImmutableList.of( - CelExpr.ofCreateMapEntry( + CelExpr.ofMapEntry( 2, CelExpr.ofConstant(3, CelConstant.ofValue(15)), CelExpr.ofConstant(4, CelConstant.ofValue(10)), diff --git a/common/src/test/java/dev/cel/common/ast/CelExprTest.java b/common/src/test/java/dev/cel/common/ast/CelExprTest.java index 5df979e41..ec4cceeab 100644 --- a/common/src/test/java/dev/cel/common/ast/CelExprTest.java +++ b/common/src/test/java/dev/cel/common/ast/CelExprTest.java @@ -66,11 +66,10 @@ private enum BuilderExprKindTestCase { .build()) .build(), Kind.SELECT), - CREATE_MAP(CelExpr.newBuilder().setCreateMap(CelMap.newBuilder().build()).build(), Kind.MAP), - CREATE_LIST( - CelExpr.newBuilder().setCreateList(CelList.newBuilder().build()).build(), Kind.LIST), + CREATE_MAP(CelExpr.newBuilder().setMap(CelMap.newBuilder().build()).build(), Kind.MAP), + CREATE_LIST(CelExpr.newBuilder().setList(CelList.newBuilder().build()).build(), Kind.LIST), CREATE_STRUCT( - CelExpr.newBuilder().setCreateStruct(CelStruct.newBuilder().build()).build(), Kind.STRUCT), + CelExpr.newBuilder().setStruct(CelStruct.newBuilder().build()).build(), Kind.STRUCT), COMPREHENSION( CelExpr.newBuilder() .setComprehension( @@ -202,10 +201,10 @@ public void celExprBuilder_setSelect() { public void celExprBuilder_setCreateList() { CelList celCreateList = CelList.newBuilder().addElements(CelExpr.ofConstant(1, CelConstant.ofValue(2))).build(); - CelExpr celExpr = CelExpr.newBuilder().setCreateList(celCreateList).build(); + CelExpr celExpr = CelExpr.newBuilder().setList(celCreateList).build(); - assertThat(celExpr.createList()).isEqualTo(celCreateList); - assertThat(celExpr.toBuilder().createList()).isEqualTo(celCreateList); + assertThat(celExpr.list()).isEqualTo(celCreateList); + assertThat(celExpr.toBuilder().list()).isEqualTo(celCreateList); } @Test @@ -228,13 +227,13 @@ public void celExprBuilder_setCreateList_setElementByIndex() { CelExpr celExpr = CelExpr.newBuilder() - .setCreateList( + .setList( celCreateList.toBuilder() .setElement(1, CelExpr.ofConstant(7, CelConstant.ofValue("world"))) .build()) .build(); - assertThat(celExpr.createList()) + assertThat(celExpr.list()) .isEqualTo( CelList.newBuilder() .addElements( @@ -254,11 +253,11 @@ public void celExprBuilder_setCreateStruct() { .setFieldKey("field_key") .build()) .build(); - CelExpr celExpr = CelExpr.newBuilder().setCreateStruct(celCreateStruct).build(); + CelExpr celExpr = CelExpr.newBuilder().setStruct(celCreateStruct).build(); - assertThat(celExpr.createStruct().entries().get(0).optionalEntry()).isFalse(); - assertThat(celExpr.createStruct()).isEqualTo(celCreateStruct); - assertThat(celExpr.toBuilder().createStruct()).isEqualTo(celCreateStruct); + assertThat(celExpr.struct().entries().get(0).optionalEntry()).isFalse(); + assertThat(celExpr.struct()).isEqualTo(celCreateStruct); + assertThat(celExpr.toBuilder().struct()).isEqualTo(celCreateStruct); } @Test @@ -302,7 +301,7 @@ public void celExprBuilder_setCreateStruct_setEntryByIndex() { CelExpr celExpr = CelExpr.newBuilder() - .setCreateStruct( + .setStruct( celCreateStruct.toBuilder() .setEntry( 1, @@ -316,7 +315,7 @@ public void celExprBuilder_setCreateStruct_setEntryByIndex() { .build()) .build(); - assertThat(celExpr.createStruct()) + assertThat(celExpr.struct()) .isEqualTo( CelStruct.newBuilder() .addEntries( @@ -378,19 +377,16 @@ public void getUnderlyingExpression_unmatchedKind_throws( assertThrows(UnsupportedOperationException.class, () -> testCase.expr.toBuilder().call()); } if (!testCase.expectedExprKind.equals(Kind.LIST)) { - assertThrows(UnsupportedOperationException.class, testCase.expr::createList); - assertThrows( - UnsupportedOperationException.class, () -> testCase.expr.toBuilder().createList()); + assertThrows(UnsupportedOperationException.class, testCase.expr::list); + assertThrows(UnsupportedOperationException.class, () -> testCase.expr.toBuilder().list()); } if (!testCase.expectedExprKind.equals(Kind.STRUCT)) { - assertThrows(UnsupportedOperationException.class, testCase.expr::createStruct); - assertThrows( - UnsupportedOperationException.class, () -> testCase.expr.toBuilder().createStruct()); + assertThrows(UnsupportedOperationException.class, testCase.expr::struct); + assertThrows(UnsupportedOperationException.class, () -> testCase.expr.toBuilder().struct()); } if (!testCase.expectedExprKind.equals(Kind.MAP)) { - assertThrows(UnsupportedOperationException.class, testCase.expr::createMap); - assertThrows( - UnsupportedOperationException.class, () -> testCase.expr.toBuilder().createMap()); + assertThrows(UnsupportedOperationException.class, testCase.expr::map); + assertThrows(UnsupportedOperationException.class, () -> testCase.expr.toBuilder().map()); } if (!testCase.expectedExprKind.equals(Kind.COMPREHENSION)) { assertThrows(UnsupportedOperationException.class, testCase.expr::comprehension); @@ -415,13 +411,13 @@ public void getDefault_unmatchedKind_returnsDefaultInstance( assertThat(testCase.expr.callOrDefault()).isEqualTo(CelCall.newBuilder().build()); } if (!testCase.expectedExprKind.equals(Kind.LIST)) { - assertThat(testCase.expr.createListOrDefault()).isEqualTo(CelList.newBuilder().build()); + assertThat(testCase.expr.listOrDefault()).isEqualTo(CelList.newBuilder().build()); } if (!testCase.expectedExprKind.equals(Kind.STRUCT)) { - assertThat(testCase.expr.createStructOrDefault()).isEqualTo(CelStruct.newBuilder().build()); + assertThat(testCase.expr.structOrDefault()).isEqualTo(CelStruct.newBuilder().build()); } if (!testCase.expectedExprKind.equals(Kind.MAP)) { - assertThat(testCase.expr.createMapOrDefault()).isEqualTo(CelMap.newBuilder().build()); + assertThat(testCase.expr.mapOrDefault()).isEqualTo(CelMap.newBuilder().build()); } if (!testCase.expectedExprKind.equals(Kind.COMPREHENSION)) { assertThat(testCase.expr.comprehensionOrDefault()) @@ -449,13 +445,13 @@ public void getDefault_matchedKind_returnsUnderlyingExpression( assertThat(testCase.expr.callOrDefault()).isEqualTo(testCase.expr.call()); break; case LIST: - assertThat(testCase.expr.createListOrDefault()).isEqualTo(testCase.expr.createList()); + assertThat(testCase.expr.listOrDefault()).isEqualTo(testCase.expr.list()); break; case STRUCT: - assertThat(testCase.expr.createStructOrDefault()).isEqualTo(testCase.expr.createStruct()); + assertThat(testCase.expr.structOrDefault()).isEqualTo(testCase.expr.struct()); break; case MAP: - assertThat(testCase.expr.createMapOrDefault()).isEqualTo(testCase.expr.createMap()); + assertThat(testCase.expr.mapOrDefault()).isEqualTo(testCase.expr.map()); break; case COMPREHENSION: assertThat(testCase.expr.comprehensionOrDefault()).isEqualTo(testCase.expr.comprehension()); diff --git a/common/src/test/java/dev/cel/common/ast/CelExprV1Alpha1ConverterTest.java b/common/src/test/java/dev/cel/common/ast/CelExprV1Alpha1ConverterTest.java index 8a5461a11..28df2285d 100644 --- a/common/src/test/java/dev/cel/common/ast/CelExprV1Alpha1ConverterTest.java +++ b/common/src/test/java/dev/cel/common/ast/CelExprV1Alpha1ConverterTest.java @@ -191,7 +191,7 @@ public void convertExprList_toCelList() { assertThat(celExpr) .isEqualTo( - CelExpr.ofCreateList( + CelExpr.ofList( 1, ImmutableList.of( CelExpr.ofConstant(2, CelConstant.ofValue(10)), @@ -221,11 +221,11 @@ public void convertExprStructExpr_toCelStruct() { assertThat(celExpr) .isEqualTo( - CelExpr.ofCreateStruct( + CelExpr.ofStruct( 1, "messageName", ImmutableList.of( - CelExpr.ofCreateStructEntry( + CelExpr.ofStructEntry( 2, "fieldKey", CelExpr.ofConstant(3, CelConstant.ofValue(10)), true)))); } @@ -299,10 +299,10 @@ public void convertExprStructExpr_toCelMap() { assertThat(celExpr) .isEqualTo( - CelExpr.ofCreateMap( + CelExpr.ofMap( 1, ImmutableList.of( - CelExpr.ofCreateMapEntry( + CelExpr.ofMapEntry( 2, CelExpr.ofConstant(3, CelConstant.ofValue(15)), CelExpr.ofConstant(4, CelConstant.ofValue(10)), @@ -453,7 +453,7 @@ public void convertCelCall_toExprCall() { @Test public void convertCelList_toExprList() { CelExpr celExpr = - CelExpr.ofCreateList( + CelExpr.ofList( 1, ImmutableList.of( CelExpr.ofConstant(2, CelConstant.ofValue(10)), @@ -478,11 +478,11 @@ public void convertCelList_toExprList() { @Test public void convertCelStructExpr_toExprStruct_withFieldKey() { CelExpr celExpr = - CelExpr.ofCreateStruct( + CelExpr.ofStruct( 1, "messageName", ImmutableList.of( - CelExpr.ofCreateStructEntry( + CelExpr.ofStructEntry( 2, "fieldKey", CelExpr.ofConstant(3, CelConstant.ofValue(10)), true))); Expr expr = CelExprV1Alpha1Converter.fromCelExpr(celExpr); @@ -508,10 +508,10 @@ public void convertCelStructExpr_toExprStruct_withFieldKey() { @Test public void convertCelMapExpr_toExprStruct() { CelExpr celExpr = - CelExpr.ofCreateMap( + CelExpr.ofMap( 1, ImmutableList.of( - CelExpr.ofCreateMapEntry( + CelExpr.ofMapEntry( 2, CelExpr.ofConstant(3, CelConstant.ofValue(15)), CelExpr.ofConstant(4, CelConstant.ofValue(10)), diff --git a/common/src/test/java/dev/cel/common/ast/CelExprVisitorTest.java b/common/src/test/java/dev/cel/common/ast/CelExprVisitorTest.java index cec7fa4fa..2ba8da806 100644 --- a/common/src/test/java/dev/cel/common/ast/CelExprVisitorTest.java +++ b/common/src/test/java/dev/cel/common/ast/CelExprVisitorTest.java @@ -53,11 +53,11 @@ public abstract static class VisitedReference { public abstract Optional call(); - public abstract Optional createStruct(); + public abstract Optional struct(); - public abstract Optional createMap(); + public abstract Optional map(); - public abstract Optional createList(); + public abstract Optional list(); public abstract Optional comprehension(); @@ -73,11 +73,11 @@ public abstract static class Builder { public abstract Builder setCall(CelCall value); - public abstract Builder setCreateStruct(CelStruct value); + public abstract Builder setStruct(CelStruct value); - public abstract Builder setCreateMap(CelMap value); + public abstract Builder setMap(CelMap value); - public abstract Builder setCreateList(CelList value); + public abstract Builder setList(CelList value); public abstract Builder setComprehension(CelComprehension value); @@ -125,19 +125,19 @@ protected void visit(CelExpr expr, CelCall call) { @Override protected void visit(CelExpr expr, CelStruct createStruct) { - visitedReference.setCreateStruct(createStruct); + visitedReference.setStruct(createStruct); super.visit(expr, createStruct); } @Override protected void visit(CelExpr expr, CelMap createMap) { - visitedReference.setCreateMap(createMap); + visitedReference.setMap(createMap); super.visit(expr, createMap); } @Override protected void visit(CelExpr expr, CelList createList) { - visitedReference.setCreateList(createList); + visitedReference.setList(createList); super.visit(expr, createList); } @@ -204,13 +204,13 @@ public void visitSelect() throws Exception { assertThat(visited) .isEqualTo( VisitedReference.newBuilder() - .setCreateStruct(CelStruct.newBuilder().setMessageName("TestAllTypes").build()) + .setStruct(CelStruct.newBuilder().setMessageName("TestAllTypes").build()) .setSelect( CelSelect.newBuilder() .setOperand( CelExpr.newBuilder() .setId(1) - .setCreateStruct( + .setStruct( CelStruct.newBuilder().setMessageName("TestAllTypes").build()) .build()) .setField("single_int64") @@ -242,7 +242,7 @@ public void visitCall() throws Exception { } @Test - public void visitCreateStruct_fieldkey() throws Exception { + public void visitStruct_fieldkey() throws Exception { CelCompiler celCompiler = CelCompilerFactory.standardCelCompilerBuilder() .addMessageTypes(TestAllTypes.getDescriptor()) @@ -258,7 +258,7 @@ public void visitCreateStruct_fieldkey() throws Exception { .isEqualTo( VisitedReference.newBuilder() .setConstant(longConstant) - .setCreateStruct( + .setStruct( CelStruct.newBuilder() .addEntries( Entry.newBuilder() @@ -272,7 +272,7 @@ public void visitCreateStruct_fieldkey() throws Exception { } @Test - public void visitCreateMap() throws Exception { + public void visitMap() throws Exception { CelCompiler celCompiler = CelCompilerFactory.standardCelCompilerBuilder().build(); CelAbstractSyntaxTree ast = celCompiler.compile("{'a': 'b'}").getAst(); @@ -283,7 +283,7 @@ public void visitCreateMap() throws Exception { .isEqualTo( VisitedReference.newBuilder() .setConstant(CelConstant.ofValue("b")) - .setCreateMap( + .setMap( CelMap.newBuilder() .addEntries( CelMap.Entry.newBuilder() @@ -296,7 +296,7 @@ public void visitCreateMap() throws Exception { } @Test - public void visitCreateList() throws Exception { + public void visitList() throws Exception { CelCompiler celCompiler = CelCompilerFactory.standardCelCompilerBuilder().build(); CelAbstractSyntaxTree ast = celCompiler.compile("[1, 1]").getAst(); @@ -308,7 +308,7 @@ public void visitCreateList() throws Exception { .isEqualTo( VisitedReference.newBuilder() .setConstant(integerVal) - .setCreateList( + .setList( CelList.newBuilder() .addElements(CelExpr.newBuilder().setId(2).setConstant(integerVal).build()) .addElements(CelExpr.newBuilder().setId(3).setConstant(integerVal).build()) @@ -334,14 +334,14 @@ public void visitComprehension() throws Exception { CelExpr.ofConstant(3, CelConstant.ofValue(1))); assertThat(comprehension.iterVar()).isEqualTo("x"); - assertThat(comprehension.iterRange().createList().elements()).isEqualTo(iterRangeElements); + assertThat(comprehension.iterRange().list().elements()).isEqualTo(iterRangeElements); assertThat(comprehension.accuInit().constant()).isEqualTo(CelConstant.ofValue(true)); assertThat(comprehension.loopCondition().call().function()) .isEqualTo(Operator.NOT_STRICTLY_FALSE.getFunction()); assertThat(comprehension.loopStep().call().function()) .isEqualTo(Operator.LOGICAL_AND.getFunction()); assertThat(comprehension.loopStep().call().args()).hasSize(2); - assertThat(visitedReference.createList().get().elements()).isEqualTo(iterRangeElements); + assertThat(visitedReference.list().get().elements()).isEqualTo(iterRangeElements); assertThat(visitedReference.identifier()) .hasValue(CelIdent.newBuilder().setName("__result__").build()); assertThat(visitedReference.arguments()).hasSize(10); diff --git a/common/src/test/java/dev/cel/common/ast/CelMutableExprConverterTest.java b/common/src/test/java/dev/cel/common/ast/CelMutableExprConverterTest.java index 927c10243..9fb2140a0 100644 --- a/common/src/test/java/dev/cel/common/ast/CelMutableExprConverterTest.java +++ b/common/src/test/java/dev/cel/common/ast/CelMutableExprConverterTest.java @@ -201,7 +201,7 @@ public void convertCelCall_toMutableCall() { @Test public void convertMutableCreateList_toCelList() { CelMutableExpr mutableExpr = - CelMutableExpr.ofCreateList( + CelMutableExpr.ofList( 1L, CelMutableList.create( ImmutableList.of( @@ -213,7 +213,7 @@ public void convertMutableCreateList_toCelList() { assertThat(celExpr) .isEqualTo( - CelExpr.ofCreateList( + CelExpr.ofList( 1L, ImmutableList.of( CelExpr.ofConstant(2L, CelConstant.ofValue("element1")), @@ -224,7 +224,7 @@ public void convertMutableCreateList_toCelList() { @Test public void convertCelList_toMutableCreateList() { CelExpr celExpr = - CelExpr.ofCreateList( + CelExpr.ofList( 1L, ImmutableList.of( CelExpr.ofConstant(2L, CelConstant.ofValue("element1")), @@ -235,7 +235,7 @@ public void convertCelList_toMutableCreateList() { assertThat(mutableExpr) .isEqualTo( - CelMutableExpr.ofCreateList( + CelMutableExpr.ofList( 1L, CelMutableList.create( ImmutableList.of( @@ -247,7 +247,7 @@ public void convertCelList_toMutableCreateList() { @Test public void convertMutableCreateStruct_toCelStruct() { CelMutableExpr mutableExpr = - CelMutableExpr.ofCreateStruct( + CelMutableExpr.ofStruct( 8L, CelMutableStruct.create( "message", @@ -262,7 +262,7 @@ public void convertMutableCreateStruct_toCelStruct() { assertThat(celExpr) .isEqualTo( - CelExpr.ofCreateStruct( + CelExpr.ofStruct( 8L, "message", ImmutableList.of( @@ -277,7 +277,7 @@ public void convertMutableCreateStruct_toCelStruct() { @Test public void convertCelStruct_toMutableCreateStruct() { CelExpr celExpr = - CelExpr.ofCreateStruct( + CelExpr.ofStruct( 8L, "message", ImmutableList.of( @@ -292,7 +292,7 @@ public void convertCelStruct_toMutableCreateStruct() { assertThat(mutableExpr) .isEqualTo( - CelMutableExpr.ofCreateStruct( + CelMutableExpr.ofStruct( 8L, CelMutableStruct.create( "message", @@ -307,7 +307,7 @@ public void convertCelStruct_toMutableCreateStruct() { @Test public void convertMutableCreateMap_toCelMap() { CelMutableExpr mutableExpr = - CelMutableExpr.ofCreateMap( + CelMutableExpr.ofMap( 9L, CelMutableMap.create( ImmutableList.of( @@ -321,10 +321,10 @@ public void convertMutableCreateMap_toCelMap() { assertThat(celExpr) .isEqualTo( - CelExpr.ofCreateMap( + CelExpr.ofMap( 9L, ImmutableList.of( - CelExpr.ofCreateMapEntry( + CelExpr.ofMapEntry( 10L, CelExpr.ofConstant(11L, CelConstant.ofValue("key")), CelExpr.ofConstant(12L, CelConstant.ofValue("value")), @@ -334,10 +334,10 @@ public void convertMutableCreateMap_toCelMap() { @Test public void convertCelMap_toMutableCreateMap() { CelExpr celExpr = - CelExpr.ofCreateMap( + CelExpr.ofMap( 9L, ImmutableList.of( - CelExpr.ofCreateMapEntry( + CelExpr.ofMapEntry( 10L, CelExpr.ofConstant(11L, CelConstant.ofValue("key")), CelExpr.ofConstant(12L, CelConstant.ofValue("value")), @@ -347,7 +347,7 @@ public void convertCelMap_toMutableCreateMap() { assertThat(mutableExpr) .isEqualTo( - CelMutableExpr.ofCreateMap( + CelMutableExpr.ofMap( 9L, CelMutableMap.create( ImmutableList.of( @@ -365,7 +365,7 @@ public void convertMutableComprehension_toCelComprehension() { 1L, CelMutableComprehension.create( "iterVar", - CelMutableExpr.ofCreateList( + CelMutableExpr.ofList( 2L, CelMutableList.create( CelMutableExpr.ofConstant(3L, CelConstant.ofValue(true)))), @@ -384,7 +384,7 @@ public void convertMutableComprehension_toCelComprehension() { "iterVar", CelExpr.newBuilder() .setId(2L) - .setCreateList( + .setList( CelList.newBuilder() .addElements(CelExpr.ofConstant(3L, CelConstant.ofValue(true))) .build()) @@ -404,7 +404,7 @@ public void convertCelComprehension_toMutableComprehension() { "iterVar", CelExpr.newBuilder() .setId(2L) - .setCreateList( + .setList( CelList.newBuilder() .addElements(CelExpr.ofConstant(3L, CelConstant.ofValue(true))) .build()) @@ -423,7 +423,7 @@ public void convertCelComprehension_toMutableComprehension() { 1L, CelMutableComprehension.create( "iterVar", - CelMutableExpr.ofCreateList( + CelMutableExpr.ofList( 2L, CelMutableList.create( CelMutableExpr.ofConstant(3L, CelConstant.ofValue(true)))), diff --git a/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java b/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java index 620fe2e8b..906c3dab8 100644 --- a/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java +++ b/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java @@ -314,26 +314,26 @@ public void mutableCall_setFunction() { } @Test - public void ofCreateList() { + public void ofList() { CelMutableExpr mutableExpr = - CelMutableExpr.ofCreateList( + CelMutableExpr.ofList( CelMutableList.create( CelMutableExpr.ofConstant(CelConstant.ofValue("element1")), CelMutableExpr.ofConstant(CelConstant.ofValue("element2")))); assertThat(mutableExpr.id()).isEqualTo(0L); - assertThat(mutableExpr.createList().elements()) + assertThat(mutableExpr.list().elements()) .containsExactly( CelMutableExpr.ofConstant(CelConstant.ofValue("element1")), CelMutableExpr.ofConstant(CelConstant.ofValue("element2"))) .inOrder(); - assertThat(mutableExpr.createList().optionalIndices()).isEmpty(); + assertThat(mutableExpr.list().optionalIndices()).isEmpty(); } @Test - public void ofCreateList_withId() { + public void ofList_withId() { CelMutableExpr mutableExpr = - CelMutableExpr.ofCreateList( + CelMutableExpr.ofList( 1L, CelMutableList.create( ImmutableList.of( @@ -342,12 +342,12 @@ public void ofCreateList_withId() { ImmutableList.of(0, 1))); assertThat(mutableExpr.id()).isEqualTo(1L); - assertThat(mutableExpr.createList().elements()) + assertThat(mutableExpr.list().elements()) .containsExactly( CelMutableExpr.ofConstant(CelConstant.ofValue("element1")), CelMutableExpr.ofConstant(CelConstant.ofValue("element2"))) .inOrder(); - assertThat(mutableExpr.createList().optionalIndices()).containsExactly(0, 1).inOrder(); + assertThat(mutableExpr.list().optionalIndices()).containsExactly(0, 1).inOrder(); } @Test @@ -366,7 +366,7 @@ public void mutableCreateList_setElementAtIndex() { @SuppressWarnings("ReferenceEquality") // test only on iterating through elements public void mutableCreateList_deepCopy() { CelMutableExpr mutableExpr = - CelMutableExpr.ofCreateList( + CelMutableExpr.ofList( CelMutableList.create( CelMutableExpr.ofConstant(CelConstant.ofValue("element1")), CelMutableExpr.ofConstant(CelConstant.ofValue("element2")))); @@ -374,31 +374,31 @@ public void mutableCreateList_deepCopy() { CelMutableExpr deepCopiedExpr = CelMutableExpr.newInstance(mutableExpr); assertThat(mutableExpr).isEqualTo(deepCopiedExpr); - assertThat(mutableExpr.createList()).isEqualTo(deepCopiedExpr.createList()); + assertThat(mutableExpr.list()).isEqualTo(deepCopiedExpr.list()); assertThat(mutableExpr).isNotSameInstanceAs(deepCopiedExpr); - assertThat(mutableExpr.createList()).isNotSameInstanceAs(deepCopiedExpr.createList()); - assertThat(mutableExpr.createList().elements()) + assertThat(mutableExpr.list()).isNotSameInstanceAs(deepCopiedExpr.list()); + assertThat(mutableExpr.list().elements()) .comparingElementsUsing( Correspondence.from( (e1, e2) -> e1 != e2 && e1.equals(e2), "are only value equal and not referentially equal")) - .containsExactlyElementsIn(deepCopiedExpr.createList().elements()); + .containsExactlyElementsIn(deepCopiedExpr.list().elements()); } @Test - public void ofCreateStruct() { + public void ofStruct() { CelMutableExpr mutableExpr = - CelMutableExpr.ofCreateStruct(CelMutableStruct.create("message", ImmutableList.of())); + CelMutableExpr.ofStruct(CelMutableStruct.create("message", ImmutableList.of())); assertThat(mutableExpr.id()).isEqualTo(0L); - assertThat(mutableExpr.createStruct().messageName()).isEqualTo("message"); - assertThat(mutableExpr.createStruct().entries()).isEmpty(); + assertThat(mutableExpr.struct().messageName()).isEqualTo("message"); + assertThat(mutableExpr.struct().entries()).isEmpty(); } @Test - public void ofCreateStruct_withId() { + public void ofStruct_withId() { CelMutableExpr mutableExpr = - CelMutableExpr.ofCreateStruct( + CelMutableExpr.ofStruct( 8L, CelMutableStruct.create( "message", @@ -410,8 +410,8 @@ public void ofCreateStruct_withId() { /* optionalEntry= */ true)))); assertThat(mutableExpr.id()).isEqualTo(8L); - assertThat(mutableExpr.createStruct().messageName()).isEqualTo("message"); - assertThat(mutableExpr.createStruct().entries()) + assertThat(mutableExpr.struct().messageName()).isEqualTo("message"); + assertThat(mutableExpr.struct().entries()) .containsExactly( CelMutableStruct.Entry.create( 9L, @@ -461,7 +461,7 @@ public void mutableCreateStructEntry_setters() { @SuppressWarnings("ReferenceEquality") // test only on iterating through elements public void mutableCreateStruct_deepCopy() { CelMutableExpr mutableExpr = - CelMutableExpr.ofCreateStruct( + CelMutableExpr.ofStruct( 8L, CelMutableStruct.create( "message", @@ -475,12 +475,12 @@ public void mutableCreateStruct_deepCopy() { CelMutableExpr deepCopiedExpr = CelMutableExpr.newInstance(mutableExpr); assertThat(mutableExpr).isEqualTo(deepCopiedExpr); - assertThat(mutableExpr.createStruct()).isEqualTo(deepCopiedExpr.createStruct()); + assertThat(mutableExpr.struct()).isEqualTo(deepCopiedExpr.struct()); assertThat(mutableExpr).isNotSameInstanceAs(deepCopiedExpr); - assertThat(mutableExpr.createStruct()).isNotSameInstanceAs(deepCopiedExpr.createStruct()); - assertThat(mutableExpr.createStruct().entries()) - .isNotSameInstanceAs(deepCopiedExpr.createStruct().entries()); - assertThat(mutableExpr.createStruct().entries()) + assertThat(mutableExpr.struct()).isNotSameInstanceAs(deepCopiedExpr.struct()); + assertThat(mutableExpr.struct().entries()) + .isNotSameInstanceAs(deepCopiedExpr.struct().entries()); + assertThat(mutableExpr.struct().entries()) .comparingElementsUsing( Correspondence.from( (e1, e2) -> @@ -489,22 +489,21 @@ public void mutableCreateStruct_deepCopy() { && e1.value() != e2.value() && e1.value().equals(e2.value()), "are only value equal and not referentially equal")) - .containsExactlyElementsIn(deepCopiedExpr.createStruct().entries()); + .containsExactlyElementsIn(deepCopiedExpr.struct().entries()); } @Test - public void ofCreateMap() { - CelMutableExpr mutableExpr = - CelMutableExpr.ofCreateMap(CelMutableMap.create(ImmutableList.of())); + public void ofMap() { + CelMutableExpr mutableExpr = CelMutableExpr.ofMap(CelMutableMap.create(ImmutableList.of())); assertThat(mutableExpr.id()).isEqualTo(0L); - assertThat(mutableExpr.createMap().entries()).isEmpty(); + assertThat(mutableExpr.map().entries()).isEmpty(); } @Test - public void ofCreateMap_withId() { + public void ofMap_withId() { CelMutableExpr mutableExpr = - CelMutableExpr.ofCreateMap( + CelMutableExpr.ofMap( 9L, CelMutableMap.create( ImmutableList.of( @@ -515,7 +514,7 @@ public void ofCreateMap_withId() { /* optionalEntry= */ true)))); assertThat(mutableExpr.id()).isEqualTo(9L); - assertThat(mutableExpr.createMap().entries()) + assertThat(mutableExpr.map().entries()) .containsExactly( CelMutableMap.Entry.create( 10L, @@ -571,7 +570,7 @@ public void mutableCreateMapEntry_setters() { @SuppressWarnings("ReferenceEquality") // test only on iterating through elements public void mutableCreateMap_deepCopy() { CelMutableExpr mutableExpr = - CelMutableExpr.ofCreateMap( + CelMutableExpr.ofMap( 9L, CelMutableMap.create( ImmutableList.of( @@ -584,10 +583,10 @@ public void mutableCreateMap_deepCopy() { CelMutableExpr deepCopiedExpr = CelMutableExpr.newInstance(mutableExpr); assertThat(mutableExpr).isEqualTo(deepCopiedExpr); - assertThat(mutableExpr.createMap()).isEqualTo(deepCopiedExpr.createMap()); + assertThat(mutableExpr.map()).isEqualTo(deepCopiedExpr.map()); assertThat(mutableExpr).isNotSameInstanceAs(deepCopiedExpr); - assertThat(mutableExpr.createMap()).isNotSameInstanceAs(deepCopiedExpr.createMap()); - assertThat(mutableExpr.createMap().entries()) + assertThat(mutableExpr.map()).isNotSameInstanceAs(deepCopiedExpr.map()); + assertThat(mutableExpr.map().entries()) .comparingElementsUsing( Correspondence.from( (e1, e2) -> @@ -598,7 +597,7 @@ public void mutableCreateMap_deepCopy() { && e1.value() != e2.value() && e1.value().equals(e2.value()), "are only value equal and not referentially equal")) - .containsExactlyElementsIn(deepCopiedExpr.createMap().entries()); + .containsExactlyElementsIn(deepCopiedExpr.map().entries()); } @Test @@ -608,7 +607,7 @@ public void ofComprehension_withId() { 10L, CelMutableComprehension.create( "iterVar", - CelMutableExpr.ofCreateList( + CelMutableExpr.ofList( CelMutableList.create(CelMutableExpr.ofConstant(CelConstant.ofValue(true)))), "accuVar", CelMutableExpr.ofConstant(CelConstant.ofValue(true)), @@ -621,7 +620,7 @@ public void ofComprehension_withId() { .isEqualTo( CelMutableComprehension.create( "iterVar", - CelMutableExpr.ofCreateList( + CelMutableExpr.ofList( CelMutableList.create(CelMutableExpr.ofConstant(CelConstant.ofValue(true)))), "accuVar", CelMutableExpr.ofConstant(CelConstant.ofValue(true)), @@ -645,7 +644,7 @@ public void mutableComprehension_setters() { mutableComprehension.setIterVar("iterVar2"); mutableComprehension.setAccuVar("accuVar2"); mutableComprehension.setIterRange( - CelMutableExpr.ofCreateList( + CelMutableExpr.ofList( CelMutableList.create(CelMutableExpr.ofConstant(CelConstant.ofValue(true))))); mutableComprehension.setAccuInit(CelMutableExpr.ofConstant(CelConstant.ofValue(true))); mutableComprehension.setLoopCondition(CelMutableExpr.ofConstant(CelConstant.ofValue(true))); @@ -656,7 +655,7 @@ public void mutableComprehension_setters() { .isEqualTo( CelMutableComprehension.create( "iterVar2", - CelMutableExpr.ofCreateList( + CelMutableExpr.ofList( CelMutableList.create(CelMutableExpr.ofConstant(CelConstant.ofValue(true)))), "accuVar2", CelMutableExpr.ofConstant(CelConstant.ofValue(true)), @@ -672,7 +671,7 @@ public void mutableComprehension_deepCopy() { 10L, CelMutableComprehension.create( "iterVar", - CelMutableExpr.ofCreateList( + CelMutableExpr.ofList( CelMutableList.create(CelMutableExpr.ofConstant(CelConstant.ofValue(true)))), "accuVar", CelMutableExpr.ofConstant(CelConstant.ofValue(true)), @@ -740,22 +739,22 @@ public void equalityTest() { CelMutableExpr.ofConstant(CelConstant.ofValue("target")), "function", CelMutableExpr.ofConstant(CelConstant.ofValue("arg"))))) - .addEqualityGroup(CelMutableExpr.ofCreateList(CelMutableList.create())) + .addEqualityGroup(CelMutableExpr.ofList(CelMutableList.create())) .addEqualityGroup( - CelMutableExpr.ofCreateList( + CelMutableExpr.ofList( 6L, CelMutableList.create( CelMutableExpr.ofConstant(CelConstant.ofValue("element1")), CelMutableExpr.ofConstant(CelConstant.ofValue("element2")))), - CelMutableExpr.ofCreateList( + CelMutableExpr.ofList( 6L, CelMutableList.create( CelMutableExpr.ofConstant(CelConstant.ofValue("element1")), CelMutableExpr.ofConstant(CelConstant.ofValue("element2"))))) .addEqualityGroup( - CelMutableExpr.ofCreateStruct(CelMutableStruct.create("message", ImmutableList.of()))) + CelMutableExpr.ofStruct(CelMutableStruct.create("message", ImmutableList.of()))) .addEqualityGroup( - CelMutableExpr.ofCreateStruct( + CelMutableExpr.ofStruct( 7L, CelMutableStruct.create( "message", @@ -765,7 +764,7 @@ public void equalityTest() { "field", CelMutableExpr.ofConstant(CelConstant.ofValue("value")), /* optionalEntry= */ true)))), - CelMutableExpr.ofCreateStruct( + CelMutableExpr.ofStruct( 7L, CelMutableStruct.create( "message", @@ -775,7 +774,7 @@ public void equalityTest() { "field", CelMutableExpr.ofConstant(CelConstant.ofValue("value")), /* optionalEntry= */ true))))) - .addEqualityGroup(CelMutableExpr.ofCreateMap(CelMutableMap.create(ImmutableList.of()))) + .addEqualityGroup(CelMutableExpr.ofMap(CelMutableMap.create(ImmutableList.of()))) .addEqualityGroup( CelMutableMap.create( ImmutableList.of( @@ -807,7 +806,7 @@ public void equalityTest() { 11L, CelMutableComprehension.create( "iterVar", - CelMutableExpr.ofCreateList( + CelMutableExpr.ofList( CelMutableList.create( CelMutableExpr.ofConstant(CelConstant.ofValue(true)))), "accuVar", @@ -819,7 +818,7 @@ public void equalityTest() { 11L, CelMutableComprehension.create( "iterVar", - CelMutableExpr.ofCreateList( + CelMutableExpr.ofList( CelMutableList.create( CelMutableExpr.ofConstant(CelConstant.ofValue(true)))), "accuVar", @@ -837,10 +836,9 @@ private enum MutableExprKindTestCase { IDENT(CelMutableExpr.ofIdent("test")), SELECT(CelMutableExpr.ofSelect(CelMutableSelect.create(CelMutableExpr.ofNotSet(), "field"))), CALL(CelMutableExpr.ofCall(CelMutableCall.create("call"))), - CREATE_LIST(CelMutableExpr.ofCreateList(CelMutableList.create())), - CREATE_STRUCT( - CelMutableExpr.ofCreateStruct(CelMutableStruct.create("message", ImmutableList.of()))), - CREATE_MAP(CelMutableExpr.ofCreateMap(CelMutableMap.create(ImmutableList.of()))), + CREATE_LIST(CelMutableExpr.ofList(CelMutableList.create())), + CREATE_STRUCT(CelMutableExpr.ofStruct(CelMutableStruct.create("message", ImmutableList.of()))), + CREATE_MAP(CelMutableExpr.ofMap(CelMutableMap.create(ImmutableList.of()))), COMPREHENSION( CelMutableExpr.ofComprehension( 10L, @@ -880,13 +878,13 @@ public void getExprValue_invalidKind_throws(@TestParameter MutableExprKindTestCa assertThrows(IllegalArgumentException.class, testCase.mutableExpr::call); } if (!testCaseKind.equals(Kind.LIST)) { - assertThrows(IllegalArgumentException.class, testCase.mutableExpr::createList); + assertThrows(IllegalArgumentException.class, testCase.mutableExpr::list); } if (!testCaseKind.equals(Kind.STRUCT)) { - assertThrows(IllegalArgumentException.class, testCase.mutableExpr::createStruct); + assertThrows(IllegalArgumentException.class, testCase.mutableExpr::struct); } if (!testCaseKind.equals(Kind.MAP)) { - assertThrows(IllegalArgumentException.class, testCase.mutableExpr::createMap); + assertThrows(IllegalArgumentException.class, testCase.mutableExpr::map); } if (!testCaseKind.equals(Kind.COMPREHENSION)) { assertThrows(IllegalArgumentException.class, testCase.mutableExpr::comprehension); @@ -912,14 +910,14 @@ private enum HashCodeTestCase { CelMutableExpr.ofConstant(CelConstant.ofValue("arg")))), -1735261193), CREATE_LIST( - CelMutableExpr.ofCreateList( + CelMutableExpr.ofList( 6L, CelMutableList.create( CelMutableExpr.ofConstant(CelConstant.ofValue("element1")), CelMutableExpr.ofConstant(CelConstant.ofValue("element2")))), 165341403), CREATE_STRUCT( - CelMutableExpr.ofCreateStruct( + CelMutableExpr.ofStruct( 7L, CelMutableStruct.create( "message", @@ -931,7 +929,7 @@ private enum HashCodeTestCase { /* optionalEntry= */ true)))), 2064611987), CREATE_MAP( - CelMutableExpr.ofCreateMap( + CelMutableExpr.ofMap( 8L, CelMutableMap.create( ImmutableList.of( @@ -946,7 +944,7 @@ private enum HashCodeTestCase { 10L, CelMutableComprehension.create( "iterVar", - CelMutableExpr.ofCreateList( + CelMutableExpr.ofList( CelMutableList.create(CelMutableExpr.ofConstant(CelConstant.ofValue(true)))), "accuVar", CelMutableExpr.ofConstant(CelConstant.ofValue(true)), diff --git a/common/src/test/java/dev/cel/common/navigation/CelNavigableExprVisitorTest.java b/common/src/test/java/dev/cel/common/navigation/CelNavigableExprVisitorTest.java index e2429c7db..c22471c05 100644 --- a/common/src/test/java/dev/cel/common/navigation/CelNavigableExprVisitorTest.java +++ b/common/src/test/java/dev/cel/common/navigation/CelNavigableExprVisitorTest.java @@ -592,11 +592,10 @@ public void messageConstruction_allNodesReturned() throws Exception { assertThat(allNodes) .containsExactly( constExpr, - CelExpr.ofCreateStruct( + CelExpr.ofStruct( 1, "TestAllTypes", - ImmutableList.of( - CelExpr.ofCreateStructEntry(2, "single_int64", constExpr, false)))); + ImmutableList.of(CelExpr.ofStructEntry(2, "single_int64", constExpr, false)))); } @Test @@ -619,11 +618,11 @@ public void messageConstruction_filterCreateStruct_allNodesReturned() throws Exc assertThat(allNodes).hasSize(1); assertThat(allNodes.get(0).expr()) .isEqualTo( - CelExpr.ofCreateStruct( + CelExpr.ofStruct( 1, "TestAllTypes", ImmutableList.of( - CelExpr.ofCreateStructEntry( + CelExpr.ofStructEntry( 2, "single_int64", CelExpr.ofConstant(3, CelConstant.ofValue(1)), false)))); } @@ -704,8 +703,8 @@ public void mapConstruction_allNodesReturned() throws Exception { .containsExactly( mapKeyExpr, mapValueExpr, - CelExpr.ofCreateMap( - 1, ImmutableList.of(CelExpr.ofCreateMapEntry(2, mapKeyExpr, mapValueExpr, false)))); + CelExpr.ofMap( + 1, ImmutableList.of(CelExpr.ofMapEntry(2, mapKeyExpr, mapValueExpr, false)))); } @Test @@ -726,8 +725,8 @@ public void mapConstruction_filterCreateMap_allNodesReturned() throws Exception CelExpr mapValueExpr = CelExpr.ofConstant(4, CelConstant.ofValue(2)); assertThat(allNodes.get(0).expr()) .isEqualTo( - CelExpr.ofCreateMap( - 1, ImmutableList.of(CelExpr.ofCreateMapEntry(2, mapKeyExpr, mapValueExpr, false)))); + CelExpr.ofMap( + 1, ImmutableList.of(CelExpr.ofMapEntry(2, mapKeyExpr, mapValueExpr, false)))); } @Test @@ -804,7 +803,7 @@ public void emptyMapConstruction_allNodesReturned() throws Exception { navigableAst.getRoot().allNodes().collect(toImmutableList()); assertThat(allNodes).hasSize(1); - assertThat(allNodes.get(0).expr()).isEqualTo(CelExpr.ofCreateMap(1, ImmutableList.of())); + assertThat(allNodes.get(0).expr()).isEqualTo(CelExpr.ofMap(1, ImmutableList.of())); } @Test @@ -824,8 +823,7 @@ public void comprehension_preOrder_allNodesReturned() throws Exception { .collect(toImmutableList()); CelExpr iterRangeConstExpr = CelExpr.ofConstant(2, CelConstant.ofValue(true)); - CelExpr iterRange = - CelExpr.ofCreateList(1, ImmutableList.of(iterRangeConstExpr), ImmutableList.of()); + CelExpr iterRange = CelExpr.ofList(1, ImmutableList.of(iterRangeConstExpr), ImmutableList.of()); CelExpr accuInit = CelExpr.ofConstant(6, CelConstant.ofValue(false)); CelExpr loopConditionIdentExpr = CelExpr.ofIdent(7, "__result__"); CelExpr loopConditionCallExpr = @@ -886,8 +884,7 @@ public void comprehension_postOrder_allNodesReturned() throws Exception { .collect(toImmutableList()); CelExpr iterRangeConstExpr = CelExpr.ofConstant(2, CelConstant.ofValue(true)); - CelExpr iterRange = - CelExpr.ofCreateList(1, ImmutableList.of(iterRangeConstExpr), ImmutableList.of()); + CelExpr iterRange = CelExpr.ofList(1, ImmutableList.of(iterRangeConstExpr), ImmutableList.of()); CelExpr accuInit = CelExpr.ofConstant(6, CelConstant.ofValue(false)); CelExpr loopConditionIdentExpr = CelExpr.ofIdent(7, "__result__"); CelExpr loopConditionCallExpr = @@ -1019,8 +1016,7 @@ public void comprehension_allNodes_parentsPopulated() throws Exception { ImmutableList allNodes = navigableAst.getRoot().allNodes(TraversalOrder.PRE_ORDER).collect(toImmutableList()); CelExpr iterRangeConstExpr = CelExpr.ofConstant(2, CelConstant.ofValue(true)); - CelExpr iterRange = - CelExpr.ofCreateList(1, ImmutableList.of(iterRangeConstExpr), ImmutableList.of()); + CelExpr iterRange = CelExpr.ofList(1, ImmutableList.of(iterRangeConstExpr), ImmutableList.of()); CelExpr accuInit = CelExpr.ofConstant(6, CelConstant.ofValue(false)); CelExpr loopConditionIdentExpr = CelExpr.ofIdent(7, "__result__"); CelExpr loopConditionCallExpr = @@ -1083,8 +1079,7 @@ public void comprehension_filterComprehension_allNodesReturned() throws Exceptio .collect(toImmutableList()); CelExpr iterRangeConstExpr = CelExpr.ofConstant(2, CelConstant.ofValue(true)); - CelExpr iterRange = - CelExpr.ofCreateList(1, ImmutableList.of(iterRangeConstExpr), ImmutableList.of()); + CelExpr iterRange = CelExpr.ofList(1, ImmutableList.of(iterRangeConstExpr), ImmutableList.of()); CelExpr accuInit = CelExpr.ofConstant(6, CelConstant.ofValue(false)); CelExpr loopConditionIdentExpr = CelExpr.ofIdent(7, "__result__"); CelExpr loopConditionCallExpr = diff --git a/common/src/test/java/dev/cel/common/navigation/CelNavigableMutableExprTest.java b/common/src/test/java/dev/cel/common/navigation/CelNavigableMutableExprTest.java index a4e8d455a..6900d41aa 100644 --- a/common/src/test/java/dev/cel/common/navigation/CelNavigableMutableExprTest.java +++ b/common/src/test/java/dev/cel/common/navigation/CelNavigableMutableExprTest.java @@ -80,10 +80,10 @@ public void builderFromInstance_sameAsStaticBuilder() { public void allNodes_filteredConstants_returnsAllConstants() { CelNavigableMutableExpr mutableExpr = CelNavigableMutableExpr.fromExpr( - CelMutableExpr.ofCreateList( + CelMutableExpr.ofList( CelMutableList.create( CelMutableExpr.ofConstant(CelConstant.ofValue("element1")), - CelMutableExpr.ofCreateList( + CelMutableExpr.ofList( CelMutableList.create( CelMutableExpr.ofConstant(CelConstant.ofValue("element2"))))))); @@ -105,10 +105,10 @@ public void allNodes_filteredConstants_returnsAllConstants() { public void descendants_filteredConstants_returnsAllConstants() { CelNavigableMutableExpr mutableExpr = CelNavigableMutableExpr.fromExpr( - CelMutableExpr.ofCreateList( + CelMutableExpr.ofList( CelMutableList.create( CelMutableExpr.ofConstant(CelConstant.ofValue("element1")), - CelMutableExpr.ofCreateList( + CelMutableExpr.ofList( CelMutableList.create( CelMutableExpr.ofConstant(CelConstant.ofValue("element2"))))))); @@ -130,10 +130,10 @@ public void descendants_filteredConstants_returnsAllConstants() { public void children_filteredConstants_returnsSingleConstant() { CelNavigableMutableExpr mutableExpr = CelNavigableMutableExpr.fromExpr( - CelMutableExpr.ofCreateList( + CelMutableExpr.ofList( CelMutableList.create( CelMutableExpr.ofConstant(CelConstant.ofValue("element1")), - CelMutableExpr.ofCreateList( + CelMutableExpr.ofList( CelMutableList.create( CelMutableExpr.ofConstant(CelConstant.ofValue("element2"))))))); diff --git a/extensions/src/main/java/dev/cel/extensions/CelMathExtensions.java b/extensions/src/main/java/dev/cel/extensions/CelMathExtensions.java index 59e51e366..c6423a05a 100644 --- a/extensions/src/main/java/dev/cel/extensions/CelMathExtensions.java +++ b/extensions/src/main/java/dev/cel/extensions/CelMathExtensions.java @@ -527,12 +527,12 @@ private static Optional checkInvalidArgument( private static Optional checkInvalidArgumentSingleArg( CelMacroExprFactory exprFactory, String functionName, CelExpr argument) { if (argument.exprKind().getKind() == Kind.LIST) { - if (argument.createList().elements().isEmpty()) { + if (argument.list().elements().isEmpty()) { return newError( exprFactory, String.format("%s invalid single argument value", functionName), argument); } - return checkInvalidArgument(exprFactory, functionName, argument.createList().elements()); + return checkInvalidArgument(exprFactory, functionName, argument.list().elements()); } if (isArgumentValidType(argument)) { return Optional.empty(); diff --git a/optimizer/src/main/java/dev/cel/optimizer/AstMutator.java b/optimizer/src/main/java/dev/cel/optimizer/AstMutator.java index 2159b14a8..e439c87cc 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/AstMutator.java +++ b/optimizer/src/main/java/dev/cel/optimizer/AstMutator.java @@ -90,7 +90,7 @@ public CelMutableAst wrapAstWithNewCelBlock( ++maxId, CelMutableCall.create( celBlockFunction, - CelMutableExpr.ofCreateList(++maxId, CelMutableList.create(subexpressions)), + CelMutableExpr.ofList(++maxId, CelMutableList.create(subexpressions)), ast.expr())); return CelMutableAst.of(blockExpr, ast.source()); @@ -569,7 +569,7 @@ private CelMutableExpr newBindMacroExpr( comprehensionId, CelMutableComprehension.create( "#unused", - CelMutableExpr.ofCreateList(iterRangeId, CelMutableList.create()), + CelMutableExpr.ofList(iterRangeId, CelMutableList.create()), varName, varInit, CelMutableExpr.ofConstant(loopConditionId, CelConstant.ofValue(false)), @@ -758,7 +758,7 @@ private CelMutableSource normalizeMacroSource( private static void unwrapListArgumentsInMacroCallExpr( CelMutableComprehension comprehension, CelMutableExpr newMacroCallExpr) { CelMutableExpr accuInit = comprehension.accuInit(); - if (!accuInit.getKind().equals(Kind.LIST) || !accuInit.createList().elements().isEmpty()) { + if (!accuInit.getKind().equals(Kind.LIST) || !accuInit.list().elements().isEmpty()) { // Does not contain an extraneous list. return; } @@ -779,7 +779,7 @@ private static void unwrapListArgumentsInMacroCallExpr( : CelMutableCall.create(existingMacroCall.function()); newMacroCall.addArgs( existingMacroCall.args().get(0)); // iter_var is first argument of the call by convention - newMacroCall.addArgs(loopStepArgs.get(1).createList().elements()); + newMacroCall.addArgs(loopStepArgs.get(1).list().elements()); newMacroCallExpr.setCall(newMacroCall); } diff --git a/optimizer/src/main/java/dev/cel/optimizer/MutableExprVisitor.java b/optimizer/src/main/java/dev/cel/optimizer/MutableExprVisitor.java index d9ecb70c9..6d37246fc 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/MutableExprVisitor.java +++ b/optimizer/src/main/java/dev/cel/optimizer/MutableExprVisitor.java @@ -71,11 +71,11 @@ CelMutableExpr visit(CelMutableExpr root) { case CALL: return visit(root, root.call()); case LIST: - return visit(root, root.createList()); + return visit(root, root.list()); case STRUCT: - return visit(root, root.createStruct()); + return visit(root, root.struct()); case MAP: - return visit(root, root.createMap()); + return visit(root, root.map()); case COMPREHENSION: return visit(root, root.comprehension()); case CONSTANT: // Fall-through is intended diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java b/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java index bef87765b..485ded5e4 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java @@ -258,7 +258,7 @@ private Optional maybeAdaptEvaluatedResult(Object result) { listElements.add(adaptedExpr); } - return Optional.of(CelMutableExpr.ofCreateList(CelMutableList.create(listElements))); + return Optional.of(CelMutableExpr.ofList(CelMutableList.create(listElements))); } else if (result instanceof Map) { Map map = (Map) result; List mapEntries = new ArrayList<>(); @@ -275,7 +275,7 @@ private Optional maybeAdaptEvaluatedResult(Object result) { mapEntries.add(CelMutableMap.Entry.create(adaptedKey, adaptedValue)); } - return Optional.of(CelMutableExpr.ofCreateMap(CelMutableMap.create(mapEntries))); + return Optional.of(CelMutableExpr.ofMap(CelMutableMap.create(mapEntries))); } // Evaluated result cannot be folded (e.g: unknowns) @@ -339,7 +339,7 @@ private Optional maybePruneBranches( return Optional.empty(); } - CelMutableList haystack = callArg.createList(); + CelMutableList haystack = callArg.list(); if (haystack.elements().isEmpty()) { return Optional.of( astMutator.replaceSubtree( @@ -438,7 +438,7 @@ private CelMutableAst pruneOptionalElements(CelMutableAst ast) { } private CelMutableAst pruneOptionalListElements(CelMutableAst mutableAst, CelMutableExpr expr) { - CelMutableList createList = expr.createList(); + CelMutableList createList = expr.list(); if (createList.optionalIndices().isEmpty()) { return mutableAst; } @@ -477,13 +477,13 @@ private CelMutableAst pruneOptionalListElements(CelMutableAst mutableAst, CelMut return astMutator.replaceSubtree( mutableAst, - CelMutableExpr.ofCreateList( + CelMutableExpr.ofList( CelMutableList.create(updatedElemBuilder.build(), updatedIndicesBuilder.build())), expr.id()); } private CelMutableAst pruneOptionalMapElements(CelMutableAst ast, CelMutableExpr expr) { - CelMutableMap createMap = expr.createMap(); + CelMutableMap createMap = expr.map(); ImmutableList.Builder updatedEntryBuilder = new ImmutableList.Builder<>(); boolean modified = false; for (CelMutableMap.Entry entry : createMap.entries()) { @@ -519,16 +519,14 @@ private CelMutableAst pruneOptionalMapElements(CelMutableAst ast, CelMutableExpr if (modified) { return astMutator.replaceSubtree( - ast, - CelMutableExpr.ofCreateMap(CelMutableMap.create(updatedEntryBuilder.build())), - expr.id()); + ast, CelMutableExpr.ofMap(CelMutableMap.create(updatedEntryBuilder.build())), expr.id()); } return ast; } private CelMutableAst pruneOptionalStructElements(CelMutableAst ast, CelMutableExpr expr) { - CelMutableStruct createStruct = expr.createStruct(); + CelMutableStruct createStruct = expr.struct(); ImmutableList.Builder updatedEntryBuilder = new ImmutableList.Builder<>(); boolean modified = false; @@ -563,7 +561,7 @@ private CelMutableAst pruneOptionalStructElements(CelMutableAst ast, CelMutableE if (modified) { return astMutator.replaceSubtree( ast, - CelMutableExpr.ofCreateStruct( + CelMutableExpr.ofStruct( CelMutableStruct.create(createStruct.messageName(), updatedEntryBuilder.build())), expr.id()); } diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java index e60fd47b2..967c68d3c 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java @@ -259,7 +259,7 @@ static void verifyOptimizedAstCorrectness(CelAbstractSyntaxTree ast) { // Assert correctness on block indices used in subexpressions CelCall celBlockCall = celBlockExpr.call(); - ImmutableList subexprs = celBlockCall.args().get(0).createList().elements(); + ImmutableList subexprs = celBlockCall.args().get(0).list().elements(); for (int i = 0; i < subexprs.size(); i++) { verifyBlockIndex(subexprs.get(i), i); } @@ -558,7 +558,7 @@ private boolean canEliminate( && navigableExpr.expr().ident().name().startsWith(BIND_IDENTIFIER_PREFIX)) // Exclude empty lists (cel.bind sets this for iterRange). && !(navigableExpr.getKind().equals(Kind.LIST) - && navigableExpr.expr().createList().elements().isEmpty()) + && navigableExpr.expr().list().elements().isEmpty()) && containsEliminableFunctionOnly(navigableExpr) && !ineligibleExprs.contains(navigableExpr.expr()); } diff --git a/optimizer/src/test/java/dev/cel/optimizer/AstMutatorTest.java b/optimizer/src/test/java/dev/cel/optimizer/AstMutatorTest.java index 24084156e..5e1d98be9 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/AstMutatorTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/AstMutatorTest.java @@ -490,7 +490,7 @@ public void replaceSubtree_replaceExtraneousListCreatedByMacro_unparseSuccess() AST_MUTATOR .replaceSubtree( mutableAst, - CelMutableExpr.ofCreateList( + CelMutableExpr.ofList( CelMutableList.create(CelMutableExpr.ofConstant(CelConstant.ofValue(2L)))), 9L) .toParsedAst(); diff --git a/parser/src/main/java/dev/cel/parser/CelMacroExprFactory.java b/parser/src/main/java/dev/cel/parser/CelMacroExprFactory.java index 70adbf510..d7c917c29 100644 --- a/parser/src/main/java/dev/cel/parser/CelMacroExprFactory.java +++ b/parser/src/main/java/dev/cel/parser/CelMacroExprFactory.java @@ -88,18 +88,18 @@ public final CelExpr copy(CelExpr expr) { case LIST: { CelExpr.CelList.Builder listBuilder = - CelExpr.CelList.newBuilder().addOptionalIndices(expr.createList().optionalIndices()); - for (CelExpr element : expr.createList().elements()) { + CelExpr.CelList.newBuilder().addOptionalIndices(expr.list().optionalIndices()); + for (CelExpr element : expr.list().elements()) { listBuilder.addElements(copy(element)); } - builder.setCreateList(listBuilder.build()); + builder.setList(listBuilder.build()); } break; case STRUCT: { CelExpr.CelStruct.Builder structBuilder = - CelExpr.CelStruct.newBuilder().setMessageName(expr.createStruct().messageName()); - for (CelExpr.CelStruct.Entry entry : expr.createStruct().entries()) { + CelExpr.CelStruct.newBuilder().setMessageName(expr.struct().messageName()); + for (CelExpr.CelStruct.Entry entry : expr.struct().entries()) { structBuilder.addEntries( CelExpr.CelStruct.Entry.newBuilder() .setId(copyExprId(entry.id())) @@ -108,13 +108,13 @@ public final CelExpr copy(CelExpr expr) { .setOptionalEntry(entry.optionalEntry()) .build()); } - builder.setCreateStruct(structBuilder.build()); + builder.setStruct(structBuilder.build()); } break; case MAP: { CelExpr.CelMap.Builder mapBuilder = CelExpr.CelMap.newBuilder(); - for (CelExpr.CelMap.Entry entry : expr.createMap().entries()) { + for (CelExpr.CelMap.Entry entry : expr.map().entries()) { mapBuilder.addEntries( CelExpr.CelMap.Entry.newBuilder() .setId(copyExprId(entry.id())) @@ -123,7 +123,7 @@ public final CelExpr copy(CelExpr expr) { .setOptionalEntry(entry.optionalEntry()) .build()); } - builder.setCreateMap(mapBuilder.build()); + builder.setMap(mapBuilder.build()); } break; case COMPREHENSION: diff --git a/parser/src/main/java/dev/cel/parser/Parser.java b/parser/src/main/java/dev/cel/parser/Parser.java index c4b3dffb6..b98a748d5 100644 --- a/parser/src/main/java/dev/cel/parser/Parser.java +++ b/parser/src/main/java/dev/cel/parser/Parser.java @@ -525,7 +525,7 @@ public CelExpr visitCreateMessage(CreateMessageContext context) { CelExpr.Builder exprBuilder = exprFactory.newExprBuilder(context.op); CelExpr.CelStruct.Builder structExpr = visitStructFields(context.entries); - return exprBuilder.setCreateStruct(structExpr.setMessageName(messageName).build()).build(); + return exprBuilder.setStruct(structExpr.setMessageName(messageName).build()).build(); } @Override @@ -566,7 +566,7 @@ public CelExpr visitCreateList(CreateListContext context) { CelExpr.Builder exprBuilder = exprFactory.newExprBuilder(context.op); CelExpr.CelList createListExpr = visitListInitElements(context.listInit()); - return exprBuilder.setCreateList(createListExpr).build(); + return exprBuilder.setList(createListExpr).build(); } private CelExpr.CelList visitListInitElements(ListInitContext context) { @@ -596,7 +596,7 @@ public CelExpr visitCreateMap(CreateMapContext context) { checkNotNull(context); CelExpr.Builder exprBuilder = exprFactory.newExprBuilder(context.op); CelExpr.CelMap.Builder createMapExpr = visitMapEntries(context.entries); - return exprBuilder.setCreateMap(createMapExpr.build()).build(); + return exprBuilder.setMap(createMapExpr.build()).build(); } private CelExpr buildMacroCallArgs(CelExpr expr) { diff --git a/parser/src/test/java/dev/cel/parser/CelMacroExprFactoryTest.java b/parser/src/test/java/dev/cel/parser/CelMacroExprFactoryTest.java index c14d22c6b..4d110b79e 100644 --- a/parser/src/test/java/dev/cel/parser/CelMacroExprFactoryTest.java +++ b/parser/src/test/java/dev/cel/parser/CelMacroExprFactoryTest.java @@ -156,8 +156,8 @@ public void newList_returnsList() { CelExpr expr = exprFactory.newList(element); assertThat(expr.id()).isEqualTo(2L); assertThat(expr.exprKind().getKind()).isEqualTo(Kind.LIST); - assertThat(expr.createList().elements()).hasSize(1); - assertThat(expr.createList().elements()).containsExactly(element); + assertThat(expr.list().elements()).hasSize(1); + assertThat(expr.list().elements()).containsExactly(element); } @Test @@ -169,7 +169,7 @@ public void newMap_returnsMap() { CelExpr expr = exprFactory.newMap(entry); assertThat(expr.id()).isEqualTo(4L); assertThat(expr.exprKind().getKind()).isEqualTo(Kind.MAP); - assertThat(expr.createMap().entries()).containsExactly(entry); + assertThat(expr.map().entries()).containsExactly(entry); } @Test @@ -189,8 +189,8 @@ public void newMessage_returnsMessage() { CelExpr expr = exprFactory.newMessage("google.example.Baz", field); assertThat(expr.id()).isEqualTo(3L); assertThat(expr.exprKind().getKind()).isEqualTo(Kind.STRUCT); - assertThat(expr.createStruct().messageName()).isEqualTo("google.example.Baz"); - assertThat(expr.createStruct().entries()).containsExactly(field); + assertThat(expr.struct().messageName()).isEqualTo("google.example.Baz"); + assertThat(expr.struct().entries()).containsExactly(field); } @Test diff --git a/parser/src/test/java/dev/cel/parser/CelUnparserImplTest.java b/parser/src/test/java/dev/cel/parser/CelUnparserImplTest.java index 321db78ef..be95fcaef 100644 --- a/parser/src/test/java/dev/cel/parser/CelUnparserImplTest.java +++ b/parser/src/test/java/dev/cel/parser/CelUnparserImplTest.java @@ -196,7 +196,7 @@ public List provideValues(Context context) { .build()) .build(), // bad args CelExpr.newBuilder() - .setCreateStruct( + .setStruct( CelStruct.newBuilder() .setMessageName("Msg") .addEntries( @@ -208,7 +208,7 @@ public List provideValues(Context context) { .build()) .build(), // bad struct CelExpr.newBuilder() - .setCreateMap( + .setMap( CelMap.newBuilder() .addEntries( CelMap.Entry.newBuilder() diff --git a/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java b/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java index b535028b0..a7f2efe8d 100644 --- a/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java +++ b/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java @@ -202,13 +202,13 @@ private IntermediateResult evalInternal(ExecutionFrame frame, CelExpr expr) result = evalCall(frame, expr, expr.call()); break; case LIST: - result = evalList(frame, expr, expr.createList()); + result = evalList(frame, expr, expr.list()); break; case STRUCT: - result = evalStruct(frame, expr, expr.createStruct()); + result = evalStruct(frame, expr, expr.struct()); break; case MAP: - result = evalMap(frame, expr.createMap()); + result = evalMap(frame, expr.map()); break; case COMPREHENSION: result = evalComprehension(frame, expr, expr.comprehension()); @@ -901,7 +901,7 @@ private IntermediateResult evalComprehension( private IntermediateResult evalCelBlock( ExecutionFrame frame, CelExpr unusedExpr, CelCall blockCall) throws InterpreterException { - CelList exprList = blockCall.args().get(0).createList(); + CelList exprList = blockCall.args().get(0).list(); Map blockList = new HashMap<>(); for (int index = 0; index < exprList.elements().size(); index++) { // Register the block indices as lazily evaluated expressions stored as unique identifiers. @@ -934,7 +934,7 @@ private static boolean isLazilyEvaluable(CelComprehension comprehension) { && !comprehension.loopCondition().constant().booleanValue() && comprehension.iterVar().equals("#unused") && comprehension.iterRange().exprKind().getKind().equals(ExprKind.Kind.LIST) - && comprehension.iterRange().createList().elements().isEmpty(); + && comprehension.iterRange().list().elements().isEmpty(); } private LazyExpression(CelExpr celExpr) { diff --git a/runtime/src/test/java/dev/cel/runtime/CelRuntimeTest.java b/runtime/src/test/java/dev/cel/runtime/CelRuntimeTest.java index f66690912..074405c20 100644 --- a/runtime/src/test/java/dev/cel/runtime/CelRuntimeTest.java +++ b/runtime/src/test/java/dev/cel/runtime/CelRuntimeTest.java @@ -293,7 +293,7 @@ public void trace_createStruct() throws Exception { CelEvaluationListener listener = (expr, res) -> { assertThat(res).isEqualTo(TestAllTypes.getDefaultInstance()); - assertThat(expr.createStruct().messageName()).isEqualTo("TestAllTypes"); + assertThat(expr.struct().messageName()).isEqualTo("TestAllTypes"); }; Cel cel = CelFactory.standardCelBuilder() @@ -314,7 +314,7 @@ public void trace_createList() throws Exception { (expr, res) -> { if (expr.exprKind().getKind().equals(Kind.LIST)) { assertThat((List) res).containsExactly(1L, 2L, 3L); - assertThat(expr.createList().elements()).hasSize(3); + assertThat(expr.list().elements()).hasSize(3); } }; Cel cel = CelFactory.standardCelBuilder().build(); @@ -332,7 +332,7 @@ public void trace_createMap() throws Exception { (expr, res) -> { if (expr.exprKind().getKind().equals(Kind.MAP)) { assertThat((Map) res).containsExactly(1L, "a"); - assertThat(expr.createMap().entries()).hasSize(1); + assertThat(expr.map().entries()).hasSize(1); } }; Cel cel = CelFactory.standardCelBuilder().build(); diff --git a/validator/src/main/java/dev/cel/validator/validators/HomogeneousLiteralValidator.java b/validator/src/main/java/dev/cel/validator/validators/HomogeneousLiteralValidator.java index b47251ccf..58947f0fb 100644 --- a/validator/src/main/java/dev/cel/validator/validators/HomogeneousLiteralValidator.java +++ b/validator/src/main/java/dev/cel/validator/validators/HomogeneousLiteralValidator.java @@ -73,8 +73,8 @@ public void validate(CelNavigableAst navigableAst, Cel cel, IssuesFactory issues private void validateList(CelAbstractSyntaxTree ast, IssuesFactory issuesFactory, CelExpr expr) { CelType previousType = null; - HashSet optionalIndices = new HashSet<>(expr.createList().optionalIndices()); - ImmutableList elements = expr.createList().elements(); + HashSet optionalIndices = new HashSet<>(expr.list().optionalIndices()); + ImmutableList elements = expr.list().elements(); for (int i = 0; i < elements.size(); i++) { CelExpr element = elements.get(i); CelType currentType = ast.getType(element.id()).get(); @@ -94,7 +94,7 @@ private void validateList(CelAbstractSyntaxTree ast, IssuesFactory issuesFactory private void validateMap(CelAbstractSyntaxTree ast, IssuesFactory issuesFactory, CelExpr expr) { CelType previousKeyType = null; CelType previousValueType = null; - for (CelMap.Entry entry : expr.createMap().entries()) { + for (CelMap.Entry entry : expr.map().entries()) { CelType currentKeyType = ast.getType(entry.key().id()).get(); CelType currentValueType = ast.getType(entry.value().id()).get(); if (entry.optionalEntry()) { From 980c9b5689b431f1b0f79efc93d31e181d055c61 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Tue, 30 Apr 2024 16:05:37 -0700 Subject: [PATCH 107/486] Add capability to regenerate baseline tests into a file PiperOrigin-RevId: 629556654 --- .../dev/cel/testing/BaselineTestCase.java | 56 +++++++++++++++++-- 1 file changed, 50 insertions(+), 6 deletions(-) diff --git a/testing/src/main/java/dev/cel/testing/BaselineTestCase.java b/testing/src/main/java/dev/cel/testing/BaselineTestCase.java index b5f83c83a..aa4215030 100644 --- a/testing/src/main/java/dev/cel/testing/BaselineTestCase.java +++ b/testing/src/main/java/dev/cel/testing/BaselineTestCase.java @@ -16,13 +16,18 @@ import static java.nio.charset.StandardCharsets.UTF_8; +import com.google.common.base.Strings; +import com.google.common.io.Files; import com.google.common.io.Resources; import java.io.BufferedWriter; import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.URL; +import java.nio.charset.Charset; import junit.framework.AssertionFailedError; import org.junit.Before; import org.junit.Rule; @@ -37,6 +42,7 @@ public abstract class BaselineTestCase { public static class BaselineComparisonError extends AssertionFailedError { private final String testName; private final String actual; + private final String actualFileLocation; private final LineDiffer.Diff lineDiff; private final String baselineFileName; @@ -48,24 +54,42 @@ public static class BaselineComparisonError extends AssertionFailedError { * @param lineDiff the diff between the expected and {@code actual}. */ public BaselineComparisonError( - String testName, String baselineFileName, String actual, LineDiffer.Diff lineDiff) { + String testName, + String baselineFileName, + String actual, + String actualFileLocation, + LineDiffer.Diff lineDiff) { this.testName = testName; this.actual = actual; + this.actualFileLocation = actualFileLocation; this.lineDiff = lineDiff; this.baselineFileName = baselineFileName; } @Override public String getMessage() { - return String.format( - "Expected for '%s' differs from actual:%n%n\"******New baseline content" - + " is******%n%s%nExpected File: %s%nDiff:\n%s", - testName, actual, baselineFileName, lineDiff); + String resultMessage = + String.format( + "Expected for '%s' differs from actual:%n%n\"******New baseline content" + + " is******%n%s%nExpected File: %s%nActual File: %s%nDiff:\n%s", + testName, actual, baselineFileName, actualFileLocation, lineDiff); + + return resultMessage; } } @Rule public TestName testName = new TestName(); + private static final String DIRECTORY_TO_COPY_NEW_BASELINE; + + static { + if (!Strings.isNullOrEmpty(System.getenv("COPY_BASELINE_TO_DIR"))) { + DIRECTORY_TO_COPY_NEW_BASELINE = System.getenv("COPY_BASELINE_TO_DIR"); + } else { + DIRECTORY_TO_COPY_NEW_BASELINE = "/tmp"; + } + } + private OutputStream output; private PrintWriter writer; private boolean isVerified; @@ -126,8 +150,9 @@ protected void verify() { String expected = getExpected().trim(); LineDiffer.Diff lineDiff = LineDiffer.diffLines(expected, actual); if (!lineDiff.isEmpty()) { + String actualFileLocation = tryCreateNewBaseline(actual); throw new BaselineComparisonError( - testName.getMethodName(), baselineFileName(), actual, lineDiff); + testName.getMethodName(), baselineFileName(), actual, actualFileLocation, lineDiff); } } catch (Exception e) { throw new RuntimeException(e); @@ -138,4 +163,23 @@ protected void verify() { protected void skipBaselineVerification() { isVerified = true; } + + /** + * Creates a baseline file that will need to be used to make the current test pass. + * + *

If the test is failing for a valid reason (e.g. developer changed some output text), then + * this file provides a convenient way for the developer to overwrite the old baseline and keep + * the test passing. + * + *

The created file is stored under /tmp or location specified by the environment variable + * DIRECTORY_TO_COPY_NEW_BASELINE. Information where the file is stored is returned as a string. + */ + private String tryCreateNewBaseline(String actual) throws IOException { + File file = + new File( + File.separator + DIRECTORY_TO_COPY_NEW_BASELINE + File.separator + baselineFileName()); + Files.createParentDirs(file); + Files.asCharSink(file, Charset.defaultCharset()).write(actual); + return file.toString(); + } } From be5aa9bf127723003ca67aaee2b3f7ece87b4237 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Tue, 30 Apr 2024 16:27:04 -0700 Subject: [PATCH 108/486] Change comprehension variable mangling logic to always generate a unique index per comprehension expr PiperOrigin-RevId: 629561823 --- .../java/dev/cel/optimizer/AstMutator.java | 51 +- .../dev/cel/optimizer/AstMutatorTest.java | 48 +- .../SubexpressionOptimizerBaselineTest.java | 3 + ...old_before_subexpression_unparsed.baseline | 40 +- .../large_expressions_bind_cascaded.baseline | 2 +- ..._expressions_block_common_subexpr.baseline | 2 +- ...pressions_block_recursion_depth_1.baseline | 2 +- ...pressions_block_recursion_depth_2.baseline | 2 +- ...pressions_block_recursion_depth_3.baseline | 2 +- ...ion_ast_block_common_subexpr_only.baseline | 878 ++++++++++---- ...ssion_ast_block_recursion_depth_1.baseline | 783 +++++++++---- ...ssion_ast_block_recursion_depth_2.baseline | 779 +++++++++---- ...ssion_ast_block_recursion_depth_3.baseline | 856 +++++++++++--- ...ssion_ast_block_recursion_depth_4.baseline | 835 +++++++++++--- ...ssion_ast_block_recursion_depth_5.baseline | 819 +++++++++++--- ...ssion_ast_block_recursion_depth_6.baseline | 860 ++++++++++---- ...ssion_ast_block_recursion_depth_7.baseline | 870 ++++++++++---- ...ssion_ast_block_recursion_depth_8.baseline | 881 ++++++++++---- ...ssion_ast_block_recursion_depth_9.baseline | 878 ++++++++++---- .../subexpression_ast_cascaded_binds.baseline | 1007 ++++++++++++----- .../resources/subexpression_unparsed.baseline | 172 +-- .../dev/cel/runtime/DefaultInterpreter.java | 2 +- 22 files changed, 7328 insertions(+), 2444 deletions(-) diff --git a/optimizer/src/main/java/dev/cel/optimizer/AstMutator.java b/optimizer/src/main/java/dev/cel/optimizer/AstMutator.java index e439c87cc..92f056e79 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/AstMutator.java +++ b/optimizer/src/main/java/dev/cel/optimizer/AstMutator.java @@ -20,9 +20,7 @@ import com.google.auto.value.AutoValue; import com.google.common.base.Preconditions; -import com.google.common.collect.HashBasedTable; import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Table; import com.google.errorprone.annotations.Immutable; import dev.cel.common.CelAbstractSyntaxTree; import dev.cel.common.CelMutableAst; @@ -261,43 +259,22 @@ public MangledComprehensionAst mangleComprehensionIdentifierNames( "Unexpected CelNavigableMutableExpr collision"); }, LinkedHashMap::new)); - int iterCount = 0; // The map that we'll eventually return to the caller. HashMap mangledIdentNamesToType = new HashMap<>(); - // Intermediary table used for the purposes of generating a unique mangled variable name. - Table comprehensionLevelToType = - HashBasedTable.create(); CelMutableExpr mutatedComprehensionExpr = navigableMutableAst.getAst().expr(); CelMutableSource newSource = navigableMutableAst.getAst().source(); + int iterCount = 0; for (Entry comprehensionEntry : comprehensionsToMangle.entrySet()) { - iterCount++; - CelNavigableMutableExpr comprehensionNode = comprehensionEntry.getKey(); - MangledComprehensionType comprehensionEntryType = comprehensionEntry.getValue(); - - CelMutableExpr comprehensionExpr = comprehensionNode.expr(); - int comprehensionNestingLevel = countComprehensionNestingLevel(comprehensionNode); - MangledComprehensionName mangledComprehensionName; - if (comprehensionLevelToType.contains(comprehensionNestingLevel, comprehensionEntryType)) { - mangledComprehensionName = - comprehensionLevelToType.get(comprehensionNestingLevel, comprehensionEntryType); - } else { - // First time encountering the pair of . Generate a unique - // mangled variable name for this. - int uniqueTypeIdx = comprehensionLevelToType.row(comprehensionNestingLevel).size(); - String mangledIterVarName = - newIterVarPrefix + comprehensionNestingLevel + ":" + uniqueTypeIdx; - String mangledResultName = - newResultPrefix + comprehensionNestingLevel + ":" + uniqueTypeIdx; - mangledComprehensionName = - MangledComprehensionName.of(mangledIterVarName, mangledResultName); - comprehensionLevelToType.put( - comprehensionNestingLevel, comprehensionEntryType, mangledComprehensionName); - } - mangledIdentNamesToType.put(mangledComprehensionName, comprehensionEntryType); + String mangledIterVarName = newIterVarPrefix + ":" + iterCount; + String mangledResultName = newResultPrefix + ":" + iterCount; + MangledComprehensionName mangledComprehensionName = + MangledComprehensionName.of(mangledIterVarName, mangledResultName); + mangledIdentNamesToType.put(mangledComprehensionName, comprehensionEntry.getValue()); + CelMutableExpr comprehensionExpr = comprehensionEntry.getKey().expr(); String iterVar = comprehensionExpr.comprehension().iterVar(); String accuVar = comprehensionExpr.comprehension().accuVar(); mutatedComprehensionExpr = @@ -315,6 +292,7 @@ public MangledComprehensionAst mangleComprehensionIdentifierNames( iterVar, mangledComprehensionName, comprehensionExpr.id()); + iterCount++; } if (iterCount >= iterationLimit) { @@ -822,19 +800,6 @@ private static long getMaxId(CelMutableExpr mutableExpr) { .orElseThrow(NoSuchElementException::new); } - private static int countComprehensionNestingLevel(CelNavigableMutableExpr comprehensionExpr) { - int nestedLevel = 0; - Optional maybeParent = comprehensionExpr.parent(); - while (maybeParent.isPresent()) { - if (maybeParent.get().getKind().equals(Kind.COMPREHENSION)) { - nestedLevel++; - } - - maybeParent = maybeParent.get().parent(); - } - return nestedLevel; - } - /** * Intermediate value class to store the mangled identifiers for iteration variable and the * comprehension result. diff --git a/optimizer/src/test/java/dev/cel/optimizer/AstMutatorTest.java b/optimizer/src/test/java/dev/cel/optimizer/AstMutatorTest.java index 5e1d98be9..3cc84ea95 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/AstMutatorTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/AstMutatorTest.java @@ -706,7 +706,7 @@ public void list_replaceElement() throws Exception { } @Test - public void createStruct_replaceValue() throws Exception { + public void struct_replaceValue() throws Exception { // Tree shape (brackets are expr IDs): // TestAllTypes [1] // single_int64 [2] @@ -722,7 +722,7 @@ public void createStruct_replaceValue() throws Exception { } @Test - public void createMap_replaceKey() throws Exception { + public void map_replaceKey() throws Exception { // Tree shape (brackets are expr IDs): // map [1] // map_entry [2] @@ -737,7 +737,7 @@ public void createMap_replaceKey() throws Exception { } @Test - public void createMap_replaceValue() throws Exception { + public void map_replaceValue() throws Exception { // Tree shape (brackets are expr IDs): // map [1] // map_entry [2] @@ -808,7 +808,7 @@ public void mangleComprehensionVariable_singleMacro() throws Exception { assertThat(mangledAst.getExpr().toString()) .isEqualTo( "COMPREHENSION [13] {\n" - + " iter_var: @c0:0\n" + + " iter_var: @c:0\n" + " iter_range: {\n" + " LIST [1] {\n" + " elements: {\n" @@ -816,7 +816,7 @@ public void mangleComprehensionVariable_singleMacro() throws Exception { + " }\n" + " }\n" + " }\n" - + " accu_var: @x0:0\n" + + " accu_var: @x:0\n" + " accu_init: {\n" + " CONSTANT [6] { value: false }\n" + " }\n" @@ -828,7 +828,7 @@ public void mangleComprehensionVariable_singleMacro() throws Exception { + " function: !_\n" + " args: {\n" + " IDENT [7] {\n" - + " name: @x0:0\n" + + " name: @x:0\n" + " }\n" + " }\n" + " }\n" @@ -840,21 +840,22 @@ public void mangleComprehensionVariable_singleMacro() throws Exception { + " function: _||_\n" + " args: {\n" + " IDENT [10] {\n" - + " name: @x0:0\n" + + " name: @x:0\n" + " }\n" + " IDENT [5] {\n" - + " name: @c0:0\n" + + " name: @c:0\n" + " }\n" + " }\n" + " }\n" + " }\n" + " result: {\n" + " IDENT [12] {\n" - + " name: @x0:0\n" + + " name: @x:0\n" + " }\n" + " }\n" + "}"); - assertThat(CEL_UNPARSER.unparse(mangledAst)).isEqualTo("[false].exists(@c0:0, @c0:0)"); + + assertThat(CEL_UNPARSER.unparse(mangledAst)).isEqualTo("[false].exists(@c:0, @c:0)"); assertThat(CEL.createProgram(CEL.check(mangledAst).getAst()).eval()).isEqualTo(false); assertConsistentMacroCalls(ast); } @@ -891,7 +892,7 @@ public void mangleComprehensionVariable_nestedMacroWithShadowedVariables() throw assertThat(mangledAst.getExpr().toString()) .isEqualTo( "COMPREHENSION [27] {\n" - + " iter_var: @c0:0\n" + + " iter_var: @c:1\n" + " iter_range: {\n" + " LIST [1] {\n" + " elements: {\n" @@ -901,7 +902,7 @@ public void mangleComprehensionVariable_nestedMacroWithShadowedVariables() throw + " }\n" + " }\n" + " }\n" - + " accu_var: @x0:0\n" + + " accu_var: @x:1\n" + " accu_init: {\n" + " CONSTANT [20] { value: false }\n" + " }\n" @@ -913,7 +914,7 @@ public void mangleComprehensionVariable_nestedMacroWithShadowedVariables() throw + " function: !_\n" + " args: {\n" + " IDENT [21] {\n" - + " name: @x0:0\n" + + " name: @x:1\n" + " }\n" + " }\n" + " }\n" @@ -925,20 +926,20 @@ public void mangleComprehensionVariable_nestedMacroWithShadowedVariables() throw + " function: _||_\n" + " args: {\n" + " IDENT [24] {\n" - + " name: @x0:0\n" + + " name: @x:1\n" + " }\n" + " COMPREHENSION [19] {\n" - + " iter_var: @c1:0\n" + + " iter_var: @c:0\n" + " iter_range: {\n" + " LIST [5] {\n" + " elements: {\n" + " IDENT [6] {\n" - + " name: @c0:0\n" + + " name: @c:1\n" + " }\n" + " }\n" + " }\n" + " }\n" - + " accu_var: @x1:0\n" + + " accu_var: @x:0\n" + " accu_init: {\n" + " CONSTANT [12] { value: false }\n" + " }\n" @@ -950,7 +951,7 @@ public void mangleComprehensionVariable_nestedMacroWithShadowedVariables() throw + " function: !_\n" + " args: {\n" + " IDENT [13] {\n" - + " name: @x1:0\n" + + " name: @x:0\n" + " }\n" + " }\n" + " }\n" @@ -962,13 +963,13 @@ public void mangleComprehensionVariable_nestedMacroWithShadowedVariables() throw + " function: _||_\n" + " args: {\n" + " IDENT [16] {\n" - + " name: @x1:0\n" + + " name: @x:0\n" + " }\n" + " CALL [10] {\n" + " function: _==_\n" + " args: {\n" + " IDENT [9] {\n" - + " name: @c1:0\n" + + " name: @c:0\n" + " }\n" + " CONSTANT [11] { value: 1 }\n" + " }\n" @@ -978,7 +979,7 @@ public void mangleComprehensionVariable_nestedMacroWithShadowedVariables() throw + " }\n" + " result: {\n" + " IDENT [18] {\n" - + " name: @x1:0\n" + + " name: @x:0\n" + " }\n" + " }\n" + " }\n" @@ -987,12 +988,13 @@ public void mangleComprehensionVariable_nestedMacroWithShadowedVariables() throw + " }\n" + " result: {\n" + " IDENT [26] {\n" - + " name: @x0:0\n" + + " name: @x:1\n" + " }\n" + " }\n" + "}"); + assertThat(CEL_UNPARSER.unparse(mangledAst)) - .isEqualTo("[x].exists(@c0:0, [@c0:0].exists(@c1:0, @c1:0 == 1))"); + .isEqualTo("[x].exists(@c:1, [@c:1].exists(@c:0, @c:0 == 1))"); assertThat(CEL.createProgram(CEL.check(mangledAst).getAst()).eval(ImmutableMap.of("x", 1))) .isEqualTo(true); assertConsistentMacroCalls(ast); diff --git a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerBaselineTest.java b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerBaselineTest.java index 2cd093ab1..f5a1c4086 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerBaselineTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerBaselineTest.java @@ -456,6 +456,9 @@ private enum CseTestCase { MULTIPLE_MACROS_2( "[[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == 'a')] +" + " [['a'].exists(l, l == 'a')] == [true, true, true, true]"), + MULTIPLE_MACROS_3( + "[1].exists(i, i > 0) && [1].exists(j, j > 0) && [1].exists(k, k > 1) && [2].exists(l, l >" + + " 1)"), NESTED_MACROS("[1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [[2, 3, 4], [2, 3, 4], [2, 3, 4]]"), NESTED_MACROS_2("[1, 2].map(y, [1, 2, 3].filter(x, x == y)) == [[1], [2]]"), INCLUSION_LIST("1 in [1,2,3] && 2 in [1,2,3] && 3 in [3, [1,2,3]] && 1 in [1,2,3]"), diff --git a/optimizer/src/test/resources/constfold_before_subexpression_unparsed.baseline b/optimizer/src/test/resources/constfold_before_subexpression_unparsed.baseline index ab1e6e12b..b18460018 100644 --- a/optimizer/src/test/resources/constfold_before_subexpression_unparsed.baseline +++ b/optimizer/src/test/resources/constfold_before_subexpression_unparsed.baseline @@ -302,6 +302,22 @@ Result: true [BLOCK_RECURSION_DEPTH_8]: true [BLOCK_RECURSION_DEPTH_9]: true +Test case: MULTIPLE_MACROS_3 +Source: [1].exists(i, i > 0) && [1].exists(j, j > 0) && [1].exists(k, k > 1) && [2].exists(l, l > 1) +=====> +Result: false +[CASCADED_BINDS]: false +[BLOCK_COMMON_SUBEXPR_ONLY]: false +[BLOCK_RECURSION_DEPTH_1]: false +[BLOCK_RECURSION_DEPTH_2]: false +[BLOCK_RECURSION_DEPTH_3]: false +[BLOCK_RECURSION_DEPTH_4]: false +[BLOCK_RECURSION_DEPTH_5]: false +[BLOCK_RECURSION_DEPTH_6]: false +[BLOCK_RECURSION_DEPTH_7]: false +[BLOCK_RECURSION_DEPTH_8]: false +[BLOCK_RECURSION_DEPTH_9]: false + Test case: NESTED_MACROS Source: [1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [[2, 3, 4], [2, 3, 4], [2, 3, 4]] =====> @@ -386,17 +402,17 @@ Test case: MACRO_SHADOWED_VARIABLE Source: [x - 1 > 3 ? x - 1 : 5].exists(x, x - 1 > 3) || x - 1 > 3 =====> Result: true -[CASCADED_BINDS]: cel.bind(@r0, x - 1, cel.bind(@r1, @r0 > 3, [@r1 ? @r0 : 5].exists(@c0:0, @c0:0 - 1 > 3) || @r1)) -[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([x - 1, @index0 > 3], [@index1 ? @index0 : 5].exists(@c0:0, @c0:0 - 1 > 3) || @index1) -[BLOCK_RECURSION_DEPTH_1]: cel.@block([x - 1, @index0 > 3, @index1 ? @index0 : 5, [@index2], @c0:0 - 1, @index4 > 3, @x0:0 || @index5], @index3.exists(@c0:0, @index5) || @index1) -[BLOCK_RECURSION_DEPTH_2]: cel.@block([x - 1 > 3, @index0 ? (x - 1) : 5, @c0:0 - 1 > 3, [@index1], @x0:0 || @index2], @index3.exists(@c0:0, @index2) || @index0) -[BLOCK_RECURSION_DEPTH_3]: cel.@block([x - 1 > 3, [@index0 ? (x - 1) : 5], @x0:0 || @c0:0 - 1 > 3, @index1.exists(@c0:0, @c0:0 - 1 > 3)], @index3 || @index0) -[BLOCK_RECURSION_DEPTH_4]: cel.@block([x - 1 > 3, [@index0 ? (x - 1) : 5].exists(@c0:0, @c0:0 - 1 > 3)], @index1 || @index0) -[BLOCK_RECURSION_DEPTH_5]: cel.@block([x - 1 > 3], [@index0 ? (x - 1) : 5].exists(@c0:0, @c0:0 - 1 > 3) || @index0) -[BLOCK_RECURSION_DEPTH_6]: cel.@block([x - 1 > 3], [@index0 ? (x - 1) : 5].exists(@c0:0, @c0:0 - 1 > 3) || @index0) -[BLOCK_RECURSION_DEPTH_7]: cel.@block([x - 1 > 3], [@index0 ? (x - 1) : 5].exists(@c0:0, @c0:0 - 1 > 3) || @index0) -[BLOCK_RECURSION_DEPTH_8]: cel.@block([x - 1 > 3], [@index0 ? (x - 1) : 5].exists(@c0:0, @c0:0 - 1 > 3) || @index0) -[BLOCK_RECURSION_DEPTH_9]: cel.@block([x - 1 > 3], [@index0 ? (x - 1) : 5].exists(@c0:0, @c0:0 - 1 > 3) || @index0) +[CASCADED_BINDS]: cel.bind(@r0, x - 1, cel.bind(@r1, @r0 > 3, [@r1 ? @r0 : 5].exists(@c:0, @c:0 - 1 > 3) || @r1)) +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([x - 1, @index0 > 3], [@index1 ? @index0 : 5].exists(@c:0, @c:0 - 1 > 3) || @index1) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([x - 1, @index0 > 3, @index1 ? @index0 : 5, [@index2], @c:0 - 1, @index4 > 3, @x:0 || @index5], @index3.exists(@c:0, @index5) || @index1) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([x - 1 > 3, @index0 ? (x - 1) : 5, @c:0 - 1 > 3, [@index1], @x:0 || @index2], @index3.exists(@c:0, @index2) || @index0) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([x - 1 > 3, [@index0 ? (x - 1) : 5], @x:0 || @c:0 - 1 > 3, @index1.exists(@c:0, @c:0 - 1 > 3)], @index3 || @index0) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([x - 1 > 3, [@index0 ? (x - 1) : 5].exists(@c:0, @c:0 - 1 > 3)], @index1 || @index0) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([x - 1 > 3], [@index0 ? (x - 1) : 5].exists(@c:0, @c:0 - 1 > 3) || @index0) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([x - 1 > 3], [@index0 ? (x - 1) : 5].exists(@c:0, @c:0 - 1 > 3) || @index0) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([x - 1 > 3], [@index0 ? (x - 1) : 5].exists(@c:0, @c:0 - 1 > 3) || @index0) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([x - 1 > 3], [@index0 ? (x - 1) : 5].exists(@c:0, @c:0 - 1 > 3) || @index0) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([x - 1 > 3], [@index0 ? (x - 1) : 5].exists(@c:0, @c:0 - 1 > 3) || @index0) Test case: MACRO_SHADOWED_VARIABLE_2 Source: ["foo", "bar"].map(x, [x + x, x + x]).map(x, [x + x, x + x]) @@ -668,4 +684,4 @@ Result: 31 [BLOCK_RECURSION_DEPTH_6]: cel.@block([pure_custom_func(msg.oneof_type.payload.single_int64), @index0 + pure_custom_func(msg.oneof_type.payload.single_int32) + @index0], @index1 + pure_custom_func(msg.single_int64)) [BLOCK_RECURSION_DEPTH_7]: cel.@block([pure_custom_func(msg.oneof_type.payload.single_int64)], @index0 + pure_custom_func(msg.oneof_type.payload.single_int32) + @index0 + pure_custom_func(msg.single_int64)) [BLOCK_RECURSION_DEPTH_8]: cel.@block([pure_custom_func(msg.oneof_type.payload.single_int64)], @index0 + pure_custom_func(msg.oneof_type.payload.single_int32) + @index0 + pure_custom_func(msg.single_int64)) -[BLOCK_RECURSION_DEPTH_9]: cel.@block([pure_custom_func(msg.oneof_type.payload.single_int64)], @index0 + pure_custom_func(msg.oneof_type.payload.single_int32) + @index0 + pure_custom_func(msg.single_int64)) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([pure_custom_func(msg.oneof_type.payload.single_int64)], @index0 + pure_custom_func(msg.oneof_type.payload.single_int32) + @index0 + pure_custom_func(msg.single_int64)) \ No newline at end of file diff --git a/optimizer/src/test/resources/large_expressions_bind_cascaded.baseline b/optimizer/src/test/resources/large_expressions_bind_cascaded.baseline index b39eebd06..a37fd38ce 100644 --- a/optimizer/src/test/resources/large_expressions_bind_cascaded.baseline +++ b/optimizer/src/test/resources/large_expressions_bind_cascaded.baseline @@ -14,4 +14,4 @@ Test case: NESTED_MACROS Source: [1,2,3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3])))))))) =====> Result: [[[[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]]], [[[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]]], [[[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]]]] -Unparsed: cel.bind(@r0, [1, 2, 3], @r0.map(@c0:0, @r0.map(@c1:0, @r0.map(@c2:0, @r0.map(@c3:0, @r0.map(@c4:0, @r0.map(@c5:0, @r0.map(@c6:0, @r0.map(@c7:0, @r0))))))))) +Unparsed: cel.bind(@r0, [1, 2, 3], @r0.map(@c:7, @r0.map(@c:6, @r0.map(@c:5, @r0.map(@c:4, @r0.map(@c:3, @r0.map(@c:2, @r0.map(@c:1, @r0.map(@c:0, @r0))))))))) \ No newline at end of file diff --git a/optimizer/src/test/resources/large_expressions_block_common_subexpr.baseline b/optimizer/src/test/resources/large_expressions_block_common_subexpr.baseline index 42c6e9e1a..35a169875 100644 --- a/optimizer/src/test/resources/large_expressions_block_common_subexpr.baseline +++ b/optimizer/src/test/resources/large_expressions_block_common_subexpr.baseline @@ -14,4 +14,4 @@ Test case: NESTED_MACROS Source: [1,2,3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3])))))))) =====> Result: [[[[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]]], [[[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]]], [[[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]]]] -Unparsed: cel.@block([[1, 2, 3]], @index0.map(@c0:0, @index0.map(@c1:0, @index0.map(@c2:0, @index0.map(@c3:0, @index0.map(@c4:0, @index0.map(@c5:0, @index0.map(@c6:0, @index0.map(@c7:0, @index0))))))))) +Unparsed: cel.@block([[1, 2, 3]], @index0.map(@c:7, @index0.map(@c:6, @index0.map(@c:5, @index0.map(@c:4, @index0.map(@c:3, @index0.map(@c:2, @index0.map(@c:1, @index0.map(@c:0, @index0))))))))) \ No newline at end of file diff --git a/optimizer/src/test/resources/large_expressions_block_recursion_depth_1.baseline b/optimizer/src/test/resources/large_expressions_block_recursion_depth_1.baseline index f391e5f87..7409190cc 100644 --- a/optimizer/src/test/resources/large_expressions_block_recursion_depth_1.baseline +++ b/optimizer/src/test/resources/large_expressions_block_recursion_depth_1.baseline @@ -14,4 +14,4 @@ Test case: NESTED_MACROS Source: [1,2,3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3])))))))) =====> Result: [[[[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]]], [[[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]]], [[[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]]]] -Unparsed: cel.@block([[1, 2, 3], [@index0], @x7:0 + @index1], @index0.map(@c0:0, @index0.map(@c1:0, @index0.map(@c2:0, @index0.map(@c3:0, @index0.map(@c4:0, @index0.map(@c5:0, @index0.map(@c6:0, @index0.map(@c7:0, @index0))))))))) +Unparsed: cel.@block([[1, 2, 3], [@index0], @x:0 + @index1], @index0.map(@c:7, @index0.map(@c:6, @index0.map(@c:5, @index0.map(@c:4, @index0.map(@c:3, @index0.map(@c:2, @index0.map(@c:1, @index0.map(@c:0, @index0))))))))) \ No newline at end of file diff --git a/optimizer/src/test/resources/large_expressions_block_recursion_depth_2.baseline b/optimizer/src/test/resources/large_expressions_block_recursion_depth_2.baseline index d77db7b6f..01fe95991 100644 --- a/optimizer/src/test/resources/large_expressions_block_recursion_depth_2.baseline +++ b/optimizer/src/test/resources/large_expressions_block_recursion_depth_2.baseline @@ -14,4 +14,4 @@ Test case: NESTED_MACROS Source: [1,2,3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3])))))))) =====> Result: [[[[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]]], [[[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]]], [[[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]]]] -Unparsed: cel.@block([[1, 2, 3], @x7:0 + [@index0], @index0.map(@c7:0, @index0), @x6:0 + [@index2], @index0.map(@c6:0, @index2), @x5:0 + [@index4], @index0.map(@c5:0, @index4), @x4:0 + [@index6], @index0.map(@c4:0, @index6), @x3:0 + [@index8], @index0.map(@c3:0, @index8), @x2:0 + [@index10], @index0.map(@c2:0, @index10), @x1:0 + [@index12], @index0.map(@c1:0, @index12), @x0:0 + [@index14]], @index0.map(@c0:0, @index14)) +Unparsed: cel.@block([[1, 2, 3], @x:0 + [@index0], @index0.map(@c:0, @index0), @x:1 + [@index2], @index0.map(@c:1, @index2), @x:2 + [@index4], @index0.map(@c:2, @index4), @x:3 + [@index6], @index0.map(@c:3, @index6), @x:4 + [@index8], @index0.map(@c:4, @index8), @x:5 + [@index10], @index0.map(@c:5, @index10), @x:6 + [@index12], @index0.map(@c:6, @index12), @x:7 + [@index14]], @index0.map(@c:7, @index14)) \ No newline at end of file diff --git a/optimizer/src/test/resources/large_expressions_block_recursion_depth_3.baseline b/optimizer/src/test/resources/large_expressions_block_recursion_depth_3.baseline index 24138a632..56d163470 100644 --- a/optimizer/src/test/resources/large_expressions_block_recursion_depth_3.baseline +++ b/optimizer/src/test/resources/large_expressions_block_recursion_depth_3.baseline @@ -14,4 +14,4 @@ Test case: NESTED_MACROS Source: [1,2,3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3])))))))) =====> Result: [[[[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]]], [[[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]]], [[[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]]]] -Unparsed: cel.@block([[1, 2, 3], @index0.map(@c7:0, @index0), @index0.map(@c6:0, @index1), @index0.map(@c5:0, @index2), @index0.map(@c4:0, @index3), @index0.map(@c3:0, @index4), @index0.map(@c2:0, @index5), @index0.map(@c1:0, @index6)], @index0.map(@c0:0, @index7)) +Unparsed: cel.@block([[1, 2, 3], @index0.map(@c:0, @index0), @index0.map(@c:1, @index1), @index0.map(@c:2, @index2), @index0.map(@c:3, @index3), @index0.map(@c:4, @index4), @index0.map(@c:5, @index5), @index0.map(@c:6, @index6)], @index0.map(@c:7, @index7)) \ No newline at end of file diff --git a/optimizer/src/test/resources/subexpression_ast_block_common_subexpr_only.baseline b/optimizer/src/test/resources/subexpression_ast_block_common_subexpr_only.baseline index a6bb92bb4..c1ad64871 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_common_subexpr_only.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_common_subexpr_only.baseline @@ -1116,61 +1116,269 @@ CALL [1] { args: { LIST [2] { elements: { - CALL [3] { - function: size + LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + } + } + LIST [5] { + elements: { + CONSTANT [6] { value: 2 } + } + } + } + } + CALL [7] { + function: _==_ + args: { + CALL [8] { + function: _+_ args: { - LIST [4] { - elements: { - COMPREHENSION [5] { - iter_var: @c0:0 - iter_range: { - LIST [6] { - elements: { - CONSTANT [7] { value: 1 } + CALL [9] { + function: _+_ + args: { + CALL [10] { + function: _+_ + args: { + CALL [11] { + function: size + args: { + LIST [12] { + elements: { + COMPREHENSION [13] { + iter_var: @c:0 + iter_range: { + IDENT [14] { + name: @index0 + } + } + accu_var: @x:0 + accu_init: { + CONSTANT [15] { value: false } + } + loop_condition: { + CALL [16] { + function: @not_strictly_false + args: { + CALL [17] { + function: !_ + args: { + IDENT [18] { + name: @x:0 + } + } + } + } + } + } + loop_step: { + CALL [19] { + function: _||_ + args: { + IDENT [20] { + name: @x:0 + } + CALL [21] { + function: _>_ + args: { + IDENT [22] { + name: @c:0 + } + CONSTANT [23] { value: 0 } + } + } + } + } + } + result: { + IDENT [24] { + name: @x:0 + } + } + } + } + } } } - } - accu_var: @x0:0 - accu_init: { - CONSTANT [8] { value: false } - } - loop_condition: { - CALL [9] { - function: @not_strictly_false + CALL [25] { + function: size args: { - CALL [10] { - function: !_ - args: { - IDENT [11] { - name: @x0:0 + LIST [26] { + elements: { + COMPREHENSION [27] { + iter_var: @c:1 + iter_range: { + IDENT [28] { + name: @index0 + } + } + accu_var: @x:1 + accu_init: { + CONSTANT [29] { value: false } + } + loop_condition: { + CALL [30] { + function: @not_strictly_false + args: { + CALL [31] { + function: !_ + args: { + IDENT [32] { + name: @x:1 + } + } + } + } + } + } + loop_step: { + CALL [33] { + function: _||_ + args: { + IDENT [34] { + name: @x:1 + } + CALL [35] { + function: _>_ + args: { + IDENT [36] { + name: @c:1 + } + CONSTANT [37] { value: 0 } + } + } + } + } + } + result: { + IDENT [38] { + name: @x:1 + } + } } } } } } } - loop_step: { - CALL [12] { - function: _||_ - args: { - IDENT [13] { - name: @x0:0 - } - CALL [14] { - function: _>_ - args: { - IDENT [15] { - name: @c0:0 + } + CALL [39] { + function: size + args: { + LIST [40] { + elements: { + COMPREHENSION [41] { + iter_var: @c:2 + iter_range: { + IDENT [42] { + name: @index1 + } + } + accu_var: @x:2 + accu_init: { + CONSTANT [43] { value: false } + } + loop_condition: { + CALL [44] { + function: @not_strictly_false + args: { + CALL [45] { + function: !_ + args: { + IDENT [46] { + name: @x:2 + } + } + } + } + } + } + loop_step: { + CALL [47] { + function: _||_ + args: { + IDENT [48] { + name: @x:2 + } + CALL [49] { + function: _>_ + args: { + IDENT [50] { + name: @c:2 + } + CONSTANT [51] { value: 1 } + } + } + } + } + } + result: { + IDENT [52] { + name: @x:2 } - CONSTANT [16] { value: 0 } } } } } } - result: { - IDENT [17] { - name: @x0:0 + } + } + } + CALL [53] { + function: size + args: { + LIST [54] { + elements: { + COMPREHENSION [55] { + iter_var: @c:3 + iter_range: { + IDENT [56] { + name: @index1 + } + } + accu_var: @x:3 + accu_init: { + CONSTANT [57] { value: false } + } + loop_condition: { + CALL [58] { + function: @not_strictly_false + args: { + CALL [59] { + function: !_ + args: { + IDENT [60] { + name: @x:3 + } + } + } + } + } + } + loop_step: { + CALL [61] { + function: _||_ + args: { + IDENT [62] { + name: @x:3 + } + CALL [63] { + function: _>_ + args: { + IDENT [64] { + name: @c:3 + } + CONSTANT [65] { value: 1 } + } + } + } + } + } + result: { + IDENT [66] { + name: @x:3 + } + } } } } @@ -1178,33 +1386,234 @@ CALL [1] { } } } - CALL [18] { - function: size + CONSTANT [67] { value: 4 } + } + } + } +} +Test case: MULTIPLE_MACROS_2 +Source: [[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == 'a')] + [['a'].exists(l, l == 'a')] == [true, true, true, true] +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + } + } + LIST [5] { + elements: { + CONSTANT [6] { value: "a" } + } + } + } + } + CALL [7] { + function: _==_ + args: { + CALL [8] { + function: _+_ args: { - LIST [19] { - elements: { - COMPREHENSION [20] { - iter_var: @c0:0 - iter_range: { - LIST [21] { + CALL [9] { + function: _+_ + args: { + CALL [10] { + function: _+_ + args: { + LIST [11] { elements: { - CONSTANT [22] { value: 2 } + COMPREHENSION [12] { + iter_var: @c:0 + iter_range: { + IDENT [13] { + name: @index0 + } + } + accu_var: @x:0 + accu_init: { + CONSTANT [14] { value: false } + } + loop_condition: { + CALL [15] { + function: @not_strictly_false + args: { + CALL [16] { + function: !_ + args: { + IDENT [17] { + name: @x:0 + } + } + } + } + } + } + loop_step: { + CALL [18] { + function: _||_ + args: { + IDENT [19] { + name: @x:0 + } + CALL [20] { + function: _>_ + args: { + IDENT [21] { + name: @c:0 + } + CONSTANT [22] { value: 0 } + } + } + } + } + } + result: { + IDENT [23] { + name: @x:0 + } + } + } + } + } + LIST [24] { + elements: { + COMPREHENSION [25] { + iter_var: @c:1 + iter_range: { + IDENT [26] { + name: @index0 + } + } + accu_var: @x:1 + accu_init: { + CONSTANT [27] { value: false } + } + loop_condition: { + CALL [28] { + function: @not_strictly_false + args: { + CALL [29] { + function: !_ + args: { + IDENT [30] { + name: @x:1 + } + } + } + } + } + } + loop_step: { + CALL [31] { + function: _||_ + args: { + IDENT [32] { + name: @x:1 + } + CALL [33] { + function: _>_ + args: { + IDENT [34] { + name: @c:1 + } + CONSTANT [35] { value: 0 } + } + } + } + } + } + result: { + IDENT [36] { + name: @x:1 + } + } + } } } } - accu_var: @x0:0 + } + LIST [37] { + elements: { + COMPREHENSION [38] { + iter_var: @c:2 + iter_range: { + IDENT [39] { + name: @index1 + } + } + accu_var: @x:2 + accu_init: { + CONSTANT [40] { value: false } + } + loop_condition: { + CALL [41] { + function: @not_strictly_false + args: { + CALL [42] { + function: !_ + args: { + IDENT [43] { + name: @x:2 + } + } + } + } + } + } + loop_step: { + CALL [44] { + function: _||_ + args: { + IDENT [45] { + name: @x:2 + } + CALL [46] { + function: _==_ + args: { + IDENT [47] { + name: @c:2 + } + CONSTANT [48] { value: "a" } + } + } + } + } + } + result: { + IDENT [49] { + name: @x:2 + } + } + } + } + } + } + } + LIST [50] { + elements: { + COMPREHENSION [51] { + iter_var: @c:3 + iter_range: { + IDENT [52] { + name: @index1 + } + } + accu_var: @x:3 accu_init: { - CONSTANT [23] { value: false } + CONSTANT [53] { value: false } } loop_condition: { - CALL [24] { + CALL [54] { function: @not_strictly_false args: { - CALL [25] { + CALL [55] { function: !_ args: { - IDENT [26] { - name: @x0:0 + IDENT [56] { + name: @x:3 } } } @@ -1212,27 +1621,27 @@ CALL [1] { } } loop_step: { - CALL [27] { + CALL [57] { function: _||_ args: { - IDENT [28] { - name: @x0:0 + IDENT [58] { + name: @x:3 } - CALL [29] { - function: _>_ + CALL [59] { + function: _==_ args: { - IDENT [30] { - name: @c0:0 + IDENT [60] { + name: @c:3 } - CONSTANT [31] { value: 1 } + CONSTANT [61] { value: "a" } } } } } } result: { - IDENT [32] { - name: @x0:0 + IDENT [62] { + name: @x:3 } } } @@ -1240,45 +1649,20 @@ CALL [1] { } } } - } - } - CALL [33] { - function: _==_ - args: { - CALL [34] { - function: _+_ - args: { - CALL [35] { - function: _+_ - args: { - CALL [36] { - function: _+_ - args: { - IDENT [37] { - name: @index0 - } - IDENT [38] { - name: @index0 - } - } - } - IDENT [39] { - name: @index1 - } - } - } - IDENT [40] { - name: @index1 - } + LIST [63] { + elements: { + CONSTANT [64] { value: true } + CONSTANT [65] { value: true } + CONSTANT [66] { value: true } + CONSTANT [67] { value: true } } } - CONSTANT [41] { value: 4 } } } } } -Test case: MULTIPLE_MACROS_2 -Source: [[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == 'a')] + [['a'].exists(l, l == 'a')] == [true, true, true, true] +Test case: MULTIPLE_MACROS_3 +Source: [1].exists(i, i > 0) && [1].exists(j, j > 0) && [1].exists(k, k > 1) && [2].exists(l, l > 1) =====> CALL [1] { function: cel.@block @@ -1287,28 +1671,37 @@ CALL [1] { elements: { LIST [3] { elements: { - COMPREHENSION [4] { - iter_var: @c0:0 + CONSTANT [4] { value: 1 } + } + } + } + } + CALL [5] { + function: _&&_ + args: { + CALL [6] { + function: _&&_ + args: { + COMPREHENSION [7] { + iter_var: @c:0 iter_range: { - LIST [5] { - elements: { - CONSTANT [6] { value: 1 } - } + IDENT [8] { + name: @index0 } } - accu_var: @x0:0 + accu_var: @x:0 accu_init: { - CONSTANT [7] { value: false } + CONSTANT [9] { value: false } } loop_condition: { - CALL [8] { + CALL [10] { function: @not_strictly_false args: { - CALL [9] { + CALL [11] { function: !_ args: { - IDENT [10] { - name: @x0:0 + IDENT [12] { + name: @x:0 } } } @@ -1316,44 +1709,38 @@ CALL [1] { } } loop_step: { - CALL [11] { + CALL [13] { function: _||_ args: { - IDENT [12] { - name: @x0:0 + IDENT [14] { + name: @x:0 } - CALL [13] { + CALL [15] { function: _>_ args: { - IDENT [14] { - name: @c0:0 + IDENT [16] { + name: @c:0 } - CONSTANT [15] { value: 0 } + CONSTANT [17] { value: 0 } } } } } } result: { - IDENT [16] { - name: @x0:0 + IDENT [18] { + name: @x:0 } } } - } - } - LIST [17] { - elements: { - COMPREHENSION [18] { - iter_var: @c0:1 + COMPREHENSION [19] { + iter_var: @c:1 iter_range: { - LIST [19] { - elements: { - CONSTANT [20] { value: "a" } - } + IDENT [20] { + name: @index0 } } - accu_var: @x0:1 + accu_var: @x:1 accu_init: { CONSTANT [21] { value: false } } @@ -1365,7 +1752,7 @@ CALL [1] { function: !_ args: { IDENT [24] { - name: @x0:1 + name: @x:1 } } } @@ -1377,15 +1764,15 @@ CALL [1] { function: _||_ args: { IDENT [26] { - name: @x0:1 + name: @x:1 } CALL [27] { - function: _==_ + function: _>_ args: { IDENT [28] { - name: @c0:1 + name: @c:1 } - CONSTANT [29] { value: "a" } + CONSTANT [29] { value: 0 } } } } @@ -1393,52 +1780,121 @@ CALL [1] { } result: { IDENT [30] { - name: @x0:1 + name: @x:1 } } } } } - } - } - CALL [31] { - function: _==_ - args: { - CALL [32] { - function: _+_ + CALL [31] { + function: _&&_ args: { - CALL [33] { - function: _+_ - args: { - CALL [34] { - function: _+_ + COMPREHENSION [32] { + iter_var: @c:2 + iter_range: { + IDENT [33] { + name: @index0 + } + } + accu_var: @x:2 + accu_init: { + CONSTANT [34] { value: false } + } + loop_condition: { + CALL [35] { + function: @not_strictly_false args: { - IDENT [35] { - name: @index0 + CALL [36] { + function: !_ + args: { + IDENT [37] { + name: @x:2 + } + } } - IDENT [36] { - name: @index0 + } + } + } + loop_step: { + CALL [38] { + function: _||_ + args: { + IDENT [39] { + name: @x:2 + } + CALL [40] { + function: _>_ + args: { + IDENT [41] { + name: @c:2 + } + CONSTANT [42] { value: 1 } + } } } } - IDENT [37] { - name: @index1 + } + result: { + IDENT [43] { + name: @x:2 } } } - IDENT [38] { - name: @index1 + COMPREHENSION [44] { + iter_var: @c:3 + iter_range: { + LIST [45] { + elements: { + CONSTANT [46] { value: 2 } + } + } + } + accu_var: @x:3 + accu_init: { + CONSTANT [47] { value: false } + } + loop_condition: { + CALL [48] { + function: @not_strictly_false + args: { + CALL [49] { + function: !_ + args: { + IDENT [50] { + name: @x:3 + } + } + } + } + } + } + loop_step: { + CALL [51] { + function: _||_ + args: { + IDENT [52] { + name: @x:3 + } + CALL [53] { + function: _>_ + args: { + IDENT [54] { + name: @c:3 + } + CONSTANT [55] { value: 1 } + } + } + } + } + } + result: { + IDENT [56] { + name: @x:3 + } + } } } } - LIST [39] { - elements: { - CONSTANT [40] { value: true } - CONSTANT [41] { value: true } - CONSTANT [42] { value: true } - CONSTANT [43] { value: true } - } - } } } } @@ -1471,13 +1927,13 @@ CALL [1] { function: _==_ args: { COMPREHENSION [12] { - iter_var: @c0:0 + iter_var: @c:1 iter_range: { IDENT [13] { name: @index0 } } - accu_var: @x0:0 + accu_var: @x:1 accu_init: { LIST [14] { elements: { @@ -1492,18 +1948,18 @@ CALL [1] { function: _+_ args: { IDENT [17] { - name: @x0:0 + name: @x:1 } LIST [18] { elements: { COMPREHENSION [19] { - iter_var: @c1:0 + iter_var: @c:0 iter_range: { IDENT [20] { name: @index0 } } - accu_var: @x1:0 + accu_var: @x:0 accu_init: { LIST [21] { elements: { @@ -1518,7 +1974,7 @@ CALL [1] { function: _+_ args: { IDENT [24] { - name: @x1:0 + name: @x:0 } LIST [25] { elements: { @@ -1526,7 +1982,7 @@ CALL [1] { function: _+_ args: { IDENT [27] { - name: @c1:0 + name: @c:0 } CONSTANT [28] { value: 1 } } @@ -1538,7 +1994,7 @@ CALL [1] { } result: { IDENT [29] { - name: @x1:0 + name: @x:0 } } } @@ -1549,7 +2005,7 @@ CALL [1] { } result: { IDENT [30] { - name: @x0:0 + name: @x:1 } } } @@ -1577,7 +2033,7 @@ CALL [31] { function: _==_ args: { COMPREHENSION [30] { - iter_var: @c0:0 + iter_var: @c:1 iter_range: { LIST [1] { elements: { @@ -1586,7 +2042,7 @@ CALL [31] { } } } - accu_var: @x0:0 + accu_var: @x:1 accu_init: { LIST [24] { elements: { @@ -1601,12 +2057,12 @@ CALL [31] { function: _+_ args: { IDENT [26] { - name: @x0:0 + name: @x:1 } LIST [27] { elements: { COMPREHENSION [23] { - iter_var: @c1:0 + iter_var: @c:0 iter_range: { LIST [6] { elements: { @@ -1616,7 +2072,7 @@ CALL [31] { } } } - accu_var: @x1:0 + accu_var: @x:0 accu_init: { LIST [15] { elements: { @@ -1634,10 +2090,10 @@ CALL [31] { function: _==_ args: { IDENT [12] { - name: @c1:0 + name: @c:0 } IDENT [14] { - name: @c0:0 + name: @c:1 } } } @@ -1645,26 +2101,26 @@ CALL [31] { function: _+_ args: { IDENT [17] { - name: @x1:0 + name: @x:0 } LIST [18] { elements: { IDENT [11] { - name: @c1:0 + name: @c:0 } } } } } IDENT [20] { - name: @x1:0 + name: @x:0 } } } } result: { IDENT [22] { - name: @x1:0 + name: @x:0 } } } @@ -1675,7 +2131,7 @@ CALL [31] { } result: { IDENT [29] { - name: @x0:0 + name: @x:1 } } } @@ -1861,13 +2317,13 @@ CALL [1] { function: _==_ args: { COMPREHENSION [13] { - iter_var: @c0:0 + iter_var: @c:1 iter_range: { IDENT [14] { name: @index0 } } - accu_var: @x0:0 + accu_var: @x:1 accu_init: { LIST [15] { elements: { @@ -1882,18 +2338,18 @@ CALL [1] { function: _+_ args: { IDENT [18] { - name: @x0:0 + name: @x:1 } LIST [19] { elements: { COMPREHENSION [20] { - iter_var: @c1:0 + iter_var: @c:0 iter_range: { IDENT [21] { name: @index0 } } - accu_var: @x1:0 + accu_var: @x:0 accu_init: { LIST [22] { elements: { @@ -1908,7 +2364,7 @@ CALL [1] { function: _+_ args: { IDENT [25] { - name: @x1:0 + name: @x:0 } LIST [26] { elements: { @@ -1922,7 +2378,7 @@ CALL [1] { } result: { IDENT [28] { - name: @x1:0 + name: @x:0 } } } @@ -1933,7 +2389,7 @@ CALL [1] { } result: { IDENT [29] { - name: @x0:0 + name: @x:1 } } } @@ -1983,7 +2439,7 @@ CALL [1] { function: _||_ args: { COMPREHENSION [10] { - iter_var: @c0:0 + iter_var: @c:0 iter_range: { LIST [11] { elements: { @@ -2002,7 +2458,7 @@ CALL [1] { } } } - accu_var: @x0:0 + accu_var: @x:0 accu_init: { CONSTANT [16] { value: false } } @@ -2014,7 +2470,7 @@ CALL [1] { function: !_ args: { IDENT [19] { - name: @x0:0 + name: @x:0 } } } @@ -2026,7 +2482,7 @@ CALL [1] { function: _||_ args: { IDENT [21] { - name: @x0:0 + name: @x:0 } CALL [22] { function: _>_ @@ -2035,7 +2491,7 @@ CALL [1] { function: _-_ args: { IDENT [24] { - name: @c0:0 + name: @c:0 } CONSTANT [25] { value: 1 } } @@ -2048,7 +2504,7 @@ CALL [1] { } result: { IDENT [27] { - name: @x0:0 + name: @x:0 } } } @@ -2071,10 +2527,10 @@ CALL [1] { function: _+_ args: { IDENT [4] { - name: @c1:0 + name: @c:0 } IDENT [5] { - name: @c1:0 + name: @c:0 } } } @@ -2082,20 +2538,20 @@ CALL [1] { function: _+_ args: { IDENT [7] { - name: @c0:0 + name: @c:1 } IDENT [8] { - name: @c0:0 + name: @c:1 } } } } } COMPREHENSION [9] { - iter_var: @c0:0 + iter_var: @c:1 iter_range: { COMPREHENSION [10] { - iter_var: @c1:0 + iter_var: @c:0 iter_range: { LIST [11] { elements: { @@ -2104,7 +2560,7 @@ CALL [1] { } } } - accu_var: @x1:0 + accu_var: @x:0 accu_init: { LIST [14] { elements: { @@ -2119,7 +2575,7 @@ CALL [1] { function: _+_ args: { IDENT [17] { - name: @x1:0 + name: @x:0 } LIST [18] { elements: { @@ -2140,12 +2596,12 @@ CALL [1] { } result: { IDENT [22] { - name: @x1:0 + name: @x:0 } } } } - accu_var: @x0:0 + accu_var: @x:1 accu_init: { LIST [23] { elements: { @@ -2160,7 +2616,7 @@ CALL [1] { function: _+_ args: { IDENT [26] { - name: @x0:0 + name: @x:1 } LIST [27] { elements: { @@ -2181,7 +2637,7 @@ CALL [1] { } result: { IDENT [31] { - name: @x0:0 + name: @x:1 } } } @@ -3101,4 +3557,4 @@ CALL [1] { } } } -} +} \ No newline at end of file diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_1.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_1.baseline index 497825b80..1b081c43c 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_1.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_1.baseline @@ -1436,90 +1436,130 @@ CALL [1] { CONSTANT [4] { value: 1 } } } - CALL [5] { + LIST [5] { + elements: { + CONSTANT [6] { value: 2 } + } + } + CALL [7] { function: _>_ args: { - IDENT [6] { - name: @c0:0 + IDENT [8] { + name: @c:0 } - CONSTANT [7] { value: 0 } + CONSTANT [9] { value: 0 } } } - CALL [8] { + CALL [10] { function: _||_ args: { - IDENT [9] { - name: @x0:0 + IDENT [11] { + name: @x:0 } - IDENT [10] { - name: @index1 + IDENT [12] { + name: @index2 } } } - LIST [11] { - elements: { - CONSTANT [12] { value: 2 } - } - } CALL [13] { function: _>_ args: { IDENT [14] { - name: @c0:0 + name: @c:1 } - CONSTANT [15] { value: 1 } + CONSTANT [15] { value: 0 } } } CALL [16] { function: _||_ args: { IDENT [17] { - name: @x0:0 + name: @x:1 } IDENT [18] { name: @index4 } } } + CALL [19] { + function: _>_ + args: { + IDENT [20] { + name: @c:2 + } + CONSTANT [21] { value: 1 } + } + } + CALL [22] { + function: _||_ + args: { + IDENT [23] { + name: @x:2 + } + IDENT [24] { + name: @index6 + } + } + } + CALL [25] { + function: _>_ + args: { + IDENT [26] { + name: @c:3 + } + CONSTANT [27] { value: 1 } + } + } + CALL [28] { + function: _||_ + args: { + IDENT [29] { + name: @x:3 + } + IDENT [30] { + name: @index8 + } + } + } } } - CALL [19] { + CALL [31] { function: _==_ args: { - CALL [20] { + CALL [32] { function: _+_ args: { - CALL [21] { + CALL [33] { function: _+_ args: { - CALL [22] { + CALL [34] { function: _+_ args: { - CALL [23] { + CALL [35] { function: size args: { - LIST [24] { + LIST [36] { elements: { - COMPREHENSION [25] { - iter_var: @c0:0 + COMPREHENSION [37] { + iter_var: @c:0 iter_range: { - IDENT [26] { + IDENT [38] { name: @index0 } } - accu_var: @x0:0 + accu_var: @x:0 accu_init: { - CONSTANT [27] { value: false } + CONSTANT [39] { value: false } } loop_condition: { - CALL [28] { + CALL [40] { function: @not_strictly_false args: { - CALL [29] { + CALL [41] { function: !_ args: { - IDENT [30] { - name: @x0:0 + IDENT [42] { + name: @x:0 } } } @@ -1527,13 +1567,13 @@ CALL [1] { } } loop_step: { - IDENT [31] { - name: @index2 + IDENT [43] { + name: @index3 } } result: { - IDENT [32] { - name: @x0:0 + IDENT [44] { + name: @x:0 } } } @@ -1541,31 +1581,31 @@ CALL [1] { } } } - CALL [33] { + CALL [45] { function: size args: { - LIST [34] { + LIST [46] { elements: { - COMPREHENSION [35] { - iter_var: @c0:0 + COMPREHENSION [47] { + iter_var: @c:1 iter_range: { - IDENT [36] { + IDENT [48] { name: @index0 } } - accu_var: @x0:0 + accu_var: @x:1 accu_init: { - CONSTANT [37] { value: false } + CONSTANT [49] { value: false } } loop_condition: { - CALL [38] { + CALL [50] { function: @not_strictly_false args: { - CALL [39] { + CALL [51] { function: !_ args: { - IDENT [40] { - name: @x0:0 + IDENT [52] { + name: @x:1 } } } @@ -1573,13 +1613,13 @@ CALL [1] { } } loop_step: { - IDENT [41] { - name: @index2 + IDENT [53] { + name: @index5 } } result: { - IDENT [42] { - name: @x0:0 + IDENT [54] { + name: @x:1 } } } @@ -1589,31 +1629,31 @@ CALL [1] { } } } - CALL [43] { + CALL [55] { function: size args: { - LIST [44] { + LIST [56] { elements: { - COMPREHENSION [45] { - iter_var: @c0:0 + COMPREHENSION [57] { + iter_var: @c:2 iter_range: { - IDENT [46] { - name: @index3 + IDENT [58] { + name: @index1 } } - accu_var: @x0:0 + accu_var: @x:2 accu_init: { - CONSTANT [47] { value: false } + CONSTANT [59] { value: false } } loop_condition: { - CALL [48] { + CALL [60] { function: @not_strictly_false args: { - CALL [49] { + CALL [61] { function: !_ args: { - IDENT [50] { - name: @x0:0 + IDENT [62] { + name: @x:2 } } } @@ -1621,13 +1661,13 @@ CALL [1] { } } loop_step: { - IDENT [51] { - name: @index5 + IDENT [63] { + name: @index7 } } result: { - IDENT [52] { - name: @x0:0 + IDENT [64] { + name: @x:2 } } } @@ -1637,31 +1677,31 @@ CALL [1] { } } } - CALL [53] { + CALL [65] { function: size args: { - LIST [54] { + LIST [66] { elements: { - COMPREHENSION [55] { - iter_var: @c0:0 + COMPREHENSION [67] { + iter_var: @c:3 iter_range: { - IDENT [56] { - name: @index3 + IDENT [68] { + name: @index1 } } - accu_var: @x0:0 + accu_var: @x:3 accu_init: { - CONSTANT [57] { value: false } + CONSTANT [69] { value: false } } loop_condition: { - CALL [58] { + CALL [70] { function: @not_strictly_false args: { - CALL [59] { + CALL [71] { function: !_ args: { - IDENT [60] { - name: @x0:0 + IDENT [72] { + name: @x:3 } } } @@ -1669,13 +1709,13 @@ CALL [1] { } } loop_step: { - IDENT [61] { - name: @index5 + IDENT [73] { + name: @index9 } } result: { - IDENT [62] { - name: @x0:0 + IDENT [74] { + name: @x:3 } } } @@ -1685,7 +1725,7 @@ CALL [1] { } } } - CONSTANT [63] { value: 4 } + CONSTANT [75] { value: 4 } } } } @@ -1703,95 +1743,135 @@ CALL [1] { CONSTANT [4] { value: 1 } } } - CALL [5] { + LIST [5] { + elements: { + CONSTANT [6] { value: "a" } + } + } + CALL [7] { function: _>_ args: { - IDENT [6] { - name: @c0:0 + IDENT [8] { + name: @c:0 } - CONSTANT [7] { value: 0 } + CONSTANT [9] { value: 0 } } } - CALL [8] { + CALL [10] { function: _||_ args: { - IDENT [9] { - name: @x0:0 + IDENT [11] { + name: @x:0 } - IDENT [10] { - name: @index1 + IDENT [12] { + name: @index2 } } } - LIST [11] { - elements: { - CONSTANT [12] { value: "a" } - } - } CALL [13] { - function: _==_ + function: _>_ args: { IDENT [14] { - name: @c0:1 + name: @c:1 } - CONSTANT [15] { value: "a" } + CONSTANT [15] { value: 0 } } } CALL [16] { function: _||_ args: { IDENT [17] { - name: @x0:1 + name: @x:1 } IDENT [18] { name: @index4 } } } - LIST [19] { + CALL [19] { + function: _==_ + args: { + IDENT [20] { + name: @c:2 + } + CONSTANT [21] { value: "a" } + } + } + CALL [22] { + function: _||_ + args: { + IDENT [23] { + name: @x:2 + } + IDENT [24] { + name: @index6 + } + } + } + CALL [25] { + function: _==_ + args: { + IDENT [26] { + name: @c:3 + } + CONSTANT [27] { value: "a" } + } + } + CALL [28] { + function: _||_ + args: { + IDENT [29] { + name: @x:3 + } + IDENT [30] { + name: @index8 + } + } + } + LIST [31] { elements: { - CONSTANT [20] { value: true } - CONSTANT [21] { value: true } - CONSTANT [22] { value: true } - CONSTANT [23] { value: true } + CONSTANT [32] { value: true } + CONSTANT [33] { value: true } + CONSTANT [34] { value: true } + CONSTANT [35] { value: true } } } } } - CALL [24] { + CALL [36] { function: _==_ args: { - CALL [25] { + CALL [37] { function: _+_ args: { - CALL [26] { + CALL [38] { function: _+_ args: { - CALL [27] { + CALL [39] { function: _+_ args: { - LIST [28] { + LIST [40] { elements: { - COMPREHENSION [29] { - iter_var: @c0:0 + COMPREHENSION [41] { + iter_var: @c:0 iter_range: { - IDENT [30] { + IDENT [42] { name: @index0 } } - accu_var: @x0:0 + accu_var: @x:0 accu_init: { - CONSTANT [31] { value: false } + CONSTANT [43] { value: false } } loop_condition: { - CALL [32] { + CALL [44] { function: @not_strictly_false args: { - CALL [33] { + CALL [45] { function: !_ args: { - IDENT [34] { - name: @x0:0 + IDENT [46] { + name: @x:0 } } } @@ -1799,40 +1879,40 @@ CALL [1] { } } loop_step: { - IDENT [35] { - name: @index2 + IDENT [47] { + name: @index3 } } result: { - IDENT [36] { - name: @x0:0 + IDENT [48] { + name: @x:0 } } } } } - LIST [37] { + LIST [49] { elements: { - COMPREHENSION [38] { - iter_var: @c0:0 + COMPREHENSION [50] { + iter_var: @c:1 iter_range: { - IDENT [39] { + IDENT [51] { name: @index0 } } - accu_var: @x0:0 + accu_var: @x:1 accu_init: { - CONSTANT [40] { value: false } + CONSTANT [52] { value: false } } loop_condition: { - CALL [41] { + CALL [53] { function: @not_strictly_false args: { - CALL [42] { + CALL [54] { function: !_ args: { - IDENT [43] { - name: @x0:0 + IDENT [55] { + name: @x:1 } } } @@ -1840,13 +1920,13 @@ CALL [1] { } } loop_step: { - IDENT [44] { - name: @index2 + IDENT [56] { + name: @index5 } } result: { - IDENT [45] { - name: @x0:0 + IDENT [57] { + name: @x:1 } } } @@ -1854,28 +1934,28 @@ CALL [1] { } } } - LIST [46] { + LIST [58] { elements: { - COMPREHENSION [47] { - iter_var: @c0:1 + COMPREHENSION [59] { + iter_var: @c:2 iter_range: { - IDENT [48] { - name: @index3 + IDENT [60] { + name: @index1 } } - accu_var: @x0:1 + accu_var: @x:2 accu_init: { - CONSTANT [49] { value: false } + CONSTANT [61] { value: false } } loop_condition: { - CALL [50] { + CALL [62] { function: @not_strictly_false args: { - CALL [51] { + CALL [63] { function: !_ args: { - IDENT [52] { - name: @x0:1 + IDENT [64] { + name: @x:2 } } } @@ -1883,13 +1963,13 @@ CALL [1] { } } loop_step: { - IDENT [53] { - name: @index5 + IDENT [65] { + name: @index7 } } result: { - IDENT [54] { - name: @x0:1 + IDENT [66] { + name: @x:2 } } } @@ -1897,28 +1977,28 @@ CALL [1] { } } } - LIST [55] { + LIST [67] { elements: { - COMPREHENSION [56] { - iter_var: @c0:1 + COMPREHENSION [68] { + iter_var: @c:3 iter_range: { - IDENT [57] { - name: @index3 + IDENT [69] { + name: @index1 } } - accu_var: @x0:1 + accu_var: @x:3 accu_init: { - CONSTANT [58] { value: false } + CONSTANT [70] { value: false } } loop_condition: { - CALL [59] { + CALL [71] { function: @not_strictly_false args: { - CALL [60] { + CALL [72] { function: !_ args: { - IDENT [61] { - name: @x0:1 + IDENT [73] { + name: @x:3 } } } @@ -1926,13 +2006,13 @@ CALL [1] { } } loop_step: { - IDENT [62] { - name: @index5 + IDENT [74] { + name: @index9 } } result: { - IDENT [63] { - name: @x0:1 + IDENT [75] { + name: @x:3 } } } @@ -1940,8 +2020,273 @@ CALL [1] { } } } - IDENT [64] { - name: @index6 + IDENT [76] { + name: @index10 + } + } + } + } +} +Test case: MULTIPLE_MACROS_3 +Source: [1].exists(i, i > 0) && [1].exists(j, j > 0) && [1].exists(k, k > 1) && [2].exists(l, l > 1) +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + } + } + CALL [5] { + function: _>_ + args: { + IDENT [6] { + name: @c:0 + } + CONSTANT [7] { value: 0 } + } + } + CALL [8] { + function: _||_ + args: { + IDENT [9] { + name: @x:0 + } + IDENT [10] { + name: @index1 + } + } + } + CALL [11] { + function: _>_ + args: { + IDENT [12] { + name: @c:1 + } + CONSTANT [13] { value: 0 } + } + } + CALL [14] { + function: _||_ + args: { + IDENT [15] { + name: @x:1 + } + IDENT [16] { + name: @index3 + } + } + } + CALL [17] { + function: _>_ + args: { + IDENT [18] { + name: @c:2 + } + CONSTANT [19] { value: 1 } + } + } + CALL [20] { + function: _||_ + args: { + IDENT [21] { + name: @x:2 + } + IDENT [22] { + name: @index5 + } + } + } + LIST [23] { + elements: { + CONSTANT [24] { value: 2 } + } + } + CALL [25] { + function: _>_ + args: { + IDENT [26] { + name: @c:3 + } + CONSTANT [27] { value: 1 } + } + } + CALL [28] { + function: _||_ + args: { + IDENT [29] { + name: @x:3 + } + IDENT [30] { + name: @index8 + } + } + } + } + } + CALL [31] { + function: _&&_ + args: { + CALL [32] { + function: _&&_ + args: { + COMPREHENSION [33] { + iter_var: @c:0 + iter_range: { + IDENT [34] { + name: @index0 + } + } + accu_var: @x:0 + accu_init: { + CONSTANT [35] { value: false } + } + loop_condition: { + CALL [36] { + function: @not_strictly_false + args: { + CALL [37] { + function: !_ + args: { + IDENT [38] { + name: @x:0 + } + } + } + } + } + } + loop_step: { + IDENT [39] { + name: @index2 + } + } + result: { + IDENT [40] { + name: @x:0 + } + } + } + COMPREHENSION [41] { + iter_var: @c:1 + iter_range: { + IDENT [42] { + name: @index0 + } + } + accu_var: @x:1 + accu_init: { + CONSTANT [43] { value: false } + } + loop_condition: { + CALL [44] { + function: @not_strictly_false + args: { + CALL [45] { + function: !_ + args: { + IDENT [46] { + name: @x:1 + } + } + } + } + } + } + loop_step: { + IDENT [47] { + name: @index4 + } + } + result: { + IDENT [48] { + name: @x:1 + } + } + } + } + } + CALL [49] { + function: _&&_ + args: { + COMPREHENSION [50] { + iter_var: @c:2 + iter_range: { + IDENT [51] { + name: @index0 + } + } + accu_var: @x:2 + accu_init: { + CONSTANT [52] { value: false } + } + loop_condition: { + CALL [53] { + function: @not_strictly_false + args: { + CALL [54] { + function: !_ + args: { + IDENT [55] { + name: @x:2 + } + } + } + } + } + } + loop_step: { + IDENT [56] { + name: @index6 + } + } + result: { + IDENT [57] { + name: @x:2 + } + } + } + COMPREHENSION [58] { + iter_var: @c:3 + iter_range: { + IDENT [59] { + name: @index7 + } + } + accu_var: @x:3 + accu_init: { + CONSTANT [60] { value: false } + } + loop_condition: { + CALL [61] { + function: @not_strictly_false + args: { + CALL [62] { + function: !_ + args: { + IDENT [63] { + name: @x:3 + } + } + } + } + } + } + loop_step: { + IDENT [64] { + name: @index9 + } + } + result: { + IDENT [65] { + name: @x:3 + } + } + } + } } } } @@ -1973,7 +2318,7 @@ CALL [1] { function: _+_ args: { IDENT [12] { - name: @c1:0 + name: @c:0 } CONSTANT [13] { value: 1 } } @@ -1989,7 +2334,7 @@ CALL [1] { function: _+_ args: { IDENT [17] { - name: @x1:0 + name: @x:0 } IDENT [18] { name: @index3 @@ -2015,13 +2360,13 @@ CALL [1] { function: _==_ args: { COMPREHENSION [24] { - iter_var: @c0:0 + iter_var: @c:1 iter_range: { IDENT [25] { name: @index0 } } - accu_var: @x0:0 + accu_var: @x:1 accu_init: { LIST [26] { elements: { @@ -2036,18 +2381,18 @@ CALL [1] { function: _+_ args: { IDENT [29] { - name: @x0:0 + name: @x:1 } LIST [30] { elements: { COMPREHENSION [31] { - iter_var: @c1:0 + iter_var: @c:0 iter_range: { IDENT [32] { name: @index0 } } - accu_var: @x1:0 + accu_var: @x:0 accu_init: { LIST [33] { elements: { @@ -2064,7 +2409,7 @@ CALL [1] { } result: { IDENT [36] { - name: @x1:0 + name: @x:0 } } } @@ -2075,7 +2420,7 @@ CALL [1] { } result: { IDENT [37] { - name: @x0:0 + name: @x:1 } } } @@ -2111,17 +2456,17 @@ CALL [1] { function: _==_ args: { IDENT [11] { - name: @c1:0 + name: @c:0 } IDENT [12] { - name: @c0:0 + name: @c:1 } } } LIST [13] { elements: { IDENT [14] { - name: @c1:0 + name: @c:0 } } } @@ -2129,7 +2474,7 @@ CALL [1] { function: _+_ args: { IDENT [16] { - name: @x1:0 + name: @x:0 } IDENT [17] { name: @index3 @@ -2146,7 +2491,7 @@ CALL [1] { name: @index4 } IDENT [21] { - name: @x1:0 + name: @x:0 } } } @@ -2176,13 +2521,13 @@ CALL [1] { function: _==_ args: { COMPREHENSION [30] { - iter_var: @c0:0 + iter_var: @c:1 iter_range: { IDENT [31] { name: @index0 } } - accu_var: @x0:0 + accu_var: @x:1 accu_init: { LIST [32] { elements: { @@ -2197,18 +2542,18 @@ CALL [1] { function: _+_ args: { IDENT [35] { - name: @x0:0 + name: @x:1 } LIST [36] { elements: { COMPREHENSION [37] { - iter_var: @c1:0 + iter_var: @c:0 iter_range: { IDENT [38] { name: @index1 } } - accu_var: @x1:0 + accu_var: @x:0 accu_init: { LIST [39] { elements: { @@ -2225,7 +2570,7 @@ CALL [1] { } result: { IDENT [42] { - name: @x1:0 + name: @x:0 } } } @@ -2236,7 +2581,7 @@ CALL [1] { } result: { IDENT [43] { - name: @x0:0 + name: @x:1 } } } @@ -2436,7 +2781,7 @@ CALL [1] { function: _+_ args: { IDENT [15] { - name: @x1:0 + name: @x:0 } IDENT [16] { name: @index3 @@ -2459,13 +2804,13 @@ CALL [1] { function: _==_ args: { COMPREHENSION [21] { - iter_var: @c0:0 + iter_var: @c:1 iter_range: { IDENT [22] { name: @index0 } } - accu_var: @x0:0 + accu_var: @x:1 accu_init: { LIST [23] { elements: { @@ -2480,18 +2825,18 @@ CALL [1] { function: _+_ args: { IDENT [26] { - name: @x0:0 + name: @x:1 } LIST [27] { elements: { COMPREHENSION [28] { - iter_var: @c1:0 + iter_var: @c:0 iter_range: { IDENT [29] { name: @index0 } } - accu_var: @x1:0 + accu_var: @x:0 accu_init: { LIST [30] { elements: { @@ -2508,7 +2853,7 @@ CALL [1] { } result: { IDENT [33] { - name: @x1:0 + name: @x:0 } } } @@ -2519,7 +2864,7 @@ CALL [1] { } result: { IDENT [34] { - name: @x0:0 + name: @x:1 } } } @@ -2579,7 +2924,7 @@ CALL [1] { function: _-_ args: { IDENT [16] { - name: @c0:0 + name: @c:0 } CONSTANT [17] { value: 1 } } @@ -2597,7 +2942,7 @@ CALL [1] { function: _||_ args: { IDENT [22] { - name: @x0:0 + name: @x:0 } IDENT [23] { name: @index5 @@ -2610,13 +2955,13 @@ CALL [1] { function: _||_ args: { COMPREHENSION [25] { - iter_var: @c0:0 + iter_var: @c:0 iter_range: { IDENT [26] { name: @index3 } } - accu_var: @x0:0 + accu_var: @x:0 accu_init: { CONSTANT [27] { value: false } } @@ -2628,7 +2973,7 @@ CALL [1] { function: !_ args: { IDENT [30] { - name: @x0:0 + name: @x:0 } } } @@ -2642,7 +2987,7 @@ CALL [1] { } result: { IDENT [32] { - name: @x0:0 + name: @x:0 } } } @@ -2665,10 +3010,10 @@ CALL [1] { function: _+_ args: { IDENT [4] { - name: @c1:0 + name: @c:0 } IDENT [5] { - name: @c1:0 + name: @c:0 } } } @@ -2676,10 +3021,10 @@ CALL [1] { function: _+_ args: { IDENT [7] { - name: @c0:0 + name: @c:1 } IDENT [8] { - name: @c0:0 + name: @c:1 } } } @@ -2710,7 +3055,7 @@ CALL [1] { function: _+_ args: { IDENT [18] { - name: @x1:0 + name: @x:0 } IDENT [19] { name: @index4 @@ -2738,7 +3083,7 @@ CALL [1] { function: _+_ args: { IDENT [26] { - name: @x0:0 + name: @x:1 } IDENT [27] { name: @index7 @@ -2748,16 +3093,16 @@ CALL [1] { } } COMPREHENSION [28] { - iter_var: @c0:0 + iter_var: @c:1 iter_range: { COMPREHENSION [29] { - iter_var: @c1:0 + iter_var: @c:0 iter_range: { IDENT [30] { name: @index2 } } - accu_var: @x1:0 + accu_var: @x:0 accu_init: { LIST [31] { elements: { @@ -2774,12 +3119,12 @@ CALL [1] { } result: { IDENT [34] { - name: @x1:0 + name: @x:0 } } } } - accu_var: @x0:0 + accu_var: @x:1 accu_init: { LIST [35] { elements: { @@ -2796,7 +3141,7 @@ CALL [1] { } result: { IDENT [38] { - name: @x0:0 + name: @x:1 } } } @@ -3965,4 +4310,4 @@ CALL [1] { } } } -} +} \ No newline at end of file diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_2.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_2.baseline index 7a5fa722d..1d3045ff6 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_2.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_2.baseline @@ -1252,89 +1252,123 @@ CALL [1] { args: { LIST [2] { elements: { - CALL [3] { + LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + } + } + LIST [5] { + elements: { + CONSTANT [6] { value: 2 } + } + } + CALL [7] { function: _||_ args: { - IDENT [4] { - name: @x0:0 + IDENT [8] { + name: @x:0 } - CALL [5] { + CALL [9] { function: _>_ args: { - IDENT [6] { - name: @c0:0 + IDENT [10] { + name: @c:0 } - CONSTANT [7] { value: 0 } + CONSTANT [11] { value: 0 } } } } } - CALL [8] { + CALL [12] { function: _||_ args: { - IDENT [9] { - name: @x0:0 + IDENT [13] { + name: @x:1 } - CALL [10] { + CALL [14] { function: _>_ args: { - IDENT [11] { - name: @c0:0 + IDENT [15] { + name: @c:1 } - CONSTANT [12] { value: 1 } + CONSTANT [16] { value: 0 } } } } } - LIST [13] { - elements: { - CONSTANT [14] { value: 1 } + CALL [17] { + function: _||_ + args: { + IDENT [18] { + name: @x:2 + } + CALL [19] { + function: _>_ + args: { + IDENT [20] { + name: @c:2 + } + CONSTANT [21] { value: 1 } + } + } } } - LIST [15] { - elements: { - CONSTANT [16] { value: 2 } + CALL [22] { + function: _||_ + args: { + IDENT [23] { + name: @x:3 + } + CALL [24] { + function: _>_ + args: { + IDENT [25] { + name: @c:3 + } + CONSTANT [26] { value: 1 } + } + } } } } } - CALL [17] { + CALL [27] { function: _==_ args: { - CALL [18] { + CALL [28] { function: _+_ args: { - CALL [19] { + CALL [29] { function: _+_ args: { - CALL [20] { + CALL [30] { function: _+_ args: { - CALL [21] { + CALL [31] { function: size args: { - LIST [22] { + LIST [32] { elements: { - COMPREHENSION [23] { - iter_var: @c0:0 + COMPREHENSION [33] { + iter_var: @c:0 iter_range: { - IDENT [24] { - name: @index2 + IDENT [34] { + name: @index0 } } - accu_var: @x0:0 + accu_var: @x:0 accu_init: { - CONSTANT [25] { value: false } + CONSTANT [35] { value: false } } loop_condition: { - CALL [26] { + CALL [36] { function: @not_strictly_false args: { - CALL [27] { + CALL [37] { function: !_ args: { - IDENT [28] { - name: @x0:0 + IDENT [38] { + name: @x:0 } } } @@ -1342,13 +1376,13 @@ CALL [1] { } } loop_step: { - IDENT [29] { - name: @index0 + IDENT [39] { + name: @index2 } } result: { - IDENT [30] { - name: @x0:0 + IDENT [40] { + name: @x:0 } } } @@ -1356,31 +1390,31 @@ CALL [1] { } } } - CALL [31] { + CALL [41] { function: size args: { - LIST [32] { + LIST [42] { elements: { - COMPREHENSION [33] { - iter_var: @c0:0 + COMPREHENSION [43] { + iter_var: @c:1 iter_range: { - IDENT [34] { - name: @index2 + IDENT [44] { + name: @index0 } } - accu_var: @x0:0 + accu_var: @x:1 accu_init: { - CONSTANT [35] { value: false } + CONSTANT [45] { value: false } } loop_condition: { - CALL [36] { + CALL [46] { function: @not_strictly_false args: { - CALL [37] { + CALL [47] { function: !_ args: { - IDENT [38] { - name: @x0:0 + IDENT [48] { + name: @x:1 } } } @@ -1388,13 +1422,13 @@ CALL [1] { } } loop_step: { - IDENT [39] { - name: @index0 + IDENT [49] { + name: @index3 } } result: { - IDENT [40] { - name: @x0:0 + IDENT [50] { + name: @x:1 } } } @@ -1404,31 +1438,31 @@ CALL [1] { } } } - CALL [41] { + CALL [51] { function: size args: { - LIST [42] { + LIST [52] { elements: { - COMPREHENSION [43] { - iter_var: @c0:0 + COMPREHENSION [53] { + iter_var: @c:2 iter_range: { - IDENT [44] { - name: @index3 + IDENT [54] { + name: @index1 } } - accu_var: @x0:0 + accu_var: @x:2 accu_init: { - CONSTANT [45] { value: false } + CONSTANT [55] { value: false } } loop_condition: { - CALL [46] { + CALL [56] { function: @not_strictly_false args: { - CALL [47] { + CALL [57] { function: !_ args: { - IDENT [48] { - name: @x0:0 + IDENT [58] { + name: @x:2 } } } @@ -1436,13 +1470,13 @@ CALL [1] { } } loop_step: { - IDENT [49] { - name: @index1 + IDENT [59] { + name: @index4 } } result: { - IDENT [50] { - name: @x0:0 + IDENT [60] { + name: @x:2 } } } @@ -1452,31 +1486,31 @@ CALL [1] { } } } - CALL [51] { + CALL [61] { function: size args: { - LIST [52] { + LIST [62] { elements: { - COMPREHENSION [53] { - iter_var: @c0:0 + COMPREHENSION [63] { + iter_var: @c:3 iter_range: { - IDENT [54] { - name: @index3 + IDENT [64] { + name: @index1 } } - accu_var: @x0:0 + accu_var: @x:3 accu_init: { - CONSTANT [55] { value: false } + CONSTANT [65] { value: false } } loop_condition: { - CALL [56] { + CALL [66] { function: @not_strictly_false args: { - CALL [57] { + CALL [67] { function: !_ args: { - IDENT [58] { - name: @x0:0 + IDENT [68] { + name: @x:3 } } } @@ -1484,13 +1518,13 @@ CALL [1] { } } loop_step: { - IDENT [59] { - name: @index1 + IDENT [69] { + name: @index5 } } result: { - IDENT [60] { - name: @x0:0 + IDENT [70] { + name: @x:3 } } } @@ -1500,7 +1534,7 @@ CALL [1] { } } } - CONSTANT [61] { value: 4 } + CONSTANT [71] { value: 4 } } } } @@ -1513,94 +1547,128 @@ CALL [1] { args: { LIST [2] { elements: { - CALL [3] { + LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + } + } + LIST [5] { + elements: { + CONSTANT [6] { value: "a" } + } + } + CALL [7] { function: _||_ args: { - IDENT [4] { - name: @x0:0 + IDENT [8] { + name: @x:0 } - CALL [5] { + CALL [9] { function: _>_ args: { - IDENT [6] { - name: @c0:0 + IDENT [10] { + name: @c:0 } - CONSTANT [7] { value: 0 } + CONSTANT [11] { value: 0 } } } } } - CALL [8] { + CALL [12] { function: _||_ args: { - IDENT [9] { - name: @x0:1 + IDENT [13] { + name: @x:1 } - CALL [10] { - function: _==_ + CALL [14] { + function: _>_ args: { - IDENT [11] { - name: @c0:1 + IDENT [15] { + name: @c:1 } - CONSTANT [12] { value: "a" } + CONSTANT [16] { value: 0 } } } } } - LIST [13] { - elements: { - CONSTANT [14] { value: 1 } + CALL [17] { + function: _||_ + args: { + IDENT [18] { + name: @x:2 + } + CALL [19] { + function: _==_ + args: { + IDENT [20] { + name: @c:2 + } + CONSTANT [21] { value: "a" } + } + } } } - LIST [15] { - elements: { - CONSTANT [16] { value: "a" } + CALL [22] { + function: _||_ + args: { + IDENT [23] { + name: @x:3 + } + CALL [24] { + function: _==_ + args: { + IDENT [25] { + name: @c:3 + } + CONSTANT [26] { value: "a" } + } + } } } - LIST [17] { + LIST [27] { elements: { - CONSTANT [18] { value: true } - CONSTANT [19] { value: true } - CONSTANT [20] { value: true } - CONSTANT [21] { value: true } + CONSTANT [28] { value: true } + CONSTANT [29] { value: true } + CONSTANT [30] { value: true } + CONSTANT [31] { value: true } } } } } - CALL [22] { + CALL [32] { function: _==_ args: { - CALL [23] { + CALL [33] { function: _+_ args: { - CALL [24] { + CALL [34] { function: _+_ args: { - CALL [25] { + CALL [35] { function: _+_ args: { - LIST [26] { + LIST [36] { elements: { - COMPREHENSION [27] { - iter_var: @c0:0 + COMPREHENSION [37] { + iter_var: @c:0 iter_range: { - IDENT [28] { - name: @index2 + IDENT [38] { + name: @index0 } } - accu_var: @x0:0 + accu_var: @x:0 accu_init: { - CONSTANT [29] { value: false } + CONSTANT [39] { value: false } } loop_condition: { - CALL [30] { + CALL [40] { function: @not_strictly_false args: { - CALL [31] { + CALL [41] { function: !_ args: { - IDENT [32] { - name: @x0:0 + IDENT [42] { + name: @x:0 } } } @@ -1608,40 +1676,40 @@ CALL [1] { } } loop_step: { - IDENT [33] { - name: @index0 + IDENT [43] { + name: @index2 } } result: { - IDENT [34] { - name: @x0:0 + IDENT [44] { + name: @x:0 } } } } } - LIST [35] { + LIST [45] { elements: { - COMPREHENSION [36] { - iter_var: @c0:0 + COMPREHENSION [46] { + iter_var: @c:1 iter_range: { - IDENT [37] { - name: @index2 + IDENT [47] { + name: @index0 } } - accu_var: @x0:0 + accu_var: @x:1 accu_init: { - CONSTANT [38] { value: false } + CONSTANT [48] { value: false } } loop_condition: { - CALL [39] { + CALL [49] { function: @not_strictly_false args: { - CALL [40] { + CALL [50] { function: !_ args: { - IDENT [41] { - name: @x0:0 + IDENT [51] { + name: @x:1 } } } @@ -1649,13 +1717,13 @@ CALL [1] { } } loop_step: { - IDENT [42] { - name: @index0 + IDENT [52] { + name: @index3 } } result: { - IDENT [43] { - name: @x0:0 + IDENT [53] { + name: @x:1 } } } @@ -1663,28 +1731,28 @@ CALL [1] { } } } - LIST [44] { + LIST [54] { elements: { - COMPREHENSION [45] { - iter_var: @c0:1 + COMPREHENSION [55] { + iter_var: @c:2 iter_range: { - IDENT [46] { - name: @index3 + IDENT [56] { + name: @index1 } } - accu_var: @x0:1 + accu_var: @x:2 accu_init: { - CONSTANT [47] { value: false } + CONSTANT [57] { value: false } } loop_condition: { - CALL [48] { + CALL [58] { function: @not_strictly_false args: { - CALL [49] { + CALL [59] { function: !_ args: { - IDENT [50] { - name: @x0:1 + IDENT [60] { + name: @x:2 } } } @@ -1692,13 +1760,13 @@ CALL [1] { } } loop_step: { - IDENT [51] { - name: @index1 + IDENT [61] { + name: @index4 } } result: { - IDENT [52] { - name: @x0:1 + IDENT [62] { + name: @x:2 } } } @@ -1706,28 +1774,28 @@ CALL [1] { } } } - LIST [53] { + LIST [63] { elements: { - COMPREHENSION [54] { - iter_var: @c0:1 + COMPREHENSION [64] { + iter_var: @c:3 iter_range: { - IDENT [55] { - name: @index3 + IDENT [65] { + name: @index1 } } - accu_var: @x0:1 + accu_var: @x:3 accu_init: { - CONSTANT [56] { value: false } + CONSTANT [66] { value: false } } loop_condition: { - CALL [57] { + CALL [67] { function: @not_strictly_false args: { - CALL [58] { + CALL [68] { function: !_ args: { - IDENT [59] { - name: @x0:1 + IDENT [69] { + name: @x:3 } } } @@ -1735,13 +1803,13 @@ CALL [1] { } } loop_step: { - IDENT [60] { - name: @index1 + IDENT [70] { + name: @index5 } } result: { - IDENT [61] { - name: @x0:1 + IDENT [71] { + name: @x:3 } } } @@ -1749,8 +1817,261 @@ CALL [1] { } } } - IDENT [62] { - name: @index4 + IDENT [72] { + name: @index6 + } + } + } + } +} +Test case: MULTIPLE_MACROS_3 +Source: [1].exists(i, i > 0) && [1].exists(j, j > 0) && [1].exists(k, k > 1) && [2].exists(l, l > 1) +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + } + } + CALL [5] { + function: _||_ + args: { + IDENT [6] { + name: @x:0 + } + CALL [7] { + function: _>_ + args: { + IDENT [8] { + name: @c:0 + } + CONSTANT [9] { value: 0 } + } + } + } + } + CALL [10] { + function: _||_ + args: { + IDENT [11] { + name: @x:1 + } + CALL [12] { + function: _>_ + args: { + IDENT [13] { + name: @c:1 + } + CONSTANT [14] { value: 0 } + } + } + } + } + CALL [15] { + function: _||_ + args: { + IDENT [16] { + name: @x:2 + } + CALL [17] { + function: _>_ + args: { + IDENT [18] { + name: @c:2 + } + CONSTANT [19] { value: 1 } + } + } + } + } + CALL [20] { + function: _||_ + args: { + IDENT [21] { + name: @x:3 + } + CALL [22] { + function: _>_ + args: { + IDENT [23] { + name: @c:3 + } + CONSTANT [24] { value: 1 } + } + } + } + } + LIST [25] { + elements: { + CONSTANT [26] { value: 2 } + } + } + } + } + CALL [27] { + function: _&&_ + args: { + CALL [28] { + function: _&&_ + args: { + COMPREHENSION [29] { + iter_var: @c:0 + iter_range: { + IDENT [30] { + name: @index0 + } + } + accu_var: @x:0 + accu_init: { + CONSTANT [31] { value: false } + } + loop_condition: { + CALL [32] { + function: @not_strictly_false + args: { + CALL [33] { + function: !_ + args: { + IDENT [34] { + name: @x:0 + } + } + } + } + } + } + loop_step: { + IDENT [35] { + name: @index1 + } + } + result: { + IDENT [36] { + name: @x:0 + } + } + } + COMPREHENSION [37] { + iter_var: @c:1 + iter_range: { + IDENT [38] { + name: @index0 + } + } + accu_var: @x:1 + accu_init: { + CONSTANT [39] { value: false } + } + loop_condition: { + CALL [40] { + function: @not_strictly_false + args: { + CALL [41] { + function: !_ + args: { + IDENT [42] { + name: @x:1 + } + } + } + } + } + } + loop_step: { + IDENT [43] { + name: @index2 + } + } + result: { + IDENT [44] { + name: @x:1 + } + } + } + } + } + CALL [45] { + function: _&&_ + args: { + COMPREHENSION [46] { + iter_var: @c:2 + iter_range: { + IDENT [47] { + name: @index0 + } + } + accu_var: @x:2 + accu_init: { + CONSTANT [48] { value: false } + } + loop_condition: { + CALL [49] { + function: @not_strictly_false + args: { + CALL [50] { + function: !_ + args: { + IDENT [51] { + name: @x:2 + } + } + } + } + } + } + loop_step: { + IDENT [52] { + name: @index3 + } + } + result: { + IDENT [53] { + name: @x:2 + } + } + } + COMPREHENSION [54] { + iter_var: @c:3 + iter_range: { + IDENT [55] { + name: @index5 + } + } + accu_var: @x:3 + accu_init: { + CONSTANT [56] { value: false } + } + loop_condition: { + CALL [57] { + function: @not_strictly_false + args: { + CALL [58] { + function: !_ + args: { + IDENT [59] { + name: @x:3 + } + } + } + } + } + } + loop_step: { + IDENT [60] { + name: @index4 + } + } + result: { + IDENT [61] { + name: @x:3 + } + } + } + } } } } @@ -1784,7 +2105,7 @@ CALL [1] { function: _+_ args: { IDENT [13] { - name: @c1:0 + name: @c:0 } CONSTANT [14] { value: 1 } } @@ -1792,13 +2113,13 @@ CALL [1] { } } COMPREHENSION [15] { - iter_var: @c1:0 + iter_var: @c:0 iter_range: { IDENT [16] { name: @index0 } } - accu_var: @x1:0 + accu_var: @x:0 accu_init: { LIST [17] { elements: { @@ -1813,7 +2134,7 @@ CALL [1] { function: _+_ args: { IDENT [20] { - name: @x1:0 + name: @x:0 } IDENT [21] { name: @index2 @@ -1823,7 +2144,7 @@ CALL [1] { } result: { IDENT [22] { - name: @x1:0 + name: @x:0 } } } @@ -1831,7 +2152,7 @@ CALL [1] { function: _+_ args: { IDENT [24] { - name: @x0:0 + name: @x:1 } LIST [25] { elements: { @@ -1843,13 +2164,13 @@ CALL [1] { } } COMPREHENSION [27] { - iter_var: @c0:0 + iter_var: @c:1 iter_range: { IDENT [28] { name: @index0 } } - accu_var: @x0:0 + accu_var: @x:1 accu_init: { LIST [29] { elements: { @@ -1866,7 +2187,7 @@ CALL [1] { } result: { IDENT [32] { - name: @x0:0 + name: @x:1 } } } @@ -1907,12 +2228,12 @@ CALL [1] { function: _+_ args: { IDENT [4] { - name: @x1:0 + name: @x:0 } LIST [5] { elements: { IDENT [6] { - name: @c1:0 + name: @c:0 } } } @@ -1925,10 +2246,10 @@ CALL [1] { function: _==_ args: { IDENT [9] { - name: @c1:0 + name: @c:0 } IDENT [10] { - name: @c0:0 + name: @c:1 } } } @@ -1936,12 +2257,12 @@ CALL [1] { name: @index0 } IDENT [12] { - name: @x1:0 + name: @x:0 } } } COMPREHENSION [13] { - iter_var: @c1:0 + iter_var: @c:0 iter_range: { LIST [14] { elements: { @@ -1951,7 +2272,7 @@ CALL [1] { } } } - accu_var: @x1:0 + accu_var: @x:0 accu_init: { LIST [18] { elements: { @@ -1968,7 +2289,7 @@ CALL [1] { } result: { IDENT [21] { - name: @x1:0 + name: @x:0 } } } @@ -1976,7 +2297,7 @@ CALL [1] { function: _+_ args: { IDENT [23] { - name: @x0:0 + name: @x:1 } LIST [24] { elements: { @@ -1988,7 +2309,7 @@ CALL [1] { } } COMPREHENSION [26] { - iter_var: @c0:0 + iter_var: @c:1 iter_range: { LIST [27] { elements: { @@ -1997,7 +2318,7 @@ CALL [1] { } } } - accu_var: @x0:0 + accu_var: @x:1 accu_init: { LIST [30] { elements: { @@ -2014,7 +2335,7 @@ CALL [1] { } result: { IDENT [33] { - name: @x0:0 + name: @x:1 } } } @@ -2228,13 +2549,13 @@ CALL [1] { } } COMPREHENSION [17] { - iter_var: @c1:0 + iter_var: @c:0 iter_range: { IDENT [18] { name: @index1 } } - accu_var: @x1:0 + accu_var: @x:0 accu_init: { LIST [19] { elements: { @@ -2249,7 +2570,7 @@ CALL [1] { function: _+_ args: { IDENT [22] { - name: @x1:0 + name: @x:0 } IDENT [23] { name: @index2 @@ -2259,7 +2580,7 @@ CALL [1] { } result: { IDENT [24] { - name: @x1:0 + name: @x:0 } } } @@ -2267,7 +2588,7 @@ CALL [1] { function: _+_ args: { IDENT [26] { - name: @x0:0 + name: @x:1 } LIST [27] { elements: { @@ -2279,13 +2600,13 @@ CALL [1] { } } COMPREHENSION [29] { - iter_var: @c0:0 + iter_var: @c:1 iter_range: { IDENT [30] { name: @index1 } } - accu_var: @x0:0 + accu_var: @x:1 accu_init: { LIST [31] { elements: { @@ -2302,7 +2623,7 @@ CALL [1] { } result: { IDENT [34] { - name: @x0:0 + name: @x:1 } } } @@ -2376,7 +2697,7 @@ CALL [1] { function: _-_ args: { IDENT [16] { - name: @c0:0 + name: @c:0 } CONSTANT [17] { value: 1 } } @@ -2395,7 +2716,7 @@ CALL [1] { function: _||_ args: { IDENT [22] { - name: @x0:0 + name: @x:0 } IDENT [23] { name: @index2 @@ -2408,13 +2729,13 @@ CALL [1] { function: _||_ args: { COMPREHENSION [25] { - iter_var: @c0:0 + iter_var: @c:0 iter_range: { IDENT [26] { name: @index3 } } - accu_var: @x0:0 + accu_var: @x:0 accu_init: { CONSTANT [27] { value: false } } @@ -2426,7 +2747,7 @@ CALL [1] { function: !_ args: { IDENT [30] { - name: @x0:0 + name: @x:0 } } } @@ -2440,7 +2761,7 @@ CALL [1] { } result: { IDENT [32] { - name: @x0:0 + name: @x:0 } } } @@ -2463,10 +2784,10 @@ CALL [1] { function: _+_ args: { IDENT [4] { - name: @c1:0 + name: @c:0 } IDENT [5] { - name: @c1:0 + name: @c:0 } } } @@ -2474,10 +2795,10 @@ CALL [1] { function: _+_ args: { IDENT [7] { - name: @c0:0 + name: @c:1 } IDENT [8] { - name: @c0:0 + name: @c:1 } } } @@ -2496,7 +2817,7 @@ CALL [1] { } } COMPREHENSION [13] { - iter_var: @c1:0 + iter_var: @c:0 iter_range: { LIST [14] { elements: { @@ -2505,7 +2826,7 @@ CALL [1] { } } } - accu_var: @x1:0 + accu_var: @x:0 accu_init: { LIST [17] { elements: { @@ -2520,7 +2841,7 @@ CALL [1] { function: _+_ args: { IDENT [20] { - name: @x1:0 + name: @x:0 } IDENT [21] { name: @index2 @@ -2530,7 +2851,7 @@ CALL [1] { } result: { IDENT [22] { - name: @x1:0 + name: @x:0 } } } @@ -2551,13 +2872,13 @@ CALL [1] { } } COMPREHENSION [27] { - iter_var: @c0:0 + iter_var: @c:1 iter_range: { IDENT [28] { name: @index3 } } - accu_var: @x0:0 + accu_var: @x:1 accu_init: { LIST [29] { elements: { @@ -2572,7 +2893,7 @@ CALL [1] { function: _+_ args: { IDENT [32] { - name: @x0:0 + name: @x:1 } IDENT [33] { name: @index4 @@ -2582,7 +2903,7 @@ CALL [1] { } result: { IDENT [34] { - name: @x0:0 + name: @x:1 } } } @@ -3613,4 +3934,4 @@ CALL [1] { } } } -} +} \ No newline at end of file diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_3.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_3.baseline index a87fd8f5a..f9c1f2a42 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_3.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_3.baseline @@ -1199,28 +1199,36 @@ CALL [1] { args: { LIST [2] { elements: { - COMPREHENSION [3] { - iter_var: @c0:0 + LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + } + } + LIST [5] { + elements: { + CONSTANT [6] { value: 2 } + } + } + COMPREHENSION [7] { + iter_var: @c:0 iter_range: { - LIST [4] { - elements: { - CONSTANT [5] { value: 1 } - } + IDENT [8] { + name: @index0 } } - accu_var: @x0:0 + accu_var: @x:0 accu_init: { - CONSTANT [6] { value: false } + CONSTANT [9] { value: false } } loop_condition: { - CALL [7] { + CALL [10] { function: @not_strictly_false args: { - CALL [8] { + CALL [11] { function: !_ args: { - IDENT [9] { - name: @x0:0 + IDENT [12] { + name: @x:0 } } } @@ -1228,52 +1236,50 @@ CALL [1] { } } loop_step: { - CALL [10] { + CALL [13] { function: _||_ args: { - IDENT [11] { - name: @x0:0 + IDENT [14] { + name: @x:0 } - CALL [12] { + CALL [15] { function: _>_ args: { - IDENT [13] { - name: @c0:0 + IDENT [16] { + name: @c:0 } - CONSTANT [14] { value: 0 } + CONSTANT [17] { value: 0 } } } } } } result: { - IDENT [15] { - name: @x0:0 + IDENT [18] { + name: @x:0 } } } - COMPREHENSION [16] { - iter_var: @c0:0 + COMPREHENSION [19] { + iter_var: @c:1 iter_range: { - LIST [17] { - elements: { - CONSTANT [18] { value: 2 } - } + IDENT [20] { + name: @index0 } } - accu_var: @x0:0 + accu_var: @x:1 accu_init: { - CONSTANT [19] { value: false } + CONSTANT [21] { value: false } } loop_condition: { - CALL [20] { + CALL [22] { function: @not_strictly_false args: { - CALL [21] { + CALL [23] { function: !_ args: { - IDENT [22] { - name: @x0:0 + IDENT [24] { + name: @x:1 } } } @@ -1281,90 +1287,210 @@ CALL [1] { } } loop_step: { - CALL [23] { + CALL [25] { function: _||_ args: { - IDENT [24] { - name: @x0:0 + IDENT [26] { + name: @x:1 } - CALL [25] { + CALL [27] { function: _>_ args: { - IDENT [26] { - name: @c0:0 + IDENT [28] { + name: @c:1 } - CONSTANT [27] { value: 1 } + CONSTANT [29] { value: 0 } } } } } } result: { - IDENT [28] { - name: @x0:0 + IDENT [30] { + name: @x:1 } } } - CALL [29] { - function: size + CALL [31] { + function: _+_ args: { - LIST [30] { - elements: { - IDENT [31] { - name: @index0 + CALL [32] { + function: size + args: { + LIST [33] { + elements: { + IDENT [34] { + name: @index2 + } + } + } + } + } + CALL [35] { + function: size + args: { + LIST [36] { + elements: { + IDENT [37] { + name: @index3 + } + } } } } } } - CALL [32] { - function: size - args: { - LIST [33] { - elements: { - IDENT [34] { - name: @index1 + COMPREHENSION [38] { + iter_var: @c:2 + iter_range: { + IDENT [39] { + name: @index1 + } + } + accu_var: @x:2 + accu_init: { + CONSTANT [40] { value: false } + } + loop_condition: { + CALL [41] { + function: @not_strictly_false + args: { + CALL [42] { + function: !_ + args: { + IDENT [43] { + name: @x:2 + } + } } } } } + loop_step: { + CALL [44] { + function: _||_ + args: { + IDENT [45] { + name: @x:2 + } + CALL [46] { + function: _>_ + args: { + IDENT [47] { + name: @c:2 + } + CONSTANT [48] { value: 1 } + } + } + } + } + } + result: { + IDENT [49] { + name: @x:2 + } + } } - CALL [35] { + CALL [50] { function: _+_ args: { - CALL [36] { - function: _+_ + IDENT [51] { + name: @index4 + } + CALL [52] { + function: size args: { - CALL [37] { - function: _+_ - args: { - IDENT [38] { - name: @index2 + LIST [53] { + elements: { + IDENT [54] { + name: @index5 } - IDENT [39] { - name: @index2 + } + } + } + } + } + } + COMPREHENSION [55] { + iter_var: @c:3 + iter_range: { + IDENT [56] { + name: @index1 + } + } + accu_var: @x:3 + accu_init: { + CONSTANT [57] { value: false } + } + loop_condition: { + CALL [58] { + function: @not_strictly_false + args: { + CALL [59] { + function: !_ + args: { + IDENT [60] { + name: @x:3 } } } - IDENT [40] { - name: @index3 + } + } + } + loop_step: { + CALL [61] { + function: _||_ + args: { + IDENT [62] { + name: @x:3 + } + CALL [63] { + function: _>_ + args: { + IDENT [64] { + name: @c:3 + } + CONSTANT [65] { value: 1 } + } } } } - IDENT [41] { - name: @index3 + } + result: { + IDENT [66] { + name: @x:3 + } + } + } + CALL [67] { + function: _+_ + args: { + IDENT [68] { + name: @index6 + } + CALL [69] { + function: size + args: { + LIST [70] { + elements: { + IDENT [71] { + name: @index7 + } + } + } + } } } } } } - CALL [42] { + CALL [72] { function: _==_ args: { - IDENT [43] { - name: @index4 + IDENT [73] { + name: @index8 } - CONSTANT [44] { value: 4 } + CONSTANT [74] { value: 4 } } } } @@ -1377,28 +1503,87 @@ CALL [1] { args: { LIST [2] { elements: { - COMPREHENSION [3] { - iter_var: @c0:0 + LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + } + } + LIST [5] { + elements: { + CONSTANT [6] { value: "a" } + } + } + COMPREHENSION [7] { + iter_var: @c:0 iter_range: { - LIST [4] { - elements: { - CONSTANT [5] { value: 1 } + IDENT [8] { + name: @index0 + } + } + accu_var: @x:0 + accu_init: { + CONSTANT [9] { value: false } + } + loop_condition: { + CALL [10] { + function: @not_strictly_false + args: { + CALL [11] { + function: !_ + args: { + IDENT [12] { + name: @x:0 + } + } + } + } + } + } + loop_step: { + CALL [13] { + function: _||_ + args: { + IDENT [14] { + name: @x:0 + } + CALL [15] { + function: _>_ + args: { + IDENT [16] { + name: @c:0 + } + CONSTANT [17] { value: 0 } + } + } } } } - accu_var: @x0:0 + result: { + IDENT [18] { + name: @x:0 + } + } + } + COMPREHENSION [19] { + iter_var: @c:1 + iter_range: { + IDENT [20] { + name: @index0 + } + } + accu_var: @x:1 accu_init: { - CONSTANT [6] { value: false } + CONSTANT [21] { value: false } } loop_condition: { - CALL [7] { + CALL [22] { function: @not_strictly_false args: { - CALL [8] { + CALL [23] { function: !_ args: { - IDENT [9] { - name: @x0:0 + IDENT [24] { + name: @x:1 } } } @@ -1406,40 +1591,267 @@ CALL [1] { } } loop_step: { - CALL [10] { + CALL [25] { function: _||_ args: { - IDENT [11] { - name: @x0:0 + IDENT [26] { + name: @x:1 } - CALL [12] { + CALL [27] { function: _>_ args: { - IDENT [13] { - name: @c0:0 + IDENT [28] { + name: @c:1 } - CONSTANT [14] { value: 0 } + CONSTANT [29] { value: 0 } } } } } } result: { - IDENT [15] { - name: @x0:0 + IDENT [30] { + name: @x:1 } } } - COMPREHENSION [16] { - iter_var: @c0:1 + COMPREHENSION [31] { + iter_var: @c:2 iter_range: { - LIST [17] { + IDENT [32] { + name: @index1 + } + } + accu_var: @x:2 + accu_init: { + CONSTANT [33] { value: false } + } + loop_condition: { + CALL [34] { + function: @not_strictly_false + args: { + CALL [35] { + function: !_ + args: { + IDENT [36] { + name: @x:2 + } + } + } + } + } + } + loop_step: { + CALL [37] { + function: _||_ + args: { + IDENT [38] { + name: @x:2 + } + CALL [39] { + function: _==_ + args: { + IDENT [40] { + name: @c:2 + } + CONSTANT [41] { value: "a" } + } + } + } + } + } + result: { + IDENT [42] { + name: @x:2 + } + } + } + CALL [43] { + function: _+_ + args: { + CALL [44] { + function: _+_ + args: { + LIST [45] { + elements: { + IDENT [46] { + name: @index2 + } + } + } + LIST [47] { + elements: { + IDENT [48] { + name: @index3 + } + } + } + } + } + LIST [49] { elements: { - CONSTANT [18] { value: "a" } + IDENT [50] { + name: @index4 + } + } + } + } + } + COMPREHENSION [51] { + iter_var: @c:3 + iter_range: { + IDENT [52] { + name: @index1 + } + } + accu_var: @x:3 + accu_init: { + CONSTANT [53] { value: false } + } + loop_condition: { + CALL [54] { + function: @not_strictly_false + args: { + CALL [55] { + function: !_ + args: { + IDENT [56] { + name: @x:3 + } + } + } + } + } + } + loop_step: { + CALL [57] { + function: _||_ + args: { + IDENT [58] { + name: @x:3 + } + CALL [59] { + function: _==_ + args: { + IDENT [60] { + name: @c:3 + } + CONSTANT [61] { value: "a" } + } + } + } + } + } + result: { + IDENT [62] { + name: @x:3 + } + } + } + } + } + CALL [63] { + function: _==_ + args: { + CALL [64] { + function: _+_ + args: { + IDENT [65] { + name: @index5 + } + LIST [66] { + elements: { + IDENT [67] { + name: @index6 + } + } + } + } + } + LIST [68] { + elements: { + CONSTANT [69] { value: true } + CONSTANT [70] { value: true } + CONSTANT [71] { value: true } + CONSTANT [72] { value: true } + } + } + } + } + } +} +Test case: MULTIPLE_MACROS_3 +Source: [1].exists(i, i > 0) && [1].exists(j, j > 0) && [1].exists(k, k > 1) && [2].exists(l, l > 1) +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + } + } + COMPREHENSION [5] { + iter_var: @c:0 + iter_range: { + IDENT [6] { + name: @index0 + } + } + accu_var: @x:0 + accu_init: { + CONSTANT [7] { value: false } + } + loop_condition: { + CALL [8] { + function: @not_strictly_false + args: { + CALL [9] { + function: !_ + args: { + IDENT [10] { + name: @x:0 + } + } + } } } } - accu_var: @x0:1 + loop_step: { + CALL [11] { + function: _||_ + args: { + IDENT [12] { + name: @x:0 + } + CALL [13] { + function: _>_ + args: { + IDENT [14] { + name: @c:0 + } + CONSTANT [15] { value: 0 } + } + } + } + } + } + result: { + IDENT [16] { + name: @x:0 + } + } + } + COMPREHENSION [17] { + iter_var: @c:1 + iter_range: { + IDENT [18] { + name: @index0 + } + } + accu_var: @x:1 accu_init: { CONSTANT [19] { value: false } } @@ -1451,7 +1863,7 @@ CALL [1] { function: !_ args: { IDENT [22] { - name: @x0:1 + name: @x:1 } } } @@ -1463,15 +1875,15 @@ CALL [1] { function: _||_ args: { IDENT [24] { - name: @x0:1 + name: @x:1 } CALL [25] { - function: _==_ + function: _>_ args: { IDENT [26] { - name: @c0:1 + name: @c:1 } - CONSTANT [27] { value: "a" } + CONSTANT [27] { value: 0 } } } } @@ -1479,65 +1891,139 @@ CALL [1] { } result: { IDENT [28] { - name: @x0:1 + name: @x:1 } } } - LIST [29] { - elements: { + COMPREHENSION [29] { + iter_var: @c:2 + iter_range: { IDENT [30] { name: @index0 } } - } - LIST [31] { - elements: { - IDENT [32] { - name: @index1 + accu_var: @x:2 + accu_init: { + CONSTANT [31] { value: false } + } + loop_condition: { + CALL [32] { + function: @not_strictly_false + args: { + CALL [33] { + function: !_ + args: { + IDENT [34] { + name: @x:2 + } + } + } + } } } - } - CALL [33] { - function: _+_ - args: { - CALL [34] { - function: _+_ + loop_step: { + CALL [35] { + function: _||_ args: { - CALL [35] { - function: _+_ + IDENT [36] { + name: @x:2 + } + CALL [37] { + function: _>_ args: { - IDENT [36] { - name: @index2 + IDENT [38] { + name: @c:2 } - IDENT [37] { - name: @index2 + CONSTANT [39] { value: 1 } + } + } + } + } + } + result: { + IDENT [40] { + name: @x:2 + } + } + } + COMPREHENSION [41] { + iter_var: @c:3 + iter_range: { + LIST [42] { + elements: { + CONSTANT [43] { value: 2 } + } + } + } + accu_var: @x:3 + accu_init: { + CONSTANT [44] { value: false } + } + loop_condition: { + CALL [45] { + function: @not_strictly_false + args: { + CALL [46] { + function: !_ + args: { + IDENT [47] { + name: @x:3 } } } - IDENT [38] { - name: @index3 + } + } + } + loop_step: { + CALL [48] { + function: _||_ + args: { + IDENT [49] { + name: @x:3 + } + CALL [50] { + function: _>_ + args: { + IDENT [51] { + name: @c:3 + } + CONSTANT [52] { value: 1 } + } } } } - IDENT [39] { - name: @index3 + } + result: { + IDENT [53] { + name: @x:3 } } } } } - CALL [40] { - function: _==_ + CALL [54] { + function: _&&_ args: { - IDENT [41] { - name: @index4 + CALL [55] { + function: _&&_ + args: { + IDENT [56] { + name: @index1 + } + IDENT [57] { + name: @index2 + } + } } - LIST [42] { - elements: { - CONSTANT [43] { value: true } - CONSTANT [44] { value: true } - CONSTANT [45] { value: true } - CONSTANT [46] { value: true } + CALL [58] { + function: _&&_ + args: { + IDENT [59] { + name: @index3 + } + IDENT [60] { + name: @index4 + } } } } @@ -1570,7 +2056,7 @@ CALL [1] { function: _+_ args: { IDENT [12] { - name: @x1:0 + name: @x:0 } LIST [13] { elements: { @@ -1578,7 +2064,7 @@ CALL [1] { function: _+_ args: { IDENT [15] { - name: @c1:0 + name: @c:0 } CONSTANT [16] { value: 1 } } @@ -1590,13 +2076,13 @@ CALL [1] { LIST [17] { elements: { COMPREHENSION [18] { - iter_var: @c1:0 + iter_var: @c:0 iter_range: { IDENT [19] { name: @index0 } } - accu_var: @x1:0 + accu_var: @x:0 accu_init: { LIST [20] { elements: { @@ -1613,7 +2099,7 @@ CALL [1] { } result: { IDENT [23] { - name: @x1:0 + name: @x:0 } } } @@ -1625,13 +2111,13 @@ CALL [1] { function: _==_ args: { COMPREHENSION [25] { - iter_var: @c0:0 + iter_var: @c:1 iter_range: { IDENT [26] { name: @index0 } } - accu_var: @x0:0 + accu_var: @x:1 accu_init: { LIST [27] { elements: { @@ -1646,7 +2132,7 @@ CALL [1] { function: _+_ args: { IDENT [30] { - name: @x0:0 + name: @x:1 } IDENT [31] { name: @index3 @@ -1656,7 +2142,7 @@ CALL [1] { } result: { IDENT [32] { - name: @x0:0 + name: @x:1 } } } @@ -1692,10 +2178,10 @@ CALL [1] { function: _==_ args: { IDENT [5] { - name: @c1:0 + name: @c:0 } IDENT [6] { - name: @c0:0 + name: @c:1 } } } @@ -1703,26 +2189,26 @@ CALL [1] { function: _+_ args: { IDENT [8] { - name: @x1:0 + name: @x:0 } LIST [9] { elements: { IDENT [10] { - name: @c1:0 + name: @c:0 } } } } } IDENT [11] { - name: @x1:0 + name: @x:0 } } } LIST [12] { elements: { COMPREHENSION [13] { - iter_var: @c1:0 + iter_var: @c:0 iter_range: { LIST [14] { elements: { @@ -1732,7 +2218,7 @@ CALL [1] { } } } - accu_var: @x1:0 + accu_var: @x:0 accu_init: { LIST [18] { elements: { @@ -1749,7 +2235,7 @@ CALL [1] { } result: { IDENT [21] { - name: @x1:0 + name: @x:0 } } } @@ -1761,7 +2247,7 @@ CALL [1] { function: _==_ args: { COMPREHENSION [23] { - iter_var: @c0:0 + iter_var: @c:1 iter_range: { LIST [24] { elements: { @@ -1770,7 +2256,7 @@ CALL [1] { } } } - accu_var: @x0:0 + accu_var: @x:1 accu_init: { LIST [27] { elements: { @@ -1785,7 +2271,7 @@ CALL [1] { function: _+_ args: { IDENT [30] { - name: @x0:0 + name: @x:1 } IDENT [31] { name: @index1 @@ -1795,7 +2281,7 @@ CALL [1] { } result: { IDENT [32] { - name: @x0:0 + name: @x:1 } } } @@ -1988,7 +2474,7 @@ CALL [1] { function: _+_ args: { IDENT [14] { - name: @x1:0 + name: @x:0 } LIST [15] { elements: { @@ -2005,13 +2491,13 @@ CALL [1] { LIST [19] { elements: { COMPREHENSION [20] { - iter_var: @c1:0 + iter_var: @c:0 iter_range: { IDENT [21] { name: @index1 } } - accu_var: @x1:0 + accu_var: @x:0 accu_init: { LIST [22] { elements: { @@ -2028,7 +2514,7 @@ CALL [1] { } result: { IDENT [25] { - name: @x1:0 + name: @x:0 } } } @@ -2040,13 +2526,13 @@ CALL [1] { function: _==_ args: { COMPREHENSION [27] { - iter_var: @c0:0 + iter_var: @c:1 iter_range: { IDENT [28] { name: @index1 } } - accu_var: @x0:0 + accu_var: @x:1 accu_init: { LIST [29] { elements: { @@ -2061,7 +2547,7 @@ CALL [1] { function: _+_ args: { IDENT [32] { - name: @x0:0 + name: @x:1 } IDENT [33] { name: @index3 @@ -2071,7 +2557,7 @@ CALL [1] { } result: { IDENT [34] { - name: @x0:0 + name: @x:1 } } } @@ -2138,7 +2624,7 @@ CALL [1] { function: _||_ args: { IDENT [16] { - name: @x0:0 + name: @x:0 } CALL [17] { function: _>_ @@ -2147,7 +2633,7 @@ CALL [1] { function: _-_ args: { IDENT [19] { - name: @c0:0 + name: @c:0 } CONSTANT [20] { value: 1 } } @@ -2158,13 +2644,13 @@ CALL [1] { } } COMPREHENSION [22] { - iter_var: @c0:0 + iter_var: @c:0 iter_range: { IDENT [23] { name: @index1 } } - accu_var: @x0:0 + accu_var: @x:0 accu_init: { CONSTANT [24] { value: false } } @@ -2176,7 +2662,7 @@ CALL [1] { function: !_ args: { IDENT [27] { - name: @x0:0 + name: @x:0 } } } @@ -2190,7 +2676,7 @@ CALL [1] { } result: { IDENT [29] { - name: @x0:0 + name: @x:0 } } } @@ -2221,10 +2707,10 @@ CALL [1] { function: _+_ args: { IDENT [4] { - name: @c1:0 + name: @c:0 } IDENT [5] { - name: @c1:0 + name: @c:0 } } } @@ -2232,10 +2718,10 @@ CALL [1] { function: _+_ args: { IDENT [7] { - name: @c0:0 + name: @c:1 } IDENT [8] { - name: @c0:0 + name: @c:1 } } } @@ -2243,7 +2729,7 @@ CALL [1] { function: _+_ args: { IDENT [10] { - name: @x1:0 + name: @x:0 } LIST [11] { elements: { @@ -2265,7 +2751,7 @@ CALL [1] { function: _+_ args: { IDENT [16] { - name: @x0:0 + name: @x:1 } LIST [17] { elements: { @@ -2286,10 +2772,10 @@ CALL [1] { } } COMPREHENSION [21] { - iter_var: @c0:0 + iter_var: @c:1 iter_range: { COMPREHENSION [22] { - iter_var: @c1:0 + iter_var: @c:0 iter_range: { LIST [23] { elements: { @@ -2298,7 +2784,7 @@ CALL [1] { } } } - accu_var: @x1:0 + accu_var: @x:0 accu_init: { LIST [26] { elements: { @@ -2315,12 +2801,12 @@ CALL [1] { } result: { IDENT [29] { - name: @x1:0 + name: @x:0 } } } } - accu_var: @x0:0 + accu_var: @x:1 accu_init: { LIST [30] { elements: { @@ -2337,7 +2823,7 @@ CALL [1] { } result: { IDENT [33] { - name: @x0:0 + name: @x:1 } } } @@ -3333,4 +3819,4 @@ CALL [1] { } } } -} +} \ No newline at end of file diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_4.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_4.baseline index 538fe0062..a640f81da 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_4.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_4.baseline @@ -1171,28 +1171,36 @@ CALL [1] { elements: { LIST [3] { elements: { - COMPREHENSION [4] { - iter_var: @c0:0 + CONSTANT [4] { value: 1 } + } + } + LIST [5] { + elements: { + CONSTANT [6] { value: 2 } + } + } + LIST [7] { + elements: { + COMPREHENSION [8] { + iter_var: @c:0 iter_range: { - LIST [5] { - elements: { - CONSTANT [6] { value: 1 } - } + IDENT [9] { + name: @index0 } } - accu_var: @x0:0 + accu_var: @x:0 accu_init: { - CONSTANT [7] { value: false } + CONSTANT [10] { value: false } } loop_condition: { - CALL [8] { + CALL [11] { function: @not_strictly_false args: { - CALL [9] { + CALL [12] { function: !_ args: { - IDENT [10] { - name: @x0:0 + IDENT [13] { + name: @x:0 } } } @@ -1200,56 +1208,54 @@ CALL [1] { } } loop_step: { - CALL [11] { + CALL [14] { function: _||_ args: { - IDENT [12] { - name: @x0:0 + IDENT [15] { + name: @x:0 } - CALL [13] { + CALL [16] { function: _>_ args: { - IDENT [14] { - name: @c0:0 + IDENT [17] { + name: @c:0 } - CONSTANT [15] { value: 0 } + CONSTANT [18] { value: 0 } } } } } } result: { - IDENT [16] { - name: @x0:0 + IDENT [19] { + name: @x:0 } } } } } - LIST [17] { + LIST [20] { elements: { - COMPREHENSION [18] { - iter_var: @c0:0 + COMPREHENSION [21] { + iter_var: @c:1 iter_range: { - LIST [19] { - elements: { - CONSTANT [20] { value: 2 } - } + IDENT [22] { + name: @index0 } } - accu_var: @x0:0 + accu_var: @x:1 accu_init: { - CONSTANT [21] { value: false } + CONSTANT [23] { value: false } } loop_condition: { - CALL [22] { + CALL [24] { function: @not_strictly_false args: { - CALL [23] { + CALL [25] { function: !_ args: { - IDENT [24] { - name: @x0:0 + IDENT [26] { + name: @x:1 } } } @@ -1257,81 +1263,198 @@ CALL [1] { } } loop_step: { - CALL [25] { + CALL [27] { function: _||_ args: { - IDENT [26] { - name: @x0:0 + IDENT [28] { + name: @x:1 } - CALL [27] { + CALL [29] { function: _>_ args: { - IDENT [28] { - name: @c0:0 + IDENT [30] { + name: @c:1 } - CONSTANT [29] { value: 1 } + CONSTANT [31] { value: 0 } } } } } } result: { - IDENT [30] { - name: @x0:0 + IDENT [32] { + name: @x:1 } } } } } - CALL [31] { - function: size - args: { - IDENT [32] { - name: @index0 + LIST [33] { + elements: { + COMPREHENSION [34] { + iter_var: @c:2 + iter_range: { + IDENT [35] { + name: @index1 + } + } + accu_var: @x:2 + accu_init: { + CONSTANT [36] { value: false } + } + loop_condition: { + CALL [37] { + function: @not_strictly_false + args: { + CALL [38] { + function: !_ + args: { + IDENT [39] { + name: @x:2 + } + } + } + } + } + } + loop_step: { + CALL [40] { + function: _||_ + args: { + IDENT [41] { + name: @x:2 + } + CALL [42] { + function: _>_ + args: { + IDENT [43] { + name: @c:2 + } + CONSTANT [44] { value: 1 } + } + } + } + } + } + result: { + IDENT [45] { + name: @x:2 + } + } } } } - CALL [33] { - function: size - args: { - IDENT [34] { - name: @index1 + LIST [46] { + elements: { + COMPREHENSION [47] { + iter_var: @c:3 + iter_range: { + IDENT [48] { + name: @index1 + } + } + accu_var: @x:3 + accu_init: { + CONSTANT [49] { value: false } + } + loop_condition: { + CALL [50] { + function: @not_strictly_false + args: { + CALL [51] { + function: !_ + args: { + IDENT [52] { + name: @x:3 + } + } + } + } + } + } + loop_step: { + CALL [53] { + function: _||_ + args: { + IDENT [54] { + name: @x:3 + } + CALL [55] { + function: _>_ + args: { + IDENT [56] { + name: @c:3 + } + CONSTANT [57] { value: 1 } + } + } + } + } + } + result: { + IDENT [58] { + name: @x:3 + } + } } } } - } - } - CALL [35] { - function: _==_ - args: { - CALL [36] { + CALL [59] { function: _+_ args: { - CALL [37] { + CALL [60] { function: _+_ args: { - CALL [38] { + CALL [61] { function: _+_ args: { - IDENT [39] { - name: @index2 + CALL [62] { + function: size + args: { + IDENT [63] { + name: @index2 + } + } } - IDENT [40] { - name: @index2 + CALL [64] { + function: size + args: { + IDENT [65] { + name: @index3 + } + } } } } - IDENT [41] { - name: @index3 + CALL [66] { + function: size + args: { + IDENT [67] { + name: @index4 + } + } } } } - IDENT [42] { - name: @index3 + CALL [68] { + function: size + args: { + IDENT [69] { + name: @index5 + } + } } } } - CONSTANT [43] { value: 4 } + } + } + CALL [70] { + function: _==_ + args: { + IDENT [71] { + name: @index6 + } + CONSTANT [72] { value: 4 } } } } @@ -1346,28 +1469,91 @@ CALL [1] { elements: { LIST [3] { elements: { - COMPREHENSION [4] { - iter_var: @c0:0 + CONSTANT [4] { value: 1 } + } + } + LIST [5] { + elements: { + CONSTANT [6] { value: "a" } + } + } + LIST [7] { + elements: { + COMPREHENSION [8] { + iter_var: @c:0 iter_range: { - LIST [5] { - elements: { - CONSTANT [6] { value: 1 } + IDENT [9] { + name: @index0 + } + } + accu_var: @x:0 + accu_init: { + CONSTANT [10] { value: false } + } + loop_condition: { + CALL [11] { + function: @not_strictly_false + args: { + CALL [12] { + function: !_ + args: { + IDENT [13] { + name: @x:0 + } + } + } } } } - accu_var: @x0:0 + loop_step: { + CALL [14] { + function: _||_ + args: { + IDENT [15] { + name: @x:0 + } + CALL [16] { + function: _>_ + args: { + IDENT [17] { + name: @c:0 + } + CONSTANT [18] { value: 0 } + } + } + } + } + } + result: { + IDENT [19] { + name: @x:0 + } + } + } + } + } + LIST [20] { + elements: { + COMPREHENSION [21] { + iter_var: @c:1 + iter_range: { + IDENT [22] { + name: @index0 + } + } + accu_var: @x:1 accu_init: { - CONSTANT [7] { value: false } + CONSTANT [23] { value: false } } loop_condition: { - CALL [8] { + CALL [24] { function: @not_strictly_false args: { - CALL [9] { + CALL [25] { function: !_ args: { - IDENT [10] { - name: @x0:0 + IDENT [26] { + name: @x:1 } } } @@ -1375,56 +1561,109 @@ CALL [1] { } } loop_step: { - CALL [11] { + CALL [27] { function: _||_ args: { - IDENT [12] { - name: @x0:0 + IDENT [28] { + name: @x:1 } - CALL [13] { + CALL [29] { function: _>_ args: { - IDENT [14] { - name: @c0:0 + IDENT [30] { + name: @c:1 } - CONSTANT [15] { value: 0 } + CONSTANT [31] { value: 0 } } } } } } result: { - IDENT [16] { - name: @x0:0 + IDENT [32] { + name: @x:1 } } } } } - LIST [17] { + LIST [33] { elements: { - COMPREHENSION [18] { - iter_var: @c0:1 + COMPREHENSION [34] { + iter_var: @c:2 iter_range: { - LIST [19] { - elements: { - CONSTANT [20] { value: "a" } + IDENT [35] { + name: @index1 + } + } + accu_var: @x:2 + accu_init: { + CONSTANT [36] { value: false } + } + loop_condition: { + CALL [37] { + function: @not_strictly_false + args: { + CALL [38] { + function: !_ + args: { + IDENT [39] { + name: @x:2 + } + } + } } } } - accu_var: @x0:1 + loop_step: { + CALL [40] { + function: _||_ + args: { + IDENT [41] { + name: @x:2 + } + CALL [42] { + function: _==_ + args: { + IDENT [43] { + name: @c:2 + } + CONSTANT [44] { value: "a" } + } + } + } + } + } + result: { + IDENT [45] { + name: @x:2 + } + } + } + } + } + LIST [46] { + elements: { + COMPREHENSION [47] { + iter_var: @c:3 + iter_range: { + IDENT [48] { + name: @index1 + } + } + accu_var: @x:3 accu_init: { - CONSTANT [21] { value: false } + CONSTANT [49] { value: false } } loop_condition: { - CALL [22] { + CALL [50] { function: @not_strictly_false args: { - CALL [23] { + CALL [51] { function: !_ args: { - IDENT [24] { - name: @x0:1 + IDENT [52] { + name: @x:3 } } } @@ -1432,27 +1671,27 @@ CALL [1] { } } loop_step: { - CALL [25] { + CALL [53] { function: _||_ args: { - IDENT [26] { - name: @x0:1 + IDENT [54] { + name: @x:3 } - CALL [27] { + CALL [55] { function: _==_ args: { - IDENT [28] { - name: @c0:1 + IDENT [56] { + name: @c:3 } - CONSTANT [29] { value: "a" } + CONSTANT [57] { value: "a" } } } } } } result: { - IDENT [30] { - name: @x0:1 + IDENT [58] { + name: @x:3 } } } @@ -1460,46 +1699,290 @@ CALL [1] { } } } - CALL [31] { + CALL [59] { function: _==_ args: { - CALL [32] { + CALL [60] { function: _+_ args: { - CALL [33] { + CALL [61] { function: _+_ args: { - CALL [34] { + CALL [62] { function: _+_ args: { - IDENT [35] { - name: @index0 + IDENT [63] { + name: @index2 } - IDENT [36] { - name: @index0 + IDENT [64] { + name: @index3 } } } - IDENT [37] { - name: @index1 + IDENT [65] { + name: @index4 } } } - IDENT [38] { - name: @index1 + IDENT [66] { + name: @index5 } } } - LIST [39] { + LIST [67] { + elements: { + CONSTANT [68] { value: true } + CONSTANT [69] { value: true } + CONSTANT [70] { value: true } + CONSTANT [71] { value: true } + } + } + } + } + } +} +Test case: MULTIPLE_MACROS_3 +Source: [1].exists(i, i > 0) && [1].exists(j, j > 0) && [1].exists(k, k > 1) && [2].exists(l, l > 1) +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + LIST [3] { elements: { - CONSTANT [40] { value: true } - CONSTANT [41] { value: true } - CONSTANT [42] { value: true } - CONSTANT [43] { value: true } + CONSTANT [4] { value: 1 } + } + } + CALL [5] { + function: _&&_ + args: { + COMPREHENSION [6] { + iter_var: @c:0 + iter_range: { + IDENT [7] { + name: @index0 + } + } + accu_var: @x:0 + accu_init: { + CONSTANT [8] { value: false } + } + loop_condition: { + CALL [9] { + function: @not_strictly_false + args: { + CALL [10] { + function: !_ + args: { + IDENT [11] { + name: @x:0 + } + } + } + } + } + } + loop_step: { + CALL [12] { + function: _||_ + args: { + IDENT [13] { + name: @x:0 + } + CALL [14] { + function: _>_ + args: { + IDENT [15] { + name: @c:0 + } + CONSTANT [16] { value: 0 } + } + } + } + } + } + result: { + IDENT [17] { + name: @x:0 + } + } + } + COMPREHENSION [18] { + iter_var: @c:1 + iter_range: { + IDENT [19] { + name: @index0 + } + } + accu_var: @x:1 + accu_init: { + CONSTANT [20] { value: false } + } + loop_condition: { + CALL [21] { + function: @not_strictly_false + args: { + CALL [22] { + function: !_ + args: { + IDENT [23] { + name: @x:1 + } + } + } + } + } + } + loop_step: { + CALL [24] { + function: _||_ + args: { + IDENT [25] { + name: @x:1 + } + CALL [26] { + function: _>_ + args: { + IDENT [27] { + name: @c:1 + } + CONSTANT [28] { value: 0 } + } + } + } + } + } + result: { + IDENT [29] { + name: @x:1 + } + } + } + } + } + CALL [30] { + function: _&&_ + args: { + COMPREHENSION [31] { + iter_var: @c:2 + iter_range: { + IDENT [32] { + name: @index0 + } + } + accu_var: @x:2 + accu_init: { + CONSTANT [33] { value: false } + } + loop_condition: { + CALL [34] { + function: @not_strictly_false + args: { + CALL [35] { + function: !_ + args: { + IDENT [36] { + name: @x:2 + } + } + } + } + } + } + loop_step: { + CALL [37] { + function: _||_ + args: { + IDENT [38] { + name: @x:2 + } + CALL [39] { + function: _>_ + args: { + IDENT [40] { + name: @c:2 + } + CONSTANT [41] { value: 1 } + } + } + } + } + } + result: { + IDENT [42] { + name: @x:2 + } + } + } + COMPREHENSION [43] { + iter_var: @c:3 + iter_range: { + LIST [44] { + elements: { + CONSTANT [45] { value: 2 } + } + } + } + accu_var: @x:3 + accu_init: { + CONSTANT [46] { value: false } + } + loop_condition: { + CALL [47] { + function: @not_strictly_false + args: { + CALL [48] { + function: !_ + args: { + IDENT [49] { + name: @x:3 + } + } + } + } + } + } + loop_step: { + CALL [50] { + function: _||_ + args: { + IDENT [51] { + name: @x:3 + } + CALL [52] { + function: _>_ + args: { + IDENT [53] { + name: @c:3 + } + CONSTANT [54] { value: 1 } + } + } + } + } + } + result: { + IDENT [55] { + name: @x:3 + } + } + } } } } } + CALL [56] { + function: _&&_ + args: { + IDENT [57] { + name: @index1 + } + IDENT [58] { + name: @index2 + } + } + } } } Test case: NESTED_MACROS @@ -1525,13 +2008,13 @@ CALL [1] { } } COMPREHENSION [11] { - iter_var: @c1:0 + iter_var: @c:0 iter_range: { IDENT [12] { name: @index0 } } - accu_var: @x1:0 + accu_var: @x:0 accu_init: { LIST [13] { elements: { @@ -1546,7 +2029,7 @@ CALL [1] { function: _+_ args: { IDENT [16] { - name: @x1:0 + name: @x:0 } LIST [17] { elements: { @@ -1554,7 +2037,7 @@ CALL [1] { function: _+_ args: { IDENT [19] { - name: @c1:0 + name: @c:0 } CONSTANT [20] { value: 1 } } @@ -1566,7 +2049,7 @@ CALL [1] { } result: { IDENT [21] { - name: @x1:0 + name: @x:0 } } } @@ -1576,13 +2059,13 @@ CALL [1] { function: _==_ args: { COMPREHENSION [23] { - iter_var: @c0:0 + iter_var: @c:1 iter_range: { IDENT [24] { name: @index0 } } - accu_var: @x0:0 + accu_var: @x:1 accu_init: { LIST [25] { elements: { @@ -1597,7 +2080,7 @@ CALL [1] { function: _+_ args: { IDENT [28] { - name: @x0:0 + name: @x:1 } LIST [29] { elements: { @@ -1611,7 +2094,7 @@ CALL [1] { } result: { IDENT [31] { - name: @x0:0 + name: @x:1 } } } @@ -1641,7 +2124,7 @@ CALL [1] { LIST [2] { elements: { COMPREHENSION [3] { - iter_var: @c1:0 + iter_var: @c:0 iter_range: { LIST [4] { elements: { @@ -1651,7 +2134,7 @@ CALL [1] { } } } - accu_var: @x1:0 + accu_var: @x:0 accu_init: { LIST [8] { elements: { @@ -1669,10 +2152,10 @@ CALL [1] { function: _==_ args: { IDENT [12] { - name: @c1:0 + name: @c:0 } IDENT [13] { - name: @c0:0 + name: @c:1 } } } @@ -1680,26 +2163,26 @@ CALL [1] { function: _+_ args: { IDENT [15] { - name: @x1:0 + name: @x:0 } LIST [16] { elements: { IDENT [17] { - name: @c1:0 + name: @c:0 } } } } } IDENT [18] { - name: @x1:0 + name: @x:0 } } } } result: { IDENT [19] { - name: @x1:0 + name: @x:0 } } } @@ -1709,7 +2192,7 @@ CALL [1] { function: _==_ args: { COMPREHENSION [21] { - iter_var: @c0:0 + iter_var: @c:1 iter_range: { LIST [22] { elements: { @@ -1718,7 +2201,7 @@ CALL [1] { } } } - accu_var: @x0:0 + accu_var: @x:1 accu_init: { LIST [25] { elements: { @@ -1733,7 +2216,7 @@ CALL [1] { function: _+_ args: { IDENT [28] { - name: @x0:0 + name: @x:1 } LIST [29] { elements: { @@ -1747,7 +2230,7 @@ CALL [1] { } result: { IDENT [31] { - name: @x0:0 + name: @x:1 } } } @@ -1934,13 +2417,13 @@ CALL [1] { } } COMPREHENSION [13] { - iter_var: @c1:0 + iter_var: @c:0 iter_range: { IDENT [14] { name: @index1 } } - accu_var: @x1:0 + accu_var: @x:0 accu_init: { LIST [15] { elements: { @@ -1955,7 +2438,7 @@ CALL [1] { function: _+_ args: { IDENT [18] { - name: @x1:0 + name: @x:0 } LIST [19] { elements: { @@ -1972,7 +2455,7 @@ CALL [1] { } result: { IDENT [23] { - name: @x1:0 + name: @x:0 } } } @@ -1982,13 +2465,13 @@ CALL [1] { function: _==_ args: { COMPREHENSION [25] { - iter_var: @c0:0 + iter_var: @c:1 iter_range: { IDENT [26] { name: @index1 } } - accu_var: @x0:0 + accu_var: @x:1 accu_init: { LIST [27] { elements: { @@ -2003,7 +2486,7 @@ CALL [1] { function: _+_ args: { IDENT [30] { - name: @x0:0 + name: @x:1 } LIST [31] { elements: { @@ -2017,7 +2500,7 @@ CALL [1] { } result: { IDENT [33] { - name: @x0:0 + name: @x:1 } } } @@ -2059,7 +2542,7 @@ CALL [1] { } } COMPREHENSION [8] { - iter_var: @c0:0 + iter_var: @c:0 iter_range: { LIST [9] { elements: { @@ -2084,7 +2567,7 @@ CALL [1] { } } } - accu_var: @x0:0 + accu_var: @x:0 accu_init: { CONSTANT [16] { value: false } } @@ -2096,7 +2579,7 @@ CALL [1] { function: !_ args: { IDENT [19] { - name: @x0:0 + name: @x:0 } } } @@ -2108,7 +2591,7 @@ CALL [1] { function: _||_ args: { IDENT [21] { - name: @x0:0 + name: @x:0 } CALL [22] { function: _>_ @@ -2117,7 +2600,7 @@ CALL [1] { function: _-_ args: { IDENT [24] { - name: @c0:0 + name: @c:0 } CONSTANT [25] { value: 1 } } @@ -2130,7 +2613,7 @@ CALL [1] { } result: { IDENT [27] { - name: @x0:0 + name: @x:0 } } } @@ -2161,10 +2644,10 @@ CALL [1] { function: _+_ args: { IDENT [4] { - name: @c1:0 + name: @c:0 } IDENT [5] { - name: @c1:0 + name: @c:0 } } } @@ -2172,15 +2655,15 @@ CALL [1] { function: _+_ args: { IDENT [7] { - name: @c0:0 + name: @c:1 } IDENT [8] { - name: @c0:0 + name: @c:1 } } } COMPREHENSION [9] { - iter_var: @c1:0 + iter_var: @c:0 iter_range: { LIST [10] { elements: { @@ -2189,7 +2672,7 @@ CALL [1] { } } } - accu_var: @x1:0 + accu_var: @x:0 accu_init: { LIST [13] { elements: { @@ -2204,7 +2687,7 @@ CALL [1] { function: _+_ args: { IDENT [16] { - name: @x1:0 + name: @x:0 } LIST [17] { elements: { @@ -2225,20 +2708,20 @@ CALL [1] { } result: { IDENT [21] { - name: @x1:0 + name: @x:0 } } } } } COMPREHENSION [22] { - iter_var: @c0:0 + iter_var: @c:1 iter_range: { IDENT [23] { name: @index2 } } - accu_var: @x0:0 + accu_var: @x:1 accu_init: { LIST [24] { elements: { @@ -2253,7 +2736,7 @@ CALL [1] { function: _+_ args: { IDENT [27] { - name: @x0:0 + name: @x:1 } LIST [28] { elements: { @@ -2274,7 +2757,7 @@ CALL [1] { } result: { IDENT [32] { - name: @x0:0 + name: @x:1 } } } @@ -3249,4 +3732,4 @@ CALL [1] { } } } -} +} \ No newline at end of file diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_5.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_5.baseline index ae1f4743b..ba9b61292 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_5.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_5.baseline @@ -1151,33 +1151,101 @@ CALL [1] { args: { LIST [2] { elements: { - CALL [3] { + LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + } + } + LIST [5] { + elements: { + CONSTANT [6] { value: 2 } + } + } + CALL [7] { function: size args: { - LIST [4] { + LIST [8] { elements: { - COMPREHENSION [5] { - iter_var: @c0:0 + COMPREHENSION [9] { + iter_var: @c:0 iter_range: { - LIST [6] { - elements: { - CONSTANT [7] { value: 1 } + IDENT [10] { + name: @index0 + } + } + accu_var: @x:0 + accu_init: { + CONSTANT [11] { value: false } + } + loop_condition: { + CALL [12] { + function: @not_strictly_false + args: { + CALL [13] { + function: !_ + args: { + IDENT [14] { + name: @x:0 + } + } + } + } + } + } + loop_step: { + CALL [15] { + function: _||_ + args: { + IDENT [16] { + name: @x:0 + } + CALL [17] { + function: _>_ + args: { + IDENT [18] { + name: @c:0 + } + CONSTANT [19] { value: 0 } + } + } } } } - accu_var: @x0:0 + result: { + IDENT [20] { + name: @x:0 + } + } + } + } + } + } + } + CALL [21] { + function: size + args: { + LIST [22] { + elements: { + COMPREHENSION [23] { + iter_var: @c:1 + iter_range: { + IDENT [24] { + name: @index0 + } + } + accu_var: @x:1 accu_init: { - CONSTANT [8] { value: false } + CONSTANT [25] { value: false } } loop_condition: { - CALL [9] { + CALL [26] { function: @not_strictly_false args: { - CALL [10] { + CALL [27] { function: !_ args: { - IDENT [11] { - name: @x0:0 + IDENT [28] { + name: @x:1 } } } @@ -1185,27 +1253,27 @@ CALL [1] { } } loop_step: { - CALL [12] { + CALL [29] { function: _||_ args: { - IDENT [13] { - name: @x0:0 + IDENT [30] { + name: @x:1 } - CALL [14] { + CALL [31] { function: _>_ args: { - IDENT [15] { - name: @c0:0 + IDENT [32] { + name: @c:1 } - CONSTANT [16] { value: 0 } + CONSTANT [33] { value: 0 } } } } } } result: { - IDENT [17] { - name: @x0:0 + IDENT [34] { + name: @x:1 } } } @@ -1213,33 +1281,91 @@ CALL [1] { } } } - CALL [18] { + CALL [35] { function: size args: { - LIST [19] { + LIST [36] { elements: { - COMPREHENSION [20] { - iter_var: @c0:0 + COMPREHENSION [37] { + iter_var: @c:2 iter_range: { - LIST [21] { - elements: { - CONSTANT [22] { value: 2 } + IDENT [38] { + name: @index1 + } + } + accu_var: @x:2 + accu_init: { + CONSTANT [39] { value: false } + } + loop_condition: { + CALL [40] { + function: @not_strictly_false + args: { + CALL [41] { + function: !_ + args: { + IDENT [42] { + name: @x:2 + } + } + } + } + } + } + loop_step: { + CALL [43] { + function: _||_ + args: { + IDENT [44] { + name: @x:2 + } + CALL [45] { + function: _>_ + args: { + IDENT [46] { + name: @c:2 + } + CONSTANT [47] { value: 1 } + } + } } } } - accu_var: @x0:0 + result: { + IDENT [48] { + name: @x:2 + } + } + } + } + } + } + } + CALL [49] { + function: size + args: { + LIST [50] { + elements: { + COMPREHENSION [51] { + iter_var: @c:3 + iter_range: { + IDENT [52] { + name: @index1 + } + } + accu_var: @x:3 accu_init: { - CONSTANT [23] { value: false } + CONSTANT [53] { value: false } } loop_condition: { - CALL [24] { + CALL [54] { function: @not_strictly_false args: { - CALL [25] { + CALL [55] { function: !_ args: { - IDENT [26] { - name: @x0:0 + IDENT [56] { + name: @x:3 } } } @@ -1247,27 +1373,27 @@ CALL [1] { } } loop_step: { - CALL [27] { + CALL [57] { function: _||_ args: { - IDENT [28] { - name: @x0:0 + IDENT [58] { + name: @x:3 } - CALL [29] { + CALL [59] { function: _>_ args: { - IDENT [30] { - name: @c0:0 + IDENT [60] { + name: @c:3 } - CONSTANT [31] { value: 1 } + CONSTANT [61] { value: 1 } } } } } } result: { - IDENT [32] { - name: @x0:0 + IDENT [62] { + name: @x:3 } } } @@ -1277,37 +1403,37 @@ CALL [1] { } } } - CALL [33] { + CALL [63] { function: _==_ args: { - CALL [34] { + CALL [64] { function: _+_ args: { - CALL [35] { + CALL [65] { function: _+_ args: { - CALL [36] { + CALL [66] { function: _+_ args: { - IDENT [37] { - name: @index0 + IDENT [67] { + name: @index2 } - IDENT [38] { - name: @index0 + IDENT [68] { + name: @index3 } } } - IDENT [39] { - name: @index1 + IDENT [69] { + name: @index4 } } } - IDENT [40] { - name: @index1 + IDENT [70] { + name: @index5 } } } - CONSTANT [41] { value: 4 } + CONSTANT [71] { value: 4 } } } } @@ -1322,28 +1448,316 @@ CALL [1] { elements: { LIST [3] { elements: { - COMPREHENSION [4] { - iter_var: @c0:0 - iter_range: { - LIST [5] { - elements: { - CONSTANT [6] { value: 1 } + CONSTANT [4] { value: 1 } + } + } + LIST [5] { + elements: { + CONSTANT [6] { value: "a" } + } + } + CALL [7] { + function: _+_ + args: { + LIST [8] { + elements: { + COMPREHENSION [9] { + iter_var: @c:0 + iter_range: { + IDENT [10] { + name: @index0 + } + } + accu_var: @x:0 + accu_init: { + CONSTANT [11] { value: false } + } + loop_condition: { + CALL [12] { + function: @not_strictly_false + args: { + CALL [13] { + function: !_ + args: { + IDENT [14] { + name: @x:0 + } + } + } + } + } + } + loop_step: { + CALL [15] { + function: _||_ + args: { + IDENT [16] { + name: @x:0 + } + CALL [17] { + function: _>_ + args: { + IDENT [18] { + name: @c:0 + } + CONSTANT [19] { value: 0 } + } + } + } + } + } + result: { + IDENT [20] { + name: @x:0 + } + } + } + } + } + LIST [21] { + elements: { + COMPREHENSION [22] { + iter_var: @c:1 + iter_range: { + IDENT [23] { + name: @index0 + } + } + accu_var: @x:1 + accu_init: { + CONSTANT [24] { value: false } + } + loop_condition: { + CALL [25] { + function: @not_strictly_false + args: { + CALL [26] { + function: !_ + args: { + IDENT [27] { + name: @x:1 + } + } + } + } + } + } + loop_step: { + CALL [28] { + function: _||_ + args: { + IDENT [29] { + name: @x:1 + } + CALL [30] { + function: _>_ + args: { + IDENT [31] { + name: @c:1 + } + CONSTANT [32] { value: 0 } + } + } + } + } + } + result: { + IDENT [33] { + name: @x:1 + } + } + } + } + } + } + } + CALL [34] { + function: _+_ + args: { + IDENT [35] { + name: @index2 + } + LIST [36] { + elements: { + COMPREHENSION [37] { + iter_var: @c:2 + iter_range: { + IDENT [38] { + name: @index1 + } + } + accu_var: @x:2 + accu_init: { + CONSTANT [39] { value: false } + } + loop_condition: { + CALL [40] { + function: @not_strictly_false + args: { + CALL [41] { + function: !_ + args: { + IDENT [42] { + name: @x:2 + } + } + } + } + } + } + loop_step: { + CALL [43] { + function: _||_ + args: { + IDENT [44] { + name: @x:2 + } + CALL [45] { + function: _==_ + args: { + IDENT [46] { + name: @c:2 + } + CONSTANT [47] { value: "a" } + } + } + } + } + } + result: { + IDENT [48] { + name: @x:2 + } + } + } + } + } + } + } + CALL [49] { + function: _+_ + args: { + IDENT [50] { + name: @index3 + } + LIST [51] { + elements: { + COMPREHENSION [52] { + iter_var: @c:3 + iter_range: { + IDENT [53] { + name: @index1 + } + } + accu_var: @x:3 + accu_init: { + CONSTANT [54] { value: false } + } + loop_condition: { + CALL [55] { + function: @not_strictly_false + args: { + CALL [56] { + function: !_ + args: { + IDENT [57] { + name: @x:3 + } + } + } + } + } + } + loop_step: { + CALL [58] { + function: _||_ + args: { + IDENT [59] { + name: @x:3 + } + CALL [60] { + function: _==_ + args: { + IDENT [61] { + name: @c:3 + } + CONSTANT [62] { value: "a" } + } + } + } + } + } + result: { + IDENT [63] { + name: @x:3 + } } } } - accu_var: @x0:0 + } + } + } + } + } + CALL [64] { + function: _==_ + args: { + IDENT [65] { + name: @index4 + } + LIST [66] { + elements: { + CONSTANT [67] { value: true } + CONSTANT [68] { value: true } + CONSTANT [69] { value: true } + CONSTANT [70] { value: true } + } + } + } + } + } +} +Test case: MULTIPLE_MACROS_3 +Source: [1].exists(i, i > 0) && [1].exists(j, j > 0) && [1].exists(k, k > 1) && [2].exists(l, l > 1) +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + } + } + } + } + CALL [5] { + function: _&&_ + args: { + CALL [6] { + function: _&&_ + args: { + COMPREHENSION [7] { + iter_var: @c:0 + iter_range: { + IDENT [8] { + name: @index0 + } + } + accu_var: @x:0 accu_init: { - CONSTANT [7] { value: false } + CONSTANT [9] { value: false } } loop_condition: { - CALL [8] { + CALL [10] { function: @not_strictly_false args: { - CALL [9] { + CALL [11] { function: !_ args: { - IDENT [10] { - name: @x0:0 + IDENT [12] { + name: @x:0 } } } @@ -1351,44 +1765,38 @@ CALL [1] { } } loop_step: { - CALL [11] { + CALL [13] { function: _||_ args: { - IDENT [12] { - name: @x0:0 + IDENT [14] { + name: @x:0 } - CALL [13] { + CALL [15] { function: _>_ args: { - IDENT [14] { - name: @c0:0 + IDENT [16] { + name: @c:0 } - CONSTANT [15] { value: 0 } + CONSTANT [17] { value: 0 } } } } } } result: { - IDENT [16] { - name: @x0:0 + IDENT [18] { + name: @x:0 } } } - } - } - LIST [17] { - elements: { - COMPREHENSION [18] { - iter_var: @c0:1 + COMPREHENSION [19] { + iter_var: @c:1 iter_range: { - LIST [19] { - elements: { - CONSTANT [20] { value: "a" } - } + IDENT [20] { + name: @index0 } } - accu_var: @x0:1 + accu_var: @x:1 accu_init: { CONSTANT [21] { value: false } } @@ -1400,7 +1808,7 @@ CALL [1] { function: !_ args: { IDENT [24] { - name: @x0:1 + name: @x:1 } } } @@ -1412,15 +1820,15 @@ CALL [1] { function: _||_ args: { IDENT [26] { - name: @x0:1 + name: @x:1 } CALL [27] { - function: _==_ + function: _>_ args: { IDENT [28] { - name: @c0:1 + name: @c:1 } - CONSTANT [29] { value: "a" } + CONSTANT [29] { value: 0 } } } } @@ -1428,52 +1836,121 @@ CALL [1] { } result: { IDENT [30] { - name: @x0:1 + name: @x:1 } } } } } - } - } - CALL [31] { - function: _==_ - args: { - CALL [32] { - function: _+_ + CALL [31] { + function: _&&_ args: { - CALL [33] { - function: _+_ - args: { - CALL [34] { - function: _+_ + COMPREHENSION [32] { + iter_var: @c:2 + iter_range: { + IDENT [33] { + name: @index0 + } + } + accu_var: @x:2 + accu_init: { + CONSTANT [34] { value: false } + } + loop_condition: { + CALL [35] { + function: @not_strictly_false args: { - IDENT [35] { - name: @index0 + CALL [36] { + function: !_ + args: { + IDENT [37] { + name: @x:2 + } + } } - IDENT [36] { - name: @index0 + } + } + } + loop_step: { + CALL [38] { + function: _||_ + args: { + IDENT [39] { + name: @x:2 + } + CALL [40] { + function: _>_ + args: { + IDENT [41] { + name: @c:2 + } + CONSTANT [42] { value: 1 } + } } } } - IDENT [37] { - name: @index1 + } + result: { + IDENT [43] { + name: @x:2 } } } - IDENT [38] { - name: @index1 + COMPREHENSION [44] { + iter_var: @c:3 + iter_range: { + LIST [45] { + elements: { + CONSTANT [46] { value: 2 } + } + } + } + accu_var: @x:3 + accu_init: { + CONSTANT [47] { value: false } + } + loop_condition: { + CALL [48] { + function: @not_strictly_false + args: { + CALL [49] { + function: !_ + args: { + IDENT [50] { + name: @x:3 + } + } + } + } + } + } + loop_step: { + CALL [51] { + function: _||_ + args: { + IDENT [52] { + name: @x:3 + } + CALL [53] { + function: _>_ + args: { + IDENT [54] { + name: @c:3 + } + CONSTANT [55] { value: 1 } + } + } + } + } + } + result: { + IDENT [56] { + name: @x:3 + } + } } } } - LIST [39] { - elements: { - CONSTANT [40] { value: true } - CONSTANT [41] { value: true } - CONSTANT [42] { value: true } - CONSTANT [43] { value: true } - } - } } } } @@ -1503,13 +1980,13 @@ CALL [1] { LIST [11] { elements: { COMPREHENSION [12] { - iter_var: @c1:0 + iter_var: @c:0 iter_range: { IDENT [13] { name: @index0 } } - accu_var: @x1:0 + accu_var: @x:0 accu_init: { LIST [14] { elements: { @@ -1524,7 +2001,7 @@ CALL [1] { function: _+_ args: { IDENT [17] { - name: @x1:0 + name: @x:0 } LIST [18] { elements: { @@ -1532,7 +2009,7 @@ CALL [1] { function: _+_ args: { IDENT [20] { - name: @c1:0 + name: @c:0 } CONSTANT [21] { value: 1 } } @@ -1544,7 +2021,7 @@ CALL [1] { } result: { IDENT [22] { - name: @x1:0 + name: @x:0 } } } @@ -1556,13 +2033,13 @@ CALL [1] { function: _==_ args: { COMPREHENSION [24] { - iter_var: @c0:0 + iter_var: @c:1 iter_range: { IDENT [25] { name: @index0 } } - accu_var: @x0:0 + accu_var: @x:1 accu_init: { LIST [26] { elements: { @@ -1577,7 +2054,7 @@ CALL [1] { function: _+_ args: { IDENT [29] { - name: @x0:0 + name: @x:1 } IDENT [30] { name: @index2 @@ -1587,7 +2064,7 @@ CALL [1] { } result: { IDENT [31] { - name: @x0:0 + name: @x:1 } } } @@ -1619,7 +2096,7 @@ CALL [1] { LIST [3] { elements: { COMPREHENSION [4] { - iter_var: @c1:0 + iter_var: @c:0 iter_range: { LIST [5] { elements: { @@ -1629,7 +2106,7 @@ CALL [1] { } } } - accu_var: @x1:0 + accu_var: @x:0 accu_init: { LIST [9] { elements: { @@ -1647,10 +2124,10 @@ CALL [1] { function: _==_ args: { IDENT [13] { - name: @c1:0 + name: @c:0 } IDENT [14] { - name: @c0:0 + name: @c:1 } } } @@ -1658,26 +2135,26 @@ CALL [1] { function: _+_ args: { IDENT [16] { - name: @x1:0 + name: @x:0 } LIST [17] { elements: { IDENT [18] { - name: @c1:0 + name: @c:0 } } } } } IDENT [19] { - name: @x1:0 + name: @x:0 } } } } result: { IDENT [20] { - name: @x1:0 + name: @x:0 } } } @@ -1689,7 +2166,7 @@ CALL [1] { function: _==_ args: { COMPREHENSION [22] { - iter_var: @c0:0 + iter_var: @c:1 iter_range: { LIST [23] { elements: { @@ -1698,7 +2175,7 @@ CALL [1] { } } } - accu_var: @x0:0 + accu_var: @x:1 accu_init: { LIST [26] { elements: { @@ -1713,7 +2190,7 @@ CALL [1] { function: _+_ args: { IDENT [29] { - name: @x0:0 + name: @x:1 } IDENT [30] { name: @index0 @@ -1723,7 +2200,7 @@ CALL [1] { } result: { IDENT [31] { - name: @x0:0 + name: @x:1 } } } @@ -1912,13 +2389,13 @@ CALL [1] { LIST [13] { elements: { COMPREHENSION [14] { - iter_var: @c1:0 + iter_var: @c:0 iter_range: { IDENT [15] { name: @index1 } } - accu_var: @x1:0 + accu_var: @x:0 accu_init: { LIST [16] { elements: { @@ -1933,7 +2410,7 @@ CALL [1] { function: _+_ args: { IDENT [19] { - name: @x1:0 + name: @x:0 } LIST [20] { elements: { @@ -1950,7 +2427,7 @@ CALL [1] { } result: { IDENT [24] { - name: @x1:0 + name: @x:0 } } } @@ -1962,13 +2439,13 @@ CALL [1] { function: _==_ args: { COMPREHENSION [26] { - iter_var: @c0:0 + iter_var: @c:1 iter_range: { IDENT [27] { name: @index1 } } - accu_var: @x0:0 + accu_var: @x:1 accu_init: { LIST [28] { elements: { @@ -1983,7 +2460,7 @@ CALL [1] { function: _+_ args: { IDENT [31] { - name: @x0:0 + name: @x:1 } IDENT [32] { name: @index2 @@ -1993,7 +2470,7 @@ CALL [1] { } result: { IDENT [33] { - name: @x0:0 + name: @x:1 } } } @@ -2040,7 +2517,7 @@ CALL [1] { function: _||_ args: { COMPREHENSION [9] { - iter_var: @c0:0 + iter_var: @c:0 iter_range: { LIST [10] { elements: { @@ -2065,7 +2542,7 @@ CALL [1] { } } } - accu_var: @x0:0 + accu_var: @x:0 accu_init: { CONSTANT [17] { value: false } } @@ -2077,7 +2554,7 @@ CALL [1] { function: !_ args: { IDENT [20] { - name: @x0:0 + name: @x:0 } } } @@ -2089,7 +2566,7 @@ CALL [1] { function: _||_ args: { IDENT [22] { - name: @x0:0 + name: @x:0 } CALL [23] { function: _>_ @@ -2098,7 +2575,7 @@ CALL [1] { function: _-_ args: { IDENT [25] { - name: @c0:0 + name: @c:0 } CONSTANT [26] { value: 1 } } @@ -2111,7 +2588,7 @@ CALL [1] { } result: { IDENT [28] { - name: @x0:0 + name: @x:0 } } } @@ -2134,10 +2611,10 @@ CALL [1] { function: _+_ args: { IDENT [4] { - name: @c1:0 + name: @c:0 } IDENT [5] { - name: @c1:0 + name: @c:0 } } } @@ -2145,20 +2622,20 @@ CALL [1] { function: _+_ args: { IDENT [7] { - name: @c0:0 + name: @c:1 } IDENT [8] { - name: @c0:0 + name: @c:1 } } } } } COMPREHENSION [9] { - iter_var: @c0:0 + iter_var: @c:1 iter_range: { COMPREHENSION [10] { - iter_var: @c1:0 + iter_var: @c:0 iter_range: { LIST [11] { elements: { @@ -2167,7 +2644,7 @@ CALL [1] { } } } - accu_var: @x1:0 + accu_var: @x:0 accu_init: { LIST [14] { elements: { @@ -2182,7 +2659,7 @@ CALL [1] { function: _+_ args: { IDENT [17] { - name: @x1:0 + name: @x:0 } LIST [18] { elements: { @@ -2203,12 +2680,12 @@ CALL [1] { } result: { IDENT [22] { - name: @x1:0 + name: @x:0 } } } } - accu_var: @x0:0 + accu_var: @x:1 accu_init: { LIST [23] { elements: { @@ -2223,7 +2700,7 @@ CALL [1] { function: _+_ args: { IDENT [26] { - name: @x0:0 + name: @x:1 } LIST [27] { elements: { @@ -2244,7 +2721,7 @@ CALL [1] { } result: { IDENT [31] { - name: @x0:0 + name: @x:1 } } } @@ -3198,4 +3675,4 @@ CALL [1] { } } } -} +} \ No newline at end of file diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_6.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_6.baseline index 0612d72aa..b68e6eaf1 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_6.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_6.baseline @@ -1145,61 +1145,270 @@ CALL [1] { args: { LIST [2] { elements: { - CALL [3] { - function: size + LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + } + } + LIST [5] { + elements: { + CONSTANT [6] { value: 2 } + } + } + CALL [7] { + function: _+_ args: { - LIST [4] { - elements: { - COMPREHENSION [5] { - iter_var: @c0:0 - iter_range: { - LIST [6] { - elements: { - CONSTANT [7] { value: 1 } + CALL [8] { + function: size + args: { + LIST [9] { + elements: { + COMPREHENSION [10] { + iter_var: @c:0 + iter_range: { + IDENT [11] { + name: @index0 + } + } + accu_var: @x:0 + accu_init: { + CONSTANT [12] { value: false } + } + loop_condition: { + CALL [13] { + function: @not_strictly_false + args: { + CALL [14] { + function: !_ + args: { + IDENT [15] { + name: @x:0 + } + } + } + } + } + } + loop_step: { + CALL [16] { + function: _||_ + args: { + IDENT [17] { + name: @x:0 + } + CALL [18] { + function: _>_ + args: { + IDENT [19] { + name: @c:0 + } + CONSTANT [20] { value: 0 } + } + } + } + } + } + result: { + IDENT [21] { + name: @x:0 + } } } } - accu_var: @x0:0 - accu_init: { - CONSTANT [8] { value: false } - } - loop_condition: { - CALL [9] { - function: @not_strictly_false - args: { - CALL [10] { - function: !_ + } + } + } + CALL [22] { + function: size + args: { + LIST [23] { + elements: { + COMPREHENSION [24] { + iter_var: @c:1 + iter_range: { + IDENT [25] { + name: @index0 + } + } + accu_var: @x:1 + accu_init: { + CONSTANT [26] { value: false } + } + loop_condition: { + CALL [27] { + function: @not_strictly_false + args: { + CALL [28] { + function: !_ + args: { + IDENT [29] { + name: @x:1 + } + } + } + } + } + } + loop_step: { + CALL [30] { + function: _||_ args: { - IDENT [11] { - name: @x0:0 + IDENT [31] { + name: @x:1 + } + CALL [32] { + function: _>_ + args: { + IDENT [33] { + name: @c:1 + } + CONSTANT [34] { value: 0 } + } } } } } + result: { + IDENT [35] { + name: @x:1 + } + } } } - loop_step: { - CALL [12] { - function: _||_ - args: { - IDENT [13] { - name: @x0:0 + } + } + } + } + } + CALL [36] { + function: _+_ + args: { + IDENT [37] { + name: @index2 + } + CALL [38] { + function: size + args: { + LIST [39] { + elements: { + COMPREHENSION [40] { + iter_var: @c:2 + iter_range: { + IDENT [41] { + name: @index1 } - CALL [14] { - function: _>_ + } + accu_var: @x:2 + accu_init: { + CONSTANT [42] { value: false } + } + loop_condition: { + CALL [43] { + function: @not_strictly_false args: { - IDENT [15] { - name: @c0:0 + CALL [44] { + function: !_ + args: { + IDENT [45] { + name: @x:2 + } + } + } + } + } + } + loop_step: { + CALL [46] { + function: _||_ + args: { + IDENT [47] { + name: @x:2 + } + CALL [48] { + function: _>_ + args: { + IDENT [49] { + name: @c:2 + } + CONSTANT [50] { value: 1 } + } } - CONSTANT [16] { value: 0 } } } } + result: { + IDENT [51] { + name: @x:2 + } + } } } - result: { - IDENT [17] { - name: @x0:0 + } + } + } + } + } + CALL [52] { + function: _+_ + args: { + IDENT [53] { + name: @index3 + } + CALL [54] { + function: size + args: { + LIST [55] { + elements: { + COMPREHENSION [56] { + iter_var: @c:3 + iter_range: { + IDENT [57] { + name: @index1 + } + } + accu_var: @x:3 + accu_init: { + CONSTANT [58] { value: false } + } + loop_condition: { + CALL [59] { + function: @not_strictly_false + args: { + CALL [60] { + function: !_ + args: { + IDENT [61] { + name: @x:3 + } + } + } + } + } + } + loop_step: { + CALL [62] { + function: _||_ + args: { + IDENT [63] { + name: @x:3 + } + CALL [64] { + function: _>_ + args: { + IDENT [65] { + name: @c:3 + } + CONSTANT [66] { value: 1 } + } + } + } + } + } + result: { + IDENT [67] { + name: @x:3 + } + } } } } @@ -1207,33 +1416,177 @@ CALL [1] { } } } - CALL [18] { - function: size + } + } + CALL [68] { + function: _==_ + args: { + IDENT [69] { + name: @index4 + } + CONSTANT [70] { value: 4 } + } + } + } +} +Test case: MULTIPLE_MACROS_2 +Source: [[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == 'a')] + [['a'].exists(l, l == 'a')] == [true, true, true, true] +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + } + } + LIST [5] { + elements: { + CONSTANT [6] { value: "a" } + } + } + CALL [7] { + function: _+_ args: { - LIST [19] { + CALL [8] { + function: _+_ + args: { + LIST [9] { + elements: { + COMPREHENSION [10] { + iter_var: @c:0 + iter_range: { + IDENT [11] { + name: @index0 + } + } + accu_var: @x:0 + accu_init: { + CONSTANT [12] { value: false } + } + loop_condition: { + CALL [13] { + function: @not_strictly_false + args: { + CALL [14] { + function: !_ + args: { + IDENT [15] { + name: @x:0 + } + } + } + } + } + } + loop_step: { + CALL [16] { + function: _||_ + args: { + IDENT [17] { + name: @x:0 + } + CALL [18] { + function: _>_ + args: { + IDENT [19] { + name: @c:0 + } + CONSTANT [20] { value: 0 } + } + } + } + } + } + result: { + IDENT [21] { + name: @x:0 + } + } + } + } + } + LIST [22] { + elements: { + COMPREHENSION [23] { + iter_var: @c:1 + iter_range: { + IDENT [24] { + name: @index0 + } + } + accu_var: @x:1 + accu_init: { + CONSTANT [25] { value: false } + } + loop_condition: { + CALL [26] { + function: @not_strictly_false + args: { + CALL [27] { + function: !_ + args: { + IDENT [28] { + name: @x:1 + } + } + } + } + } + } + loop_step: { + CALL [29] { + function: _||_ + args: { + IDENT [30] { + name: @x:1 + } + CALL [31] { + function: _>_ + args: { + IDENT [32] { + name: @c:1 + } + CONSTANT [33] { value: 0 } + } + } + } + } + } + result: { + IDENT [34] { + name: @x:1 + } + } + } + } + } + } + } + LIST [35] { elements: { - COMPREHENSION [20] { - iter_var: @c0:0 + COMPREHENSION [36] { + iter_var: @c:2 iter_range: { - LIST [21] { - elements: { - CONSTANT [22] { value: 2 } - } + IDENT [37] { + name: @index1 } } - accu_var: @x0:0 + accu_var: @x:2 accu_init: { - CONSTANT [23] { value: false } + CONSTANT [38] { value: false } } loop_condition: { - CALL [24] { + CALL [39] { function: @not_strictly_false args: { - CALL [25] { + CALL [40] { function: !_ args: { - IDENT [26] { - name: @x0:0 + IDENT [41] { + name: @x:2 } } } @@ -1241,27 +1594,27 @@ CALL [1] { } } loop_step: { - CALL [27] { + CALL [42] { function: _||_ args: { - IDENT [28] { - name: @x0:0 + IDENT [43] { + name: @x:2 } - CALL [29] { - function: _>_ + CALL [44] { + function: _==_ args: { - IDENT [30] { - name: @c0:0 + IDENT [45] { + name: @c:2 } - CONSTANT [31] { value: 1 } + CONSTANT [46] { value: "a" } } } } } } result: { - IDENT [32] { - name: @x0:0 + IDENT [47] { + name: @x:2 } } } @@ -1271,43 +1624,86 @@ CALL [1] { } } } - CALL [33] { + CALL [48] { function: _==_ args: { - CALL [34] { + CALL [49] { function: _+_ args: { - CALL [35] { - function: _+_ - args: { - CALL [36] { - function: _+_ - args: { - IDENT [37] { - name: @index0 + IDENT [50] { + name: @index2 + } + LIST [51] { + elements: { + COMPREHENSION [52] { + iter_var: @c:3 + iter_range: { + IDENT [53] { + name: @index1 } - IDENT [38] { - name: @index0 + } + accu_var: @x:3 + accu_init: { + CONSTANT [54] { value: false } + } + loop_condition: { + CALL [55] { + function: @not_strictly_false + args: { + CALL [56] { + function: !_ + args: { + IDENT [57] { + name: @x:3 + } + } + } + } + } + } + loop_step: { + CALL [58] { + function: _||_ + args: { + IDENT [59] { + name: @x:3 + } + CALL [60] { + function: _==_ + args: { + IDENT [61] { + name: @c:3 + } + CONSTANT [62] { value: "a" } + } + } + } + } + } + result: { + IDENT [63] { + name: @x:3 } } - } - IDENT [39] { - name: @index1 } } } - IDENT [40] { - name: @index1 - } } } - CONSTANT [41] { value: 4 } + LIST [64] { + elements: { + CONSTANT [65] { value: true } + CONSTANT [66] { value: true } + CONSTANT [67] { value: true } + CONSTANT [68] { value: true } + } + } } } } } -Test case: MULTIPLE_MACROS_2 -Source: [[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == 'a')] + [['a'].exists(l, l == 'a')] == [true, true, true, true] +Test case: MULTIPLE_MACROS_3 +Source: [1].exists(i, i > 0) && [1].exists(j, j > 0) && [1].exists(k, k > 1) && [2].exists(l, l > 1) =====> CALL [1] { function: cel.@block @@ -1316,28 +1712,37 @@ CALL [1] { elements: { LIST [3] { elements: { - COMPREHENSION [4] { - iter_var: @c0:0 + CONSTANT [4] { value: 1 } + } + } + } + } + CALL [5] { + function: _&&_ + args: { + CALL [6] { + function: _&&_ + args: { + COMPREHENSION [7] { + iter_var: @c:0 iter_range: { - LIST [5] { - elements: { - CONSTANT [6] { value: 1 } - } + IDENT [8] { + name: @index0 } } - accu_var: @x0:0 + accu_var: @x:0 accu_init: { - CONSTANT [7] { value: false } + CONSTANT [9] { value: false } } loop_condition: { - CALL [8] { + CALL [10] { function: @not_strictly_false args: { - CALL [9] { + CALL [11] { function: !_ args: { - IDENT [10] { - name: @x0:0 + IDENT [12] { + name: @x:0 } } } @@ -1345,44 +1750,38 @@ CALL [1] { } } loop_step: { - CALL [11] { + CALL [13] { function: _||_ args: { - IDENT [12] { - name: @x0:0 + IDENT [14] { + name: @x:0 } - CALL [13] { + CALL [15] { function: _>_ args: { - IDENT [14] { - name: @c0:0 + IDENT [16] { + name: @c:0 } - CONSTANT [15] { value: 0 } + CONSTANT [17] { value: 0 } } } } } } result: { - IDENT [16] { - name: @x0:0 + IDENT [18] { + name: @x:0 } } } - } - } - LIST [17] { - elements: { - COMPREHENSION [18] { - iter_var: @c0:1 + COMPREHENSION [19] { + iter_var: @c:1 iter_range: { - LIST [19] { - elements: { - CONSTANT [20] { value: "a" } - } + IDENT [20] { + name: @index0 } } - accu_var: @x0:1 + accu_var: @x:1 accu_init: { CONSTANT [21] { value: false } } @@ -1394,7 +1793,7 @@ CALL [1] { function: !_ args: { IDENT [24] { - name: @x0:1 + name: @x:1 } } } @@ -1406,15 +1805,15 @@ CALL [1] { function: _||_ args: { IDENT [26] { - name: @x0:1 + name: @x:1 } CALL [27] { - function: _==_ + function: _>_ args: { IDENT [28] { - name: @c0:1 + name: @c:1 } - CONSTANT [29] { value: "a" } + CONSTANT [29] { value: 0 } } } } @@ -1422,52 +1821,121 @@ CALL [1] { } result: { IDENT [30] { - name: @x0:1 + name: @x:1 } } } } } - } - } - CALL [31] { - function: _==_ - args: { - CALL [32] { - function: _+_ + CALL [31] { + function: _&&_ args: { - CALL [33] { - function: _+_ - args: { - CALL [34] { - function: _+_ + COMPREHENSION [32] { + iter_var: @c:2 + iter_range: { + IDENT [33] { + name: @index0 + } + } + accu_var: @x:2 + accu_init: { + CONSTANT [34] { value: false } + } + loop_condition: { + CALL [35] { + function: @not_strictly_false args: { - IDENT [35] { - name: @index0 + CALL [36] { + function: !_ + args: { + IDENT [37] { + name: @x:2 + } + } } - IDENT [36] { - name: @index0 + } + } + } + loop_step: { + CALL [38] { + function: _||_ + args: { + IDENT [39] { + name: @x:2 + } + CALL [40] { + function: _>_ + args: { + IDENT [41] { + name: @c:2 + } + CONSTANT [42] { value: 1 } + } } } } - IDENT [37] { - name: @index1 + } + result: { + IDENT [43] { + name: @x:2 } } } - IDENT [38] { - name: @index1 + COMPREHENSION [44] { + iter_var: @c:3 + iter_range: { + LIST [45] { + elements: { + CONSTANT [46] { value: 2 } + } + } + } + accu_var: @x:3 + accu_init: { + CONSTANT [47] { value: false } + } + loop_condition: { + CALL [48] { + function: @not_strictly_false + args: { + CALL [49] { + function: !_ + args: { + IDENT [50] { + name: @x:3 + } + } + } + } + } + } + loop_step: { + CALL [51] { + function: _||_ + args: { + IDENT [52] { + name: @x:3 + } + CALL [53] { + function: _>_ + args: { + IDENT [54] { + name: @c:3 + } + CONSTANT [55] { value: 1 } + } + } + } + } + } + result: { + IDENT [56] { + name: @x:3 + } + } } } } - LIST [39] { - elements: { - CONSTANT [40] { value: true } - CONSTANT [41] { value: true } - CONSTANT [42] { value: true } - CONSTANT [43] { value: true } - } - } } } } @@ -1498,18 +1966,18 @@ CALL [1] { function: _+_ args: { IDENT [12] { - name: @x0:0 + name: @x:1 } LIST [13] { elements: { COMPREHENSION [14] { - iter_var: @c1:0 + iter_var: @c:0 iter_range: { IDENT [15] { name: @index0 } } - accu_var: @x1:0 + accu_var: @x:0 accu_init: { LIST [16] { elements: { @@ -1524,7 +1992,7 @@ CALL [1] { function: _+_ args: { IDENT [19] { - name: @x1:0 + name: @x:0 } LIST [20] { elements: { @@ -1532,7 +2000,7 @@ CALL [1] { function: _+_ args: { IDENT [22] { - name: @c1:0 + name: @c:0 } CONSTANT [23] { value: 1 } } @@ -1544,7 +2012,7 @@ CALL [1] { } result: { IDENT [24] { - name: @x1:0 + name: @x:0 } } } @@ -1558,13 +2026,13 @@ CALL [1] { function: _==_ args: { COMPREHENSION [26] { - iter_var: @c0:0 + iter_var: @c:1 iter_range: { IDENT [27] { name: @index0 } } - accu_var: @x0:0 + accu_var: @x:1 accu_init: { LIST [28] { elements: { @@ -1581,7 +2049,7 @@ CALL [1] { } result: { IDENT [31] { - name: @x0:0 + name: @x:1 } } } @@ -1614,12 +2082,12 @@ CALL [1] { function: _+_ args: { IDENT [4] { - name: @x0:0 + name: @x:1 } LIST [5] { elements: { COMPREHENSION [6] { - iter_var: @c1:0 + iter_var: @c:0 iter_range: { LIST [7] { elements: { @@ -1629,7 +2097,7 @@ CALL [1] { } } } - accu_var: @x1:0 + accu_var: @x:0 accu_init: { LIST [11] { elements: { @@ -1647,10 +2115,10 @@ CALL [1] { function: _==_ args: { IDENT [15] { - name: @c1:0 + name: @c:0 } IDENT [16] { - name: @c0:0 + name: @c:1 } } } @@ -1658,26 +2126,26 @@ CALL [1] { function: _+_ args: { IDENT [18] { - name: @x1:0 + name: @x:0 } LIST [19] { elements: { IDENT [20] { - name: @c1:0 + name: @c:0 } } } } } IDENT [21] { - name: @x1:0 + name: @x:0 } } } } result: { IDENT [22] { - name: @x1:0 + name: @x:0 } } } @@ -1691,7 +2159,7 @@ CALL [1] { function: _==_ args: { COMPREHENSION [24] { - iter_var: @c0:0 + iter_var: @c:1 iter_range: { LIST [25] { elements: { @@ -1700,7 +2168,7 @@ CALL [1] { } } } - accu_var: @x0:0 + accu_var: @x:1 accu_init: { LIST [28] { elements: { @@ -1717,7 +2185,7 @@ CALL [1] { } result: { IDENT [31] { - name: @x0:0 + name: @x:1 } } } @@ -1907,18 +2375,18 @@ CALL [1] { function: _+_ args: { IDENT [14] { - name: @x0:0 + name: @x:1 } LIST [15] { elements: { COMPREHENSION [16] { - iter_var: @c1:0 + iter_var: @c:0 iter_range: { IDENT [17] { name: @index1 } } - accu_var: @x1:0 + accu_var: @x:0 accu_init: { LIST [18] { elements: { @@ -1933,7 +2401,7 @@ CALL [1] { function: _+_ args: { IDENT [21] { - name: @x1:0 + name: @x:0 } LIST [22] { elements: { @@ -1950,7 +2418,7 @@ CALL [1] { } result: { IDENT [26] { - name: @x1:0 + name: @x:0 } } } @@ -1964,13 +2432,13 @@ CALL [1] { function: _==_ args: { COMPREHENSION [28] { - iter_var: @c0:0 + iter_var: @c:1 iter_range: { IDENT [29] { name: @index1 } } - accu_var: @x0:0 + accu_var: @x:1 accu_init: { LIST [30] { elements: { @@ -1987,7 +2455,7 @@ CALL [1] { } result: { IDENT [33] { - name: @x0:0 + name: @x:1 } } } @@ -2034,7 +2502,7 @@ CALL [1] { function: _||_ args: { COMPREHENSION [9] { - iter_var: @c0:0 + iter_var: @c:0 iter_range: { LIST [10] { elements: { @@ -2059,7 +2527,7 @@ CALL [1] { } } } - accu_var: @x0:0 + accu_var: @x:0 accu_init: { CONSTANT [17] { value: false } } @@ -2071,7 +2539,7 @@ CALL [1] { function: !_ args: { IDENT [20] { - name: @x0:0 + name: @x:0 } } } @@ -2083,7 +2551,7 @@ CALL [1] { function: _||_ args: { IDENT [22] { - name: @x0:0 + name: @x:0 } CALL [23] { function: _>_ @@ -2092,7 +2560,7 @@ CALL [1] { function: _-_ args: { IDENT [25] { - name: @c0:0 + name: @c:0 } CONSTANT [26] { value: 1 } } @@ -2105,7 +2573,7 @@ CALL [1] { } result: { IDENT [28] { - name: @x0:0 + name: @x:0 } } } @@ -2128,10 +2596,10 @@ CALL [1] { function: _+_ args: { IDENT [4] { - name: @c1:0 + name: @c:0 } IDENT [5] { - name: @c1:0 + name: @c:0 } } } @@ -2139,20 +2607,20 @@ CALL [1] { function: _+_ args: { IDENT [7] { - name: @c0:0 + name: @c:1 } IDENT [8] { - name: @c0:0 + name: @c:1 } } } } } COMPREHENSION [9] { - iter_var: @c0:0 + iter_var: @c:1 iter_range: { COMPREHENSION [10] { - iter_var: @c1:0 + iter_var: @c:0 iter_range: { LIST [11] { elements: { @@ -2161,7 +2629,7 @@ CALL [1] { } } } - accu_var: @x1:0 + accu_var: @x:0 accu_init: { LIST [14] { elements: { @@ -2176,7 +2644,7 @@ CALL [1] { function: _+_ args: { IDENT [17] { - name: @x1:0 + name: @x:0 } LIST [18] { elements: { @@ -2197,12 +2665,12 @@ CALL [1] { } result: { IDENT [22] { - name: @x1:0 + name: @x:0 } } } } - accu_var: @x0:0 + accu_var: @x:1 accu_init: { LIST [23] { elements: { @@ -2217,7 +2685,7 @@ CALL [1] { function: _+_ args: { IDENT [26] { - name: @x0:0 + name: @x:1 } LIST [27] { elements: { @@ -2238,7 +2706,7 @@ CALL [1] { } result: { IDENT [31] { - name: @x0:0 + name: @x:1 } } } @@ -3165,4 +3633,4 @@ CALL [1] { } } } -} +} \ No newline at end of file diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_7.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_7.baseline index eee2b9b4a..410c1ff1a 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_7.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_7.baseline @@ -1142,61 +1142,272 @@ CALL [1] { args: { LIST [2] { elements: { - CALL [3] { - function: size + LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + } + } + LIST [5] { + elements: { + CONSTANT [6] { value: 2 } + } + } + CALL [7] { + function: _+_ args: { - LIST [4] { - elements: { - COMPREHENSION [5] { - iter_var: @c0:0 - iter_range: { - LIST [6] { + CALL [8] { + function: _+_ + args: { + CALL [9] { + function: size + args: { + LIST [10] { elements: { - CONSTANT [7] { value: 1 } + COMPREHENSION [11] { + iter_var: @c:0 + iter_range: { + IDENT [12] { + name: @index0 + } + } + accu_var: @x:0 + accu_init: { + CONSTANT [13] { value: false } + } + loop_condition: { + CALL [14] { + function: @not_strictly_false + args: { + CALL [15] { + function: !_ + args: { + IDENT [16] { + name: @x:0 + } + } + } + } + } + } + loop_step: { + CALL [17] { + function: _||_ + args: { + IDENT [18] { + name: @x:0 + } + CALL [19] { + function: _>_ + args: { + IDENT [20] { + name: @c:0 + } + CONSTANT [21] { value: 0 } + } + } + } + } + } + result: { + IDENT [22] { + name: @x:0 + } + } + } } } } - accu_var: @x0:0 - accu_init: { - CONSTANT [8] { value: false } - } - loop_condition: { - CALL [9] { - function: @not_strictly_false - args: { - CALL [10] { - function: !_ - args: { - IDENT [11] { - name: @x0:0 + } + CALL [23] { + function: size + args: { + LIST [24] { + elements: { + COMPREHENSION [25] { + iter_var: @c:1 + iter_range: { + IDENT [26] { + name: @index0 + } + } + accu_var: @x:1 + accu_init: { + CONSTANT [27] { value: false } + } + loop_condition: { + CALL [28] { + function: @not_strictly_false + args: { + CALL [29] { + function: !_ + args: { + IDENT [30] { + name: @x:1 + } + } + } + } + } + } + loop_step: { + CALL [31] { + function: _||_ + args: { + IDENT [32] { + name: @x:1 + } + CALL [33] { + function: _>_ + args: { + IDENT [34] { + name: @c:1 + } + CONSTANT [35] { value: 0 } + } + } + } + } + } + result: { + IDENT [36] { + name: @x:1 } } } } } } - loop_step: { - CALL [12] { - function: _||_ - args: { - IDENT [13] { - name: @x0:0 + } + } + } + CALL [37] { + function: size + args: { + LIST [38] { + elements: { + COMPREHENSION [39] { + iter_var: @c:2 + iter_range: { + IDENT [40] { + name: @index1 + } + } + accu_var: @x:2 + accu_init: { + CONSTANT [41] { value: false } + } + loop_condition: { + CALL [42] { + function: @not_strictly_false + args: { + CALL [43] { + function: !_ + args: { + IDENT [44] { + name: @x:2 + } + } + } + } } - CALL [14] { - function: _>_ + } + loop_step: { + CALL [45] { + function: _||_ args: { - IDENT [15] { - name: @c0:0 + IDENT [46] { + name: @x:2 + } + CALL [47] { + function: _>_ + args: { + IDENT [48] { + name: @c:2 + } + CONSTANT [49] { value: 1 } + } } - CONSTANT [16] { value: 0 } } } } + result: { + IDENT [50] { + name: @x:2 + } + } } } - result: { - IDENT [17] { - name: @x0:0 + } + } + } + } + } + } + } + CALL [51] { + function: _==_ + args: { + CALL [52] { + function: _+_ + args: { + IDENT [53] { + name: @index2 + } + CALL [54] { + function: size + args: { + LIST [55] { + elements: { + COMPREHENSION [56] { + iter_var: @c:3 + iter_range: { + IDENT [57] { + name: @index1 + } + } + accu_var: @x:3 + accu_init: { + CONSTANT [58] { value: false } + } + loop_condition: { + CALL [59] { + function: @not_strictly_false + args: { + CALL [60] { + function: !_ + args: { + IDENT [61] { + name: @x:3 + } + } + } + } + } + } + loop_step: { + CALL [62] { + function: _||_ + args: { + IDENT [63] { + name: @x:3 + } + CALL [64] { + function: _>_ + args: { + IDENT [65] { + name: @c:3 + } + CONSTANT [66] { value: 1 } + } + } + } + } + } + result: { + IDENT [67] { + name: @x:3 + } + } } } } @@ -1204,33 +1415,229 @@ CALL [1] { } } } - CALL [18] { - function: size + CONSTANT [68] { value: 4 } + } + } + } +} +Test case: MULTIPLE_MACROS_2 +Source: [[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == 'a')] + [['a'].exists(l, l == 'a')] == [true, true, true, true] +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + } + } + LIST [5] { + elements: { + CONSTANT [6] { value: "a" } + } + } + CALL [7] { + function: _+_ args: { - LIST [19] { - elements: { - COMPREHENSION [20] { - iter_var: @c0:0 - iter_range: { - LIST [21] { + CALL [8] { + function: _+_ + args: { + CALL [9] { + function: _+_ + args: { + LIST [10] { elements: { - CONSTANT [22] { value: 2 } + COMPREHENSION [11] { + iter_var: @c:0 + iter_range: { + IDENT [12] { + name: @index0 + } + } + accu_var: @x:0 + accu_init: { + CONSTANT [13] { value: false } + } + loop_condition: { + CALL [14] { + function: @not_strictly_false + args: { + CALL [15] { + function: !_ + args: { + IDENT [16] { + name: @x:0 + } + } + } + } + } + } + loop_step: { + CALL [17] { + function: _||_ + args: { + IDENT [18] { + name: @x:0 + } + CALL [19] { + function: _>_ + args: { + IDENT [20] { + name: @c:0 + } + CONSTANT [21] { value: 0 } + } + } + } + } + } + result: { + IDENT [22] { + name: @x:0 + } + } + } } } + LIST [23] { + elements: { + COMPREHENSION [24] { + iter_var: @c:1 + iter_range: { + IDENT [25] { + name: @index0 + } + } + accu_var: @x:1 + accu_init: { + CONSTANT [26] { value: false } + } + loop_condition: { + CALL [27] { + function: @not_strictly_false + args: { + CALL [28] { + function: !_ + args: { + IDENT [29] { + name: @x:1 + } + } + } + } + } + } + loop_step: { + CALL [30] { + function: _||_ + args: { + IDENT [31] { + name: @x:1 + } + CALL [32] { + function: _>_ + args: { + IDENT [33] { + name: @c:1 + } + CONSTANT [34] { value: 0 } + } + } + } + } + } + result: { + IDENT [35] { + name: @x:1 + } + } + } + } + } + } + } + LIST [36] { + elements: { + COMPREHENSION [37] { + iter_var: @c:2 + iter_range: { + IDENT [38] { + name: @index1 + } + } + accu_var: @x:2 + accu_init: { + CONSTANT [39] { value: false } + } + loop_condition: { + CALL [40] { + function: @not_strictly_false + args: { + CALL [41] { + function: !_ + args: { + IDENT [42] { + name: @x:2 + } + } + } + } + } + } + loop_step: { + CALL [43] { + function: _||_ + args: { + IDENT [44] { + name: @x:2 + } + CALL [45] { + function: _==_ + args: { + IDENT [46] { + name: @c:2 + } + CONSTANT [47] { value: "a" } + } + } + } + } + } + result: { + IDENT [48] { + name: @x:2 + } + } + } + } + } + } + } + LIST [49] { + elements: { + COMPREHENSION [50] { + iter_var: @c:3 + iter_range: { + IDENT [51] { + name: @index1 + } } - accu_var: @x0:0 + accu_var: @x:3 accu_init: { - CONSTANT [23] { value: false } + CONSTANT [52] { value: false } } loop_condition: { - CALL [24] { + CALL [53] { function: @not_strictly_false args: { - CALL [25] { + CALL [54] { function: !_ args: { - IDENT [26] { - name: @x0:0 + IDENT [55] { + name: @x:3 } } } @@ -1238,27 +1645,27 @@ CALL [1] { } } loop_step: { - CALL [27] { + CALL [56] { function: _||_ args: { - IDENT [28] { - name: @x0:0 + IDENT [57] { + name: @x:3 } - CALL [29] { - function: _>_ + CALL [58] { + function: _==_ args: { - IDENT [30] { - name: @c0:0 + IDENT [59] { + name: @c:3 } - CONSTANT [31] { value: 1 } + CONSTANT [60] { value: "a" } } } } } } result: { - IDENT [32] { - name: @x0:0 + IDENT [61] { + name: @x:3 } } } @@ -1268,43 +1675,26 @@ CALL [1] { } } } - CALL [33] { + CALL [62] { function: _==_ args: { - CALL [34] { - function: _+_ - args: { - CALL [35] { - function: _+_ - args: { - CALL [36] { - function: _+_ - args: { - IDENT [37] { - name: @index0 - } - IDENT [38] { - name: @index0 - } - } - } - IDENT [39] { - name: @index1 - } - } - } - IDENT [40] { - name: @index1 - } + IDENT [63] { + name: @index2 + } + LIST [64] { + elements: { + CONSTANT [65] { value: true } + CONSTANT [66] { value: true } + CONSTANT [67] { value: true } + CONSTANT [68] { value: true } } } - CONSTANT [41] { value: 4 } } } } } -Test case: MULTIPLE_MACROS_2 -Source: [[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == 'a')] + [['a'].exists(l, l == 'a')] == [true, true, true, true] +Test case: MULTIPLE_MACROS_3 +Source: [1].exists(i, i > 0) && [1].exists(j, j > 0) && [1].exists(k, k > 1) && [2].exists(l, l > 1) =====> CALL [1] { function: cel.@block @@ -1313,28 +1703,37 @@ CALL [1] { elements: { LIST [3] { elements: { - COMPREHENSION [4] { - iter_var: @c0:0 + CONSTANT [4] { value: 1 } + } + } + } + } + CALL [5] { + function: _&&_ + args: { + CALL [6] { + function: _&&_ + args: { + COMPREHENSION [7] { + iter_var: @c:0 iter_range: { - LIST [5] { - elements: { - CONSTANT [6] { value: 1 } - } + IDENT [8] { + name: @index0 } } - accu_var: @x0:0 + accu_var: @x:0 accu_init: { - CONSTANT [7] { value: false } + CONSTANT [9] { value: false } } loop_condition: { - CALL [8] { + CALL [10] { function: @not_strictly_false args: { - CALL [9] { + CALL [11] { function: !_ args: { - IDENT [10] { - name: @x0:0 + IDENT [12] { + name: @x:0 } } } @@ -1342,44 +1741,38 @@ CALL [1] { } } loop_step: { - CALL [11] { + CALL [13] { function: _||_ args: { - IDENT [12] { - name: @x0:0 + IDENT [14] { + name: @x:0 } - CALL [13] { + CALL [15] { function: _>_ args: { - IDENT [14] { - name: @c0:0 + IDENT [16] { + name: @c:0 } - CONSTANT [15] { value: 0 } + CONSTANT [17] { value: 0 } } } } } } result: { - IDENT [16] { - name: @x0:0 + IDENT [18] { + name: @x:0 } } } - } - } - LIST [17] { - elements: { - COMPREHENSION [18] { - iter_var: @c0:1 + COMPREHENSION [19] { + iter_var: @c:1 iter_range: { - LIST [19] { - elements: { - CONSTANT [20] { value: "a" } - } + IDENT [20] { + name: @index0 } } - accu_var: @x0:1 + accu_var: @x:1 accu_init: { CONSTANT [21] { value: false } } @@ -1391,7 +1784,7 @@ CALL [1] { function: !_ args: { IDENT [24] { - name: @x0:1 + name: @x:1 } } } @@ -1403,15 +1796,15 @@ CALL [1] { function: _||_ args: { IDENT [26] { - name: @x0:1 + name: @x:1 } CALL [27] { - function: _==_ + function: _>_ args: { IDENT [28] { - name: @c0:1 + name: @c:1 } - CONSTANT [29] { value: "a" } + CONSTANT [29] { value: 0 } } } } @@ -1419,52 +1812,121 @@ CALL [1] { } result: { IDENT [30] { - name: @x0:1 + name: @x:1 } } } } } - } - } - CALL [31] { - function: _==_ - args: { - CALL [32] { - function: _+_ + CALL [31] { + function: _&&_ args: { - CALL [33] { - function: _+_ - args: { - CALL [34] { - function: _+_ + COMPREHENSION [32] { + iter_var: @c:2 + iter_range: { + IDENT [33] { + name: @index0 + } + } + accu_var: @x:2 + accu_init: { + CONSTANT [34] { value: false } + } + loop_condition: { + CALL [35] { + function: @not_strictly_false args: { - IDENT [35] { - name: @index0 + CALL [36] { + function: !_ + args: { + IDENT [37] { + name: @x:2 + } + } } - IDENT [36] { - name: @index0 + } + } + } + loop_step: { + CALL [38] { + function: _||_ + args: { + IDENT [39] { + name: @x:2 + } + CALL [40] { + function: _>_ + args: { + IDENT [41] { + name: @c:2 + } + CONSTANT [42] { value: 1 } + } } } } - IDENT [37] { - name: @index1 + } + result: { + IDENT [43] { + name: @x:2 } } } - IDENT [38] { - name: @index1 + COMPREHENSION [44] { + iter_var: @c:3 + iter_range: { + LIST [45] { + elements: { + CONSTANT [46] { value: 2 } + } + } + } + accu_var: @x:3 + accu_init: { + CONSTANT [47] { value: false } + } + loop_condition: { + CALL [48] { + function: @not_strictly_false + args: { + CALL [49] { + function: !_ + args: { + IDENT [50] { + name: @x:3 + } + } + } + } + } + } + loop_step: { + CALL [51] { + function: _||_ + args: { + IDENT [52] { + name: @x:3 + } + CALL [53] { + function: _>_ + args: { + IDENT [54] { + name: @c:3 + } + CONSTANT [55] { value: 1 } + } + } + } + } + } + result: { + IDENT [56] { + name: @x:3 + } + } } } } - LIST [39] { - elements: { - CONSTANT [40] { value: true } - CONSTANT [41] { value: true } - CONSTANT [42] { value: true } - CONSTANT [43] { value: true } - } - } } } } @@ -1492,13 +1954,13 @@ CALL [1] { } } COMPREHENSION [11] { - iter_var: @c0:0 + iter_var: @c:1 iter_range: { IDENT [12] { name: @index0 } } - accu_var: @x0:0 + accu_var: @x:1 accu_init: { LIST [13] { elements: { @@ -1513,18 +1975,18 @@ CALL [1] { function: _+_ args: { IDENT [16] { - name: @x0:0 + name: @x:1 } LIST [17] { elements: { COMPREHENSION [18] { - iter_var: @c1:0 + iter_var: @c:0 iter_range: { IDENT [19] { name: @index0 } } - accu_var: @x1:0 + accu_var: @x:0 accu_init: { LIST [20] { elements: { @@ -1539,7 +2001,7 @@ CALL [1] { function: _+_ args: { IDENT [23] { - name: @x1:0 + name: @x:0 } LIST [24] { elements: { @@ -1547,7 +2009,7 @@ CALL [1] { function: _+_ args: { IDENT [26] { - name: @c1:0 + name: @c:0 } CONSTANT [27] { value: 1 } } @@ -1559,7 +2021,7 @@ CALL [1] { } result: { IDENT [28] { - name: @x1:0 + name: @x:0 } } } @@ -1570,7 +2032,7 @@ CALL [1] { } result: { IDENT [29] { - name: @x0:0 + name: @x:1 } } } @@ -1608,7 +2070,7 @@ CALL [1] { LIST [2] { elements: { COMPREHENSION [3] { - iter_var: @c0:0 + iter_var: @c:1 iter_range: { LIST [4] { elements: { @@ -1617,7 +2079,7 @@ CALL [1] { } } } - accu_var: @x0:0 + accu_var: @x:1 accu_init: { LIST [7] { elements: { @@ -1632,12 +2094,12 @@ CALL [1] { function: _+_ args: { IDENT [10] { - name: @x0:0 + name: @x:1 } LIST [11] { elements: { COMPREHENSION [12] { - iter_var: @c1:0 + iter_var: @c:0 iter_range: { LIST [13] { elements: { @@ -1647,7 +2109,7 @@ CALL [1] { } } } - accu_var: @x1:0 + accu_var: @x:0 accu_init: { LIST [17] { elements: { @@ -1665,10 +2127,10 @@ CALL [1] { function: _==_ args: { IDENT [21] { - name: @c1:0 + name: @c:0 } IDENT [22] { - name: @c0:0 + name: @c:1 } } } @@ -1676,26 +2138,26 @@ CALL [1] { function: _+_ args: { IDENT [24] { - name: @x1:0 + name: @x:0 } LIST [25] { elements: { IDENT [26] { - name: @c1:0 + name: @c:0 } } } } } IDENT [27] { - name: @x1:0 + name: @x:0 } } } } result: { IDENT [28] { - name: @x1:0 + name: @x:0 } } } @@ -1706,7 +2168,7 @@ CALL [1] { } result: { IDENT [29] { - name: @x0:0 + name: @x:1 } } } @@ -1901,13 +2363,13 @@ CALL [1] { } } COMPREHENSION [13] { - iter_var: @c0:0 + iter_var: @c:1 iter_range: { IDENT [14] { name: @index1 } } - accu_var: @x0:0 + accu_var: @x:1 accu_init: { LIST [15] { elements: { @@ -1922,18 +2384,18 @@ CALL [1] { function: _+_ args: { IDENT [18] { - name: @x0:0 + name: @x:1 } LIST [19] { elements: { COMPREHENSION [20] { - iter_var: @c1:0 + iter_var: @c:0 iter_range: { IDENT [21] { name: @index1 } } - accu_var: @x1:0 + accu_var: @x:0 accu_init: { LIST [22] { elements: { @@ -1948,7 +2410,7 @@ CALL [1] { function: _+_ args: { IDENT [25] { - name: @x1:0 + name: @x:0 } LIST [26] { elements: { @@ -1965,7 +2427,7 @@ CALL [1] { } result: { IDENT [30] { - name: @x1:0 + name: @x:0 } } } @@ -1976,7 +2438,7 @@ CALL [1] { } result: { IDENT [31] { - name: @x0:0 + name: @x:1 } } } @@ -2031,7 +2493,7 @@ CALL [1] { function: _||_ args: { COMPREHENSION [9] { - iter_var: @c0:0 + iter_var: @c:0 iter_range: { LIST [10] { elements: { @@ -2056,7 +2518,7 @@ CALL [1] { } } } - accu_var: @x0:0 + accu_var: @x:0 accu_init: { CONSTANT [17] { value: false } } @@ -2068,7 +2530,7 @@ CALL [1] { function: !_ args: { IDENT [20] { - name: @x0:0 + name: @x:0 } } } @@ -2080,7 +2542,7 @@ CALL [1] { function: _||_ args: { IDENT [22] { - name: @x0:0 + name: @x:0 } CALL [23] { function: _>_ @@ -2089,7 +2551,7 @@ CALL [1] { function: _-_ args: { IDENT [25] { - name: @c0:0 + name: @c:0 } CONSTANT [26] { value: 1 } } @@ -2102,7 +2564,7 @@ CALL [1] { } result: { IDENT [28] { - name: @x0:0 + name: @x:0 } } } @@ -2125,10 +2587,10 @@ CALL [1] { function: _+_ args: { IDENT [4] { - name: @c1:0 + name: @c:0 } IDENT [5] { - name: @c1:0 + name: @c:0 } } } @@ -2136,20 +2598,20 @@ CALL [1] { function: _+_ args: { IDENT [7] { - name: @c0:0 + name: @c:1 } IDENT [8] { - name: @c0:0 + name: @c:1 } } } } } COMPREHENSION [9] { - iter_var: @c0:0 + iter_var: @c:1 iter_range: { COMPREHENSION [10] { - iter_var: @c1:0 + iter_var: @c:0 iter_range: { LIST [11] { elements: { @@ -2158,7 +2620,7 @@ CALL [1] { } } } - accu_var: @x1:0 + accu_var: @x:0 accu_init: { LIST [14] { elements: { @@ -2173,7 +2635,7 @@ CALL [1] { function: _+_ args: { IDENT [17] { - name: @x1:0 + name: @x:0 } LIST [18] { elements: { @@ -2194,12 +2656,12 @@ CALL [1] { } result: { IDENT [22] { - name: @x1:0 + name: @x:0 } } } } - accu_var: @x0:0 + accu_var: @x:1 accu_init: { LIST [23] { elements: { @@ -2214,7 +2676,7 @@ CALL [1] { function: _+_ args: { IDENT [26] { - name: @x0:0 + name: @x:1 } LIST [27] { elements: { @@ -2235,7 +2697,7 @@ CALL [1] { } result: { IDENT [31] { - name: @x0:0 + name: @x:1 } } } @@ -3159,4 +3621,4 @@ CALL [1] { } } } -} +} \ No newline at end of file diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_8.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_8.baseline index 8e9897902..d8c949600 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_8.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_8.baseline @@ -1142,61 +1142,264 @@ CALL [1] { args: { LIST [2] { elements: { - CALL [3] { - function: size + LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + } + } + LIST [5] { + elements: { + CONSTANT [6] { value: 2 } + } + } + CALL [7] { + function: _+_ args: { - LIST [4] { - elements: { - COMPREHENSION [5] { - iter_var: @c0:0 - iter_range: { - LIST [6] { - elements: { - CONSTANT [7] { value: 1 } + CALL [8] { + function: _+_ + args: { + CALL [9] { + function: _+_ + args: { + CALL [10] { + function: size + args: { + LIST [11] { + elements: { + COMPREHENSION [12] { + iter_var: @c:0 + iter_range: { + IDENT [13] { + name: @index0 + } + } + accu_var: @x:0 + accu_init: { + CONSTANT [14] { value: false } + } + loop_condition: { + CALL [15] { + function: @not_strictly_false + args: { + CALL [16] { + function: !_ + args: { + IDENT [17] { + name: @x:0 + } + } + } + } + } + } + loop_step: { + CALL [18] { + function: _||_ + args: { + IDENT [19] { + name: @x:0 + } + CALL [20] { + function: _>_ + args: { + IDENT [21] { + name: @c:0 + } + CONSTANT [22] { value: 0 } + } + } + } + } + } + result: { + IDENT [23] { + name: @x:0 + } + } + } + } + } } } - } - accu_var: @x0:0 - accu_init: { - CONSTANT [8] { value: false } - } - loop_condition: { - CALL [9] { - function: @not_strictly_false + CALL [24] { + function: size args: { - CALL [10] { - function: !_ - args: { - IDENT [11] { - name: @x0:0 + LIST [25] { + elements: { + COMPREHENSION [26] { + iter_var: @c:1 + iter_range: { + IDENT [27] { + name: @index0 + } + } + accu_var: @x:1 + accu_init: { + CONSTANT [28] { value: false } + } + loop_condition: { + CALL [29] { + function: @not_strictly_false + args: { + CALL [30] { + function: !_ + args: { + IDENT [31] { + name: @x:1 + } + } + } + } + } + } + loop_step: { + CALL [32] { + function: _||_ + args: { + IDENT [33] { + name: @x:1 + } + CALL [34] { + function: _>_ + args: { + IDENT [35] { + name: @c:1 + } + CONSTANT [36] { value: 0 } + } + } + } + } + } + result: { + IDENT [37] { + name: @x:1 + } + } } } } } } } - loop_step: { - CALL [12] { - function: _||_ - args: { - IDENT [13] { - name: @x0:0 - } - CALL [14] { - function: _>_ - args: { - IDENT [15] { - name: @c0:0 + } + CALL [38] { + function: size + args: { + LIST [39] { + elements: { + COMPREHENSION [40] { + iter_var: @c:2 + iter_range: { + IDENT [41] { + name: @index1 + } + } + accu_var: @x:2 + accu_init: { + CONSTANT [42] { value: false } + } + loop_condition: { + CALL [43] { + function: @not_strictly_false + args: { + CALL [44] { + function: !_ + args: { + IDENT [45] { + name: @x:2 + } + } + } + } + } + } + loop_step: { + CALL [46] { + function: _||_ + args: { + IDENT [47] { + name: @x:2 + } + CALL [48] { + function: _>_ + args: { + IDENT [49] { + name: @c:2 + } + CONSTANT [50] { value: 1 } + } + } + } + } + } + result: { + IDENT [51] { + name: @x:2 } - CONSTANT [16] { value: 0 } } } } } } - result: { - IDENT [17] { - name: @x0:0 + } + } + } + CALL [52] { + function: size + args: { + LIST [53] { + elements: { + COMPREHENSION [54] { + iter_var: @c:3 + iter_range: { + IDENT [55] { + name: @index1 + } + } + accu_var: @x:3 + accu_init: { + CONSTANT [56] { value: false } + } + loop_condition: { + CALL [57] { + function: @not_strictly_false + args: { + CALL [58] { + function: !_ + args: { + IDENT [59] { + name: @x:3 + } + } + } + } + } + } + loop_step: { + CALL [60] { + function: _||_ + args: { + IDENT [61] { + name: @x:3 + } + CALL [62] { + function: _>_ + args: { + IDENT [63] { + name: @c:3 + } + CONSTANT [64] { value: 1 } + } + } + } + } + } + result: { + IDENT [65] { + name: @x:3 + } + } } } } @@ -1204,33 +1407,242 @@ CALL [1] { } } } - CALL [18] { - function: size + } + } + CALL [66] { + function: _==_ + args: { + IDENT [67] { + name: @index2 + } + CONSTANT [68] { value: 4 } + } + } + } +} +Test case: MULTIPLE_MACROS_2 +Source: [[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == 'a')] + [['a'].exists(l, l == 'a')] == [true, true, true, true] +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + } + } + LIST [5] { + elements: { + CONSTANT [6] { value: "a" } + } + } + } + } + CALL [7] { + function: _==_ + args: { + CALL [8] { + function: _+_ args: { - LIST [19] { - elements: { - COMPREHENSION [20] { - iter_var: @c0:0 - iter_range: { - LIST [21] { + CALL [9] { + function: _+_ + args: { + CALL [10] { + function: _+_ + args: { + LIST [11] { + elements: { + COMPREHENSION [12] { + iter_var: @c:0 + iter_range: { + IDENT [13] { + name: @index0 + } + } + accu_var: @x:0 + accu_init: { + CONSTANT [14] { value: false } + } + loop_condition: { + CALL [15] { + function: @not_strictly_false + args: { + CALL [16] { + function: !_ + args: { + IDENT [17] { + name: @x:0 + } + } + } + } + } + } + loop_step: { + CALL [18] { + function: _||_ + args: { + IDENT [19] { + name: @x:0 + } + CALL [20] { + function: _>_ + args: { + IDENT [21] { + name: @c:0 + } + CONSTANT [22] { value: 0 } + } + } + } + } + } + result: { + IDENT [23] { + name: @x:0 + } + } + } + } + } + LIST [24] { elements: { - CONSTANT [22] { value: 2 } + COMPREHENSION [25] { + iter_var: @c:1 + iter_range: { + IDENT [26] { + name: @index0 + } + } + accu_var: @x:1 + accu_init: { + CONSTANT [27] { value: false } + } + loop_condition: { + CALL [28] { + function: @not_strictly_false + args: { + CALL [29] { + function: !_ + args: { + IDENT [30] { + name: @x:1 + } + } + } + } + } + } + loop_step: { + CALL [31] { + function: _||_ + args: { + IDENT [32] { + name: @x:1 + } + CALL [33] { + function: _>_ + args: { + IDENT [34] { + name: @c:1 + } + CONSTANT [35] { value: 0 } + } + } + } + } + } + result: { + IDENT [36] { + name: @x:1 + } + } + } + } + } + } + } + LIST [37] { + elements: { + COMPREHENSION [38] { + iter_var: @c:2 + iter_range: { + IDENT [39] { + name: @index1 + } + } + accu_var: @x:2 + accu_init: { + CONSTANT [40] { value: false } + } + loop_condition: { + CALL [41] { + function: @not_strictly_false + args: { + CALL [42] { + function: !_ + args: { + IDENT [43] { + name: @x:2 + } + } + } + } + } + } + loop_step: { + CALL [44] { + function: _||_ + args: { + IDENT [45] { + name: @x:2 + } + CALL [46] { + function: _==_ + args: { + IDENT [47] { + name: @c:2 + } + CONSTANT [48] { value: "a" } + } + } + } + } + } + result: { + IDENT [49] { + name: @x:2 + } } } } - accu_var: @x0:0 + } + } + } + LIST [50] { + elements: { + COMPREHENSION [51] { + iter_var: @c:3 + iter_range: { + IDENT [52] { + name: @index1 + } + } + accu_var: @x:3 accu_init: { - CONSTANT [23] { value: false } + CONSTANT [53] { value: false } } loop_condition: { - CALL [24] { + CALL [54] { function: @not_strictly_false args: { - CALL [25] { + CALL [55] { function: !_ args: { - IDENT [26] { - name: @x0:0 + IDENT [56] { + name: @x:3 } } } @@ -1238,27 +1650,27 @@ CALL [1] { } } loop_step: { - CALL [27] { + CALL [57] { function: _||_ args: { - IDENT [28] { - name: @x0:0 + IDENT [58] { + name: @x:3 } - CALL [29] { - function: _>_ + CALL [59] { + function: _==_ args: { - IDENT [30] { - name: @c0:0 + IDENT [60] { + name: @c:3 } - CONSTANT [31] { value: 1 } + CONSTANT [61] { value: "a" } } } } } } result: { - IDENT [32] { - name: @x0:0 + IDENT [62] { + name: @x:3 } } } @@ -1266,45 +1678,20 @@ CALL [1] { } } } - } - } - CALL [33] { - function: _==_ - args: { - CALL [34] { - function: _+_ - args: { - CALL [35] { - function: _+_ - args: { - CALL [36] { - function: _+_ - args: { - IDENT [37] { - name: @index0 - } - IDENT [38] { - name: @index0 - } - } - } - IDENT [39] { - name: @index1 - } - } - } - IDENT [40] { - name: @index1 - } + LIST [63] { + elements: { + CONSTANT [64] { value: true } + CONSTANT [65] { value: true } + CONSTANT [66] { value: true } + CONSTANT [67] { value: true } } } - CONSTANT [41] { value: 4 } } } } } -Test case: MULTIPLE_MACROS_2 -Source: [[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == 'a')] + [['a'].exists(l, l == 'a')] == [true, true, true, true] +Test case: MULTIPLE_MACROS_3 +Source: [1].exists(i, i > 0) && [1].exists(j, j > 0) && [1].exists(k, k > 1) && [2].exists(l, l > 1) =====> CALL [1] { function: cel.@block @@ -1313,28 +1700,37 @@ CALL [1] { elements: { LIST [3] { elements: { - COMPREHENSION [4] { - iter_var: @c0:0 + CONSTANT [4] { value: 1 } + } + } + } + } + CALL [5] { + function: _&&_ + args: { + CALL [6] { + function: _&&_ + args: { + COMPREHENSION [7] { + iter_var: @c:0 iter_range: { - LIST [5] { - elements: { - CONSTANT [6] { value: 1 } - } + IDENT [8] { + name: @index0 } } - accu_var: @x0:0 + accu_var: @x:0 accu_init: { - CONSTANT [7] { value: false } + CONSTANT [9] { value: false } } loop_condition: { - CALL [8] { + CALL [10] { function: @not_strictly_false args: { - CALL [9] { + CALL [11] { function: !_ args: { - IDENT [10] { - name: @x0:0 + IDENT [12] { + name: @x:0 } } } @@ -1342,44 +1738,38 @@ CALL [1] { } } loop_step: { - CALL [11] { + CALL [13] { function: _||_ args: { - IDENT [12] { - name: @x0:0 + IDENT [14] { + name: @x:0 } - CALL [13] { + CALL [15] { function: _>_ args: { - IDENT [14] { - name: @c0:0 + IDENT [16] { + name: @c:0 } - CONSTANT [15] { value: 0 } + CONSTANT [17] { value: 0 } } } } } } result: { - IDENT [16] { - name: @x0:0 + IDENT [18] { + name: @x:0 } } } - } - } - LIST [17] { - elements: { - COMPREHENSION [18] { - iter_var: @c0:1 + COMPREHENSION [19] { + iter_var: @c:1 iter_range: { - LIST [19] { - elements: { - CONSTANT [20] { value: "a" } - } + IDENT [20] { + name: @index0 } } - accu_var: @x0:1 + accu_var: @x:1 accu_init: { CONSTANT [21] { value: false } } @@ -1391,7 +1781,7 @@ CALL [1] { function: !_ args: { IDENT [24] { - name: @x0:1 + name: @x:1 } } } @@ -1403,15 +1793,15 @@ CALL [1] { function: _||_ args: { IDENT [26] { - name: @x0:1 + name: @x:1 } CALL [27] { - function: _==_ + function: _>_ args: { IDENT [28] { - name: @c0:1 + name: @c:1 } - CONSTANT [29] { value: "a" } + CONSTANT [29] { value: 0 } } } } @@ -1419,52 +1809,121 @@ CALL [1] { } result: { IDENT [30] { - name: @x0:1 + name: @x:1 } } } } } - } - } - CALL [31] { - function: _==_ - args: { - CALL [32] { - function: _+_ + CALL [31] { + function: _&&_ args: { - CALL [33] { - function: _+_ - args: { - CALL [34] { - function: _+_ + COMPREHENSION [32] { + iter_var: @c:2 + iter_range: { + IDENT [33] { + name: @index0 + } + } + accu_var: @x:2 + accu_init: { + CONSTANT [34] { value: false } + } + loop_condition: { + CALL [35] { + function: @not_strictly_false args: { - IDENT [35] { - name: @index0 + CALL [36] { + function: !_ + args: { + IDENT [37] { + name: @x:2 + } + } } - IDENT [36] { - name: @index0 + } + } + } + loop_step: { + CALL [38] { + function: _||_ + args: { + IDENT [39] { + name: @x:2 + } + CALL [40] { + function: _>_ + args: { + IDENT [41] { + name: @c:2 + } + CONSTANT [42] { value: 1 } + } } } } - IDENT [37] { - name: @index1 + } + result: { + IDENT [43] { + name: @x:2 } } } - IDENT [38] { - name: @index1 + COMPREHENSION [44] { + iter_var: @c:3 + iter_range: { + LIST [45] { + elements: { + CONSTANT [46] { value: 2 } + } + } + } + accu_var: @x:3 + accu_init: { + CONSTANT [47] { value: false } + } + loop_condition: { + CALL [48] { + function: @not_strictly_false + args: { + CALL [49] { + function: !_ + args: { + IDENT [50] { + name: @x:3 + } + } + } + } + } + } + loop_step: { + CALL [51] { + function: _||_ + args: { + IDENT [52] { + name: @x:3 + } + CALL [53] { + function: _>_ + args: { + IDENT [54] { + name: @c:3 + } + CONSTANT [55] { value: 1 } + } + } + } + } + } + result: { + IDENT [56] { + name: @x:3 + } + } } } } - LIST [39] { - elements: { - CONSTANT [40] { value: true } - CONSTANT [41] { value: true } - CONSTANT [42] { value: true } - CONSTANT [43] { value: true } - } - } } } } @@ -1497,13 +1956,13 @@ CALL [1] { function: _==_ args: { COMPREHENSION [12] { - iter_var: @c0:0 + iter_var: @c:1 iter_range: { IDENT [13] { name: @index0 } } - accu_var: @x0:0 + accu_var: @x:1 accu_init: { LIST [14] { elements: { @@ -1518,18 +1977,18 @@ CALL [1] { function: _+_ args: { IDENT [17] { - name: @x0:0 + name: @x:1 } LIST [18] { elements: { COMPREHENSION [19] { - iter_var: @c1:0 + iter_var: @c:0 iter_range: { IDENT [20] { name: @index0 } } - accu_var: @x1:0 + accu_var: @x:0 accu_init: { LIST [21] { elements: { @@ -1544,7 +2003,7 @@ CALL [1] { function: _+_ args: { IDENT [24] { - name: @x1:0 + name: @x:0 } LIST [25] { elements: { @@ -1552,7 +2011,7 @@ CALL [1] { function: _+_ args: { IDENT [27] { - name: @c1:0 + name: @c:0 } CONSTANT [28] { value: 1 } } @@ -1564,7 +2023,7 @@ CALL [1] { } result: { IDENT [29] { - name: @x1:0 + name: @x:0 } } } @@ -1575,7 +2034,7 @@ CALL [1] { } result: { IDENT [30] { - name: @x0:0 + name: @x:1 } } } @@ -1603,7 +2062,7 @@ CALL [31] { function: _==_ args: { COMPREHENSION [30] { - iter_var: @c0:0 + iter_var: @c:1 iter_range: { LIST [1] { elements: { @@ -1612,7 +2071,7 @@ CALL [31] { } } } - accu_var: @x0:0 + accu_var: @x:1 accu_init: { LIST [24] { elements: { @@ -1627,12 +2086,12 @@ CALL [31] { function: _+_ args: { IDENT [26] { - name: @x0:0 + name: @x:1 } LIST [27] { elements: { COMPREHENSION [23] { - iter_var: @c1:0 + iter_var: @c:0 iter_range: { LIST [6] { elements: { @@ -1642,7 +2101,7 @@ CALL [31] { } } } - accu_var: @x1:0 + accu_var: @x:0 accu_init: { LIST [15] { elements: { @@ -1660,10 +2119,10 @@ CALL [31] { function: _==_ args: { IDENT [12] { - name: @c1:0 + name: @c:0 } IDENT [14] { - name: @c0:0 + name: @c:1 } } } @@ -1671,26 +2130,26 @@ CALL [31] { function: _+_ args: { IDENT [17] { - name: @x1:0 + name: @x:0 } LIST [18] { elements: { IDENT [11] { - name: @c1:0 + name: @c:0 } } } } } IDENT [20] { - name: @x1:0 + name: @x:0 } } } } result: { IDENT [22] { - name: @x1:0 + name: @x:0 } } } @@ -1701,7 +2160,7 @@ CALL [31] { } result: { IDENT [29] { - name: @x0:0 + name: @x:1 } } } @@ -1891,13 +2350,13 @@ CALL [1] { function: _==_ args: { COMPREHENSION [14] { - iter_var: @c0:0 + iter_var: @c:1 iter_range: { IDENT [15] { name: @index1 } } - accu_var: @x0:0 + accu_var: @x:1 accu_init: { LIST [16] { elements: { @@ -1912,18 +2371,18 @@ CALL [1] { function: _+_ args: { IDENT [19] { - name: @x0:0 + name: @x:1 } LIST [20] { elements: { COMPREHENSION [21] { - iter_var: @c1:0 + iter_var: @c:0 iter_range: { IDENT [22] { name: @index1 } } - accu_var: @x1:0 + accu_var: @x:0 accu_init: { LIST [23] { elements: { @@ -1938,7 +2397,7 @@ CALL [1] { function: _+_ args: { IDENT [26] { - name: @x1:0 + name: @x:0 } LIST [27] { elements: { @@ -1955,7 +2414,7 @@ CALL [1] { } result: { IDENT [31] { - name: @x1:0 + name: @x:0 } } } @@ -1966,7 +2425,7 @@ CALL [1] { } result: { IDENT [32] { - name: @x0:0 + name: @x:1 } } } @@ -2013,7 +2472,7 @@ CALL [1] { function: _||_ args: { COMPREHENSION [9] { - iter_var: @c0:0 + iter_var: @c:0 iter_range: { LIST [10] { elements: { @@ -2038,7 +2497,7 @@ CALL [1] { } } } - accu_var: @x0:0 + accu_var: @x:0 accu_init: { CONSTANT [17] { value: false } } @@ -2050,7 +2509,7 @@ CALL [1] { function: !_ args: { IDENT [20] { - name: @x0:0 + name: @x:0 } } } @@ -2062,7 +2521,7 @@ CALL [1] { function: _||_ args: { IDENT [22] { - name: @x0:0 + name: @x:0 } CALL [23] { function: _>_ @@ -2071,7 +2530,7 @@ CALL [1] { function: _-_ args: { IDENT [25] { - name: @c0:0 + name: @c:0 } CONSTANT [26] { value: 1 } } @@ -2084,7 +2543,7 @@ CALL [1] { } result: { IDENT [28] { - name: @x0:0 + name: @x:0 } } } @@ -2107,10 +2566,10 @@ CALL [1] { function: _+_ args: { IDENT [4] { - name: @c1:0 + name: @c:0 } IDENT [5] { - name: @c1:0 + name: @c:0 } } } @@ -2118,20 +2577,20 @@ CALL [1] { function: _+_ args: { IDENT [7] { - name: @c0:0 + name: @c:1 } IDENT [8] { - name: @c0:0 + name: @c:1 } } } } } COMPREHENSION [9] { - iter_var: @c0:0 + iter_var: @c:1 iter_range: { COMPREHENSION [10] { - iter_var: @c1:0 + iter_var: @c:0 iter_range: { LIST [11] { elements: { @@ -2140,7 +2599,7 @@ CALL [1] { } } } - accu_var: @x1:0 + accu_var: @x:0 accu_init: { LIST [14] { elements: { @@ -2155,7 +2614,7 @@ CALL [1] { function: _+_ args: { IDENT [17] { - name: @x1:0 + name: @x:0 } LIST [18] { elements: { @@ -2176,12 +2635,12 @@ CALL [1] { } result: { IDENT [22] { - name: @x1:0 + name: @x:0 } } } } - accu_var: @x0:0 + accu_var: @x:1 accu_init: { LIST [23] { elements: { @@ -2196,7 +2655,7 @@ CALL [1] { function: _+_ args: { IDENT [26] { - name: @x0:0 + name: @x:1 } LIST [27] { elements: { @@ -2217,7 +2676,7 @@ CALL [1] { } result: { IDENT [31] { - name: @x0:0 + name: @x:1 } } } @@ -3141,4 +3600,4 @@ CALL [1] { } } } -} +} \ No newline at end of file diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_9.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_9.baseline index fd8be83cf..b9bccc56c 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_9.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_9.baseline @@ -1130,61 +1130,269 @@ CALL [1] { args: { LIST [2] { elements: { - CALL [3] { - function: size + LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + } + } + LIST [5] { + elements: { + CONSTANT [6] { value: 2 } + } + } + } + } + CALL [7] { + function: _==_ + args: { + CALL [8] { + function: _+_ args: { - LIST [4] { - elements: { - COMPREHENSION [5] { - iter_var: @c0:0 - iter_range: { - LIST [6] { - elements: { - CONSTANT [7] { value: 1 } + CALL [9] { + function: _+_ + args: { + CALL [10] { + function: _+_ + args: { + CALL [11] { + function: size + args: { + LIST [12] { + elements: { + COMPREHENSION [13] { + iter_var: @c:0 + iter_range: { + IDENT [14] { + name: @index0 + } + } + accu_var: @x:0 + accu_init: { + CONSTANT [15] { value: false } + } + loop_condition: { + CALL [16] { + function: @not_strictly_false + args: { + CALL [17] { + function: !_ + args: { + IDENT [18] { + name: @x:0 + } + } + } + } + } + } + loop_step: { + CALL [19] { + function: _||_ + args: { + IDENT [20] { + name: @x:0 + } + CALL [21] { + function: _>_ + args: { + IDENT [22] { + name: @c:0 + } + CONSTANT [23] { value: 0 } + } + } + } + } + } + result: { + IDENT [24] { + name: @x:0 + } + } + } + } + } } } - } - accu_var: @x0:0 - accu_init: { - CONSTANT [8] { value: false } - } - loop_condition: { - CALL [9] { - function: @not_strictly_false + CALL [25] { + function: size args: { - CALL [10] { - function: !_ - args: { - IDENT [11] { - name: @x0:0 + LIST [26] { + elements: { + COMPREHENSION [27] { + iter_var: @c:1 + iter_range: { + IDENT [28] { + name: @index0 + } + } + accu_var: @x:1 + accu_init: { + CONSTANT [29] { value: false } + } + loop_condition: { + CALL [30] { + function: @not_strictly_false + args: { + CALL [31] { + function: !_ + args: { + IDENT [32] { + name: @x:1 + } + } + } + } + } + } + loop_step: { + CALL [33] { + function: _||_ + args: { + IDENT [34] { + name: @x:1 + } + CALL [35] { + function: _>_ + args: { + IDENT [36] { + name: @c:1 + } + CONSTANT [37] { value: 0 } + } + } + } + } + } + result: { + IDENT [38] { + name: @x:1 + } + } } } } } } } - loop_step: { - CALL [12] { - function: _||_ - args: { - IDENT [13] { - name: @x0:0 - } - CALL [14] { - function: _>_ - args: { - IDENT [15] { - name: @c0:0 + } + CALL [39] { + function: size + args: { + LIST [40] { + elements: { + COMPREHENSION [41] { + iter_var: @c:2 + iter_range: { + IDENT [42] { + name: @index1 + } + } + accu_var: @x:2 + accu_init: { + CONSTANT [43] { value: false } + } + loop_condition: { + CALL [44] { + function: @not_strictly_false + args: { + CALL [45] { + function: !_ + args: { + IDENT [46] { + name: @x:2 + } + } + } + } + } + } + loop_step: { + CALL [47] { + function: _||_ + args: { + IDENT [48] { + name: @x:2 + } + CALL [49] { + function: _>_ + args: { + IDENT [50] { + name: @c:2 + } + CONSTANT [51] { value: 1 } + } + } + } + } + } + result: { + IDENT [52] { + name: @x:2 } - CONSTANT [16] { value: 0 } } } } } } - result: { - IDENT [17] { - name: @x0:0 + } + } + } + CALL [53] { + function: size + args: { + LIST [54] { + elements: { + COMPREHENSION [55] { + iter_var: @c:3 + iter_range: { + IDENT [56] { + name: @index1 + } + } + accu_var: @x:3 + accu_init: { + CONSTANT [57] { value: false } + } + loop_condition: { + CALL [58] { + function: @not_strictly_false + args: { + CALL [59] { + function: !_ + args: { + IDENT [60] { + name: @x:3 + } + } + } + } + } + } + loop_step: { + CALL [61] { + function: _||_ + args: { + IDENT [62] { + name: @x:3 + } + CALL [63] { + function: _>_ + args: { + IDENT [64] { + name: @c:3 + } + CONSTANT [65] { value: 1 } + } + } + } + } + } + result: { + IDENT [66] { + name: @x:3 + } + } } } } @@ -1192,33 +1400,234 @@ CALL [1] { } } } - CALL [18] { - function: size + CONSTANT [67] { value: 4 } + } + } + } +} +Test case: MULTIPLE_MACROS_2 +Source: [[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == 'a')] + [['a'].exists(l, l == 'a')] == [true, true, true, true] +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + } + } + LIST [5] { + elements: { + CONSTANT [6] { value: "a" } + } + } + } + } + CALL [7] { + function: _==_ + args: { + CALL [8] { + function: _+_ args: { - LIST [19] { - elements: { - COMPREHENSION [20] { - iter_var: @c0:0 - iter_range: { - LIST [21] { + CALL [9] { + function: _+_ + args: { + CALL [10] { + function: _+_ + args: { + LIST [11] { + elements: { + COMPREHENSION [12] { + iter_var: @c:0 + iter_range: { + IDENT [13] { + name: @index0 + } + } + accu_var: @x:0 + accu_init: { + CONSTANT [14] { value: false } + } + loop_condition: { + CALL [15] { + function: @not_strictly_false + args: { + CALL [16] { + function: !_ + args: { + IDENT [17] { + name: @x:0 + } + } + } + } + } + } + loop_step: { + CALL [18] { + function: _||_ + args: { + IDENT [19] { + name: @x:0 + } + CALL [20] { + function: _>_ + args: { + IDENT [21] { + name: @c:0 + } + CONSTANT [22] { value: 0 } + } + } + } + } + } + result: { + IDENT [23] { + name: @x:0 + } + } + } + } + } + LIST [24] { elements: { - CONSTANT [22] { value: 2 } + COMPREHENSION [25] { + iter_var: @c:1 + iter_range: { + IDENT [26] { + name: @index0 + } + } + accu_var: @x:1 + accu_init: { + CONSTANT [27] { value: false } + } + loop_condition: { + CALL [28] { + function: @not_strictly_false + args: { + CALL [29] { + function: !_ + args: { + IDENT [30] { + name: @x:1 + } + } + } + } + } + } + loop_step: { + CALL [31] { + function: _||_ + args: { + IDENT [32] { + name: @x:1 + } + CALL [33] { + function: _>_ + args: { + IDENT [34] { + name: @c:1 + } + CONSTANT [35] { value: 0 } + } + } + } + } + } + result: { + IDENT [36] { + name: @x:1 + } + } + } } } } - accu_var: @x0:0 + } + LIST [37] { + elements: { + COMPREHENSION [38] { + iter_var: @c:2 + iter_range: { + IDENT [39] { + name: @index1 + } + } + accu_var: @x:2 + accu_init: { + CONSTANT [40] { value: false } + } + loop_condition: { + CALL [41] { + function: @not_strictly_false + args: { + CALL [42] { + function: !_ + args: { + IDENT [43] { + name: @x:2 + } + } + } + } + } + } + loop_step: { + CALL [44] { + function: _||_ + args: { + IDENT [45] { + name: @x:2 + } + CALL [46] { + function: _==_ + args: { + IDENT [47] { + name: @c:2 + } + CONSTANT [48] { value: "a" } + } + } + } + } + } + result: { + IDENT [49] { + name: @x:2 + } + } + } + } + } + } + } + LIST [50] { + elements: { + COMPREHENSION [51] { + iter_var: @c:3 + iter_range: { + IDENT [52] { + name: @index1 + } + } + accu_var: @x:3 accu_init: { - CONSTANT [23] { value: false } + CONSTANT [53] { value: false } } loop_condition: { - CALL [24] { + CALL [54] { function: @not_strictly_false args: { - CALL [25] { + CALL [55] { function: !_ args: { - IDENT [26] { - name: @x0:0 + IDENT [56] { + name: @x:3 } } } @@ -1226,27 +1635,27 @@ CALL [1] { } } loop_step: { - CALL [27] { + CALL [57] { function: _||_ args: { - IDENT [28] { - name: @x0:0 + IDENT [58] { + name: @x:3 } - CALL [29] { - function: _>_ + CALL [59] { + function: _==_ args: { - IDENT [30] { - name: @c0:0 + IDENT [60] { + name: @c:3 } - CONSTANT [31] { value: 1 } + CONSTANT [61] { value: "a" } } } } } } result: { - IDENT [32] { - name: @x0:0 + IDENT [62] { + name: @x:3 } } } @@ -1254,45 +1663,20 @@ CALL [1] { } } } - } - } - CALL [33] { - function: _==_ - args: { - CALL [34] { - function: _+_ - args: { - CALL [35] { - function: _+_ - args: { - CALL [36] { - function: _+_ - args: { - IDENT [37] { - name: @index0 - } - IDENT [38] { - name: @index0 - } - } - } - IDENT [39] { - name: @index1 - } - } - } - IDENT [40] { - name: @index1 - } + LIST [63] { + elements: { + CONSTANT [64] { value: true } + CONSTANT [65] { value: true } + CONSTANT [66] { value: true } + CONSTANT [67] { value: true } } } - CONSTANT [41] { value: 4 } } } } } -Test case: MULTIPLE_MACROS_2 -Source: [[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == 'a')] + [['a'].exists(l, l == 'a')] == [true, true, true, true] +Test case: MULTIPLE_MACROS_3 +Source: [1].exists(i, i > 0) && [1].exists(j, j > 0) && [1].exists(k, k > 1) && [2].exists(l, l > 1) =====> CALL [1] { function: cel.@block @@ -1301,28 +1685,37 @@ CALL [1] { elements: { LIST [3] { elements: { - COMPREHENSION [4] { - iter_var: @c0:0 + CONSTANT [4] { value: 1 } + } + } + } + } + CALL [5] { + function: _&&_ + args: { + CALL [6] { + function: _&&_ + args: { + COMPREHENSION [7] { + iter_var: @c:0 iter_range: { - LIST [5] { - elements: { - CONSTANT [6] { value: 1 } - } + IDENT [8] { + name: @index0 } } - accu_var: @x0:0 + accu_var: @x:0 accu_init: { - CONSTANT [7] { value: false } + CONSTANT [9] { value: false } } loop_condition: { - CALL [8] { + CALL [10] { function: @not_strictly_false args: { - CALL [9] { + CALL [11] { function: !_ args: { - IDENT [10] { - name: @x0:0 + IDENT [12] { + name: @x:0 } } } @@ -1330,44 +1723,38 @@ CALL [1] { } } loop_step: { - CALL [11] { + CALL [13] { function: _||_ args: { - IDENT [12] { - name: @x0:0 + IDENT [14] { + name: @x:0 } - CALL [13] { + CALL [15] { function: _>_ args: { - IDENT [14] { - name: @c0:0 + IDENT [16] { + name: @c:0 } - CONSTANT [15] { value: 0 } + CONSTANT [17] { value: 0 } } } } } } result: { - IDENT [16] { - name: @x0:0 + IDENT [18] { + name: @x:0 } } } - } - } - LIST [17] { - elements: { - COMPREHENSION [18] { - iter_var: @c0:1 + COMPREHENSION [19] { + iter_var: @c:1 iter_range: { - LIST [19] { - elements: { - CONSTANT [20] { value: "a" } - } + IDENT [20] { + name: @index0 } } - accu_var: @x0:1 + accu_var: @x:1 accu_init: { CONSTANT [21] { value: false } } @@ -1379,7 +1766,7 @@ CALL [1] { function: !_ args: { IDENT [24] { - name: @x0:1 + name: @x:1 } } } @@ -1391,15 +1778,15 @@ CALL [1] { function: _||_ args: { IDENT [26] { - name: @x0:1 + name: @x:1 } CALL [27] { - function: _==_ + function: _>_ args: { IDENT [28] { - name: @c0:1 + name: @c:1 } - CONSTANT [29] { value: "a" } + CONSTANT [29] { value: 0 } } } } @@ -1407,52 +1794,121 @@ CALL [1] { } result: { IDENT [30] { - name: @x0:1 + name: @x:1 } } } } } - } - } - CALL [31] { - function: _==_ - args: { - CALL [32] { - function: _+_ + CALL [31] { + function: _&&_ args: { - CALL [33] { - function: _+_ - args: { - CALL [34] { - function: _+_ + COMPREHENSION [32] { + iter_var: @c:2 + iter_range: { + IDENT [33] { + name: @index0 + } + } + accu_var: @x:2 + accu_init: { + CONSTANT [34] { value: false } + } + loop_condition: { + CALL [35] { + function: @not_strictly_false args: { - IDENT [35] { - name: @index0 + CALL [36] { + function: !_ + args: { + IDENT [37] { + name: @x:2 + } + } } - IDENT [36] { - name: @index0 + } + } + } + loop_step: { + CALL [38] { + function: _||_ + args: { + IDENT [39] { + name: @x:2 + } + CALL [40] { + function: _>_ + args: { + IDENT [41] { + name: @c:2 + } + CONSTANT [42] { value: 1 } + } } } } - IDENT [37] { - name: @index1 + } + result: { + IDENT [43] { + name: @x:2 } } } - IDENT [38] { - name: @index1 + COMPREHENSION [44] { + iter_var: @c:3 + iter_range: { + LIST [45] { + elements: { + CONSTANT [46] { value: 2 } + } + } + } + accu_var: @x:3 + accu_init: { + CONSTANT [47] { value: false } + } + loop_condition: { + CALL [48] { + function: @not_strictly_false + args: { + CALL [49] { + function: !_ + args: { + IDENT [50] { + name: @x:3 + } + } + } + } + } + } + loop_step: { + CALL [51] { + function: _||_ + args: { + IDENT [52] { + name: @x:3 + } + CALL [53] { + function: _>_ + args: { + IDENT [54] { + name: @c:3 + } + CONSTANT [55] { value: 1 } + } + } + } + } + } + result: { + IDENT [56] { + name: @x:3 + } + } } } } - LIST [39] { - elements: { - CONSTANT [40] { value: true } - CONSTANT [41] { value: true } - CONSTANT [42] { value: true } - CONSTANT [43] { value: true } - } - } } } } @@ -1485,13 +1941,13 @@ CALL [1] { function: _==_ args: { COMPREHENSION [12] { - iter_var: @c0:0 + iter_var: @c:1 iter_range: { IDENT [13] { name: @index0 } } - accu_var: @x0:0 + accu_var: @x:1 accu_init: { LIST [14] { elements: { @@ -1506,18 +1962,18 @@ CALL [1] { function: _+_ args: { IDENT [17] { - name: @x0:0 + name: @x:1 } LIST [18] { elements: { COMPREHENSION [19] { - iter_var: @c1:0 + iter_var: @c:0 iter_range: { IDENT [20] { name: @index0 } } - accu_var: @x1:0 + accu_var: @x:0 accu_init: { LIST [21] { elements: { @@ -1532,7 +1988,7 @@ CALL [1] { function: _+_ args: { IDENT [24] { - name: @x1:0 + name: @x:0 } LIST [25] { elements: { @@ -1540,7 +1996,7 @@ CALL [1] { function: _+_ args: { IDENT [27] { - name: @c1:0 + name: @c:0 } CONSTANT [28] { value: 1 } } @@ -1552,7 +2008,7 @@ CALL [1] { } result: { IDENT [29] { - name: @x1:0 + name: @x:0 } } } @@ -1563,7 +2019,7 @@ CALL [1] { } result: { IDENT [30] { - name: @x0:0 + name: @x:1 } } } @@ -1591,7 +2047,7 @@ CALL [31] { function: _==_ args: { COMPREHENSION [30] { - iter_var: @c0:0 + iter_var: @c:1 iter_range: { LIST [1] { elements: { @@ -1600,7 +2056,7 @@ CALL [31] { } } } - accu_var: @x0:0 + accu_var: @x:1 accu_init: { LIST [24] { elements: { @@ -1615,12 +2071,12 @@ CALL [31] { function: _+_ args: { IDENT [26] { - name: @x0:0 + name: @x:1 } LIST [27] { elements: { COMPREHENSION [23] { - iter_var: @c1:0 + iter_var: @c:0 iter_range: { LIST [6] { elements: { @@ -1630,7 +2086,7 @@ CALL [31] { } } } - accu_var: @x1:0 + accu_var: @x:0 accu_init: { LIST [15] { elements: { @@ -1648,10 +2104,10 @@ CALL [31] { function: _==_ args: { IDENT [12] { - name: @c1:0 + name: @c:0 } IDENT [14] { - name: @c0:0 + name: @c:1 } } } @@ -1659,26 +2115,26 @@ CALL [31] { function: _+_ args: { IDENT [17] { - name: @x1:0 + name: @x:0 } LIST [18] { elements: { IDENT [11] { - name: @c1:0 + name: @c:0 } } } } } IDENT [20] { - name: @x1:0 + name: @x:0 } } } } result: { IDENT [22] { - name: @x1:0 + name: @x:0 } } } @@ -1689,7 +2145,7 @@ CALL [31] { } result: { IDENT [29] { - name: @x0:0 + name: @x:1 } } } @@ -1879,13 +2335,13 @@ CALL [1] { function: _==_ args: { COMPREHENSION [14] { - iter_var: @c0:0 + iter_var: @c:1 iter_range: { IDENT [15] { name: @index1 } } - accu_var: @x0:0 + accu_var: @x:1 accu_init: { LIST [16] { elements: { @@ -1900,18 +2356,18 @@ CALL [1] { function: _+_ args: { IDENT [19] { - name: @x0:0 + name: @x:1 } LIST [20] { elements: { COMPREHENSION [21] { - iter_var: @c1:0 + iter_var: @c:0 iter_range: { IDENT [22] { name: @index1 } } - accu_var: @x1:0 + accu_var: @x:0 accu_init: { LIST [23] { elements: { @@ -1926,7 +2382,7 @@ CALL [1] { function: _+_ args: { IDENT [26] { - name: @x1:0 + name: @x:0 } LIST [27] { elements: { @@ -1943,7 +2399,7 @@ CALL [1] { } result: { IDENT [31] { - name: @x1:0 + name: @x:0 } } } @@ -1954,7 +2410,7 @@ CALL [1] { } result: { IDENT [32] { - name: @x0:0 + name: @x:1 } } } @@ -2001,7 +2457,7 @@ CALL [1] { function: _||_ args: { COMPREHENSION [9] { - iter_var: @c0:0 + iter_var: @c:0 iter_range: { LIST [10] { elements: { @@ -2026,7 +2482,7 @@ CALL [1] { } } } - accu_var: @x0:0 + accu_var: @x:0 accu_init: { CONSTANT [17] { value: false } } @@ -2038,7 +2494,7 @@ CALL [1] { function: !_ args: { IDENT [20] { - name: @x0:0 + name: @x:0 } } } @@ -2050,7 +2506,7 @@ CALL [1] { function: _||_ args: { IDENT [22] { - name: @x0:0 + name: @x:0 } CALL [23] { function: _>_ @@ -2059,7 +2515,7 @@ CALL [1] { function: _-_ args: { IDENT [25] { - name: @c0:0 + name: @c:0 } CONSTANT [26] { value: 1 } } @@ -2072,7 +2528,7 @@ CALL [1] { } result: { IDENT [28] { - name: @x0:0 + name: @x:0 } } } @@ -2095,10 +2551,10 @@ CALL [1] { function: _+_ args: { IDENT [4] { - name: @c1:0 + name: @c:0 } IDENT [5] { - name: @c1:0 + name: @c:0 } } } @@ -2106,20 +2562,20 @@ CALL [1] { function: _+_ args: { IDENT [7] { - name: @c0:0 + name: @c:1 } IDENT [8] { - name: @c0:0 + name: @c:1 } } } } } COMPREHENSION [9] { - iter_var: @c0:0 + iter_var: @c:1 iter_range: { COMPREHENSION [10] { - iter_var: @c1:0 + iter_var: @c:0 iter_range: { LIST [11] { elements: { @@ -2128,7 +2584,7 @@ CALL [1] { } } } - accu_var: @x1:0 + accu_var: @x:0 accu_init: { LIST [14] { elements: { @@ -2143,7 +2599,7 @@ CALL [1] { function: _+_ args: { IDENT [17] { - name: @x1:0 + name: @x:0 } LIST [18] { elements: { @@ -2164,12 +2620,12 @@ CALL [1] { } result: { IDENT [22] { - name: @x1:0 + name: @x:0 } } } } - accu_var: @x0:0 + accu_var: @x:1 accu_init: { LIST [23] { elements: { @@ -2184,7 +2640,7 @@ CALL [1] { function: _+_ args: { IDENT [26] { - name: @x0:0 + name: @x:1 } LIST [27] { elements: { @@ -2205,7 +2661,7 @@ CALL [1] { } result: { IDENT [31] { - name: @x0:0 + name: @x:1 } } } @@ -3129,4 +3585,4 @@ CALL [1] { } } } -} +} \ No newline at end of file diff --git a/optimizer/src/test/resources/subexpression_ast_cascaded_binds.baseline b/optimizer/src/test/resources/subexpression_ast_cascaded_binds.baseline index 17f8eb774..5d09067b9 100644 --- a/optimizer/src/test/resources/subexpression_ast_cascaded_binds.baseline +++ b/optimizer/src/test/resources/subexpression_ast_cascaded_binds.baseline @@ -1552,61 +1552,296 @@ CALL [1] { } accu_var: @r1 accu_init: { - CALL [4] { - function: size + LIST [4] { + elements: { + CONSTANT [5] { value: 2 } + } + } + } + loop_condition: { + CONSTANT [6] { value: false } + } + loop_step: { + IDENT [7] { + name: @r1 + } + } + result: { + CALL [8] { + function: _+_ args: { - LIST [5] { - elements: { - COMPREHENSION [6] { - iter_var: @c0:0 + CALL [9] { + function: _+_ + args: { + COMPREHENSION [10] { + iter_var: #unused iter_range: { - LIST [7] { + LIST [11] { elements: { - CONSTANT [8] { value: 2 } } } } - accu_var: @x0:0 + accu_var: @r0 accu_init: { - CONSTANT [9] { value: false } + LIST [12] { + elements: { + CONSTANT [13] { value: 1 } + } + } } loop_condition: { - CALL [10] { - function: @not_strictly_false + CONSTANT [14] { value: false } + } + loop_step: { + IDENT [15] { + name: @r0 + } + } + result: { + CALL [16] { + function: _+_ args: { - CALL [11] { - function: !_ + CALL [17] { + function: size args: { - IDENT [12] { - name: @x0:0 + LIST [18] { + elements: { + COMPREHENSION [19] { + iter_var: @c:0 + iter_range: { + IDENT [20] { + name: @r0 + } + } + accu_var: @x:0 + accu_init: { + CONSTANT [21] { value: false } + } + loop_condition: { + CALL [22] { + function: @not_strictly_false + args: { + CALL [23] { + function: !_ + args: { + IDENT [24] { + name: @x:0 + } + } + } + } + } + } + loop_step: { + CALL [25] { + function: _||_ + args: { + IDENT [26] { + name: @x:0 + } + CALL [27] { + function: _>_ + args: { + IDENT [28] { + name: @c:0 + } + CONSTANT [29] { value: 0 } + } + } + } + } + } + result: { + IDENT [30] { + name: @x:0 + } + } + } + } + } + } + } + CALL [31] { + function: size + args: { + LIST [32] { + elements: { + COMPREHENSION [33] { + iter_var: @c:1 + iter_range: { + IDENT [34] { + name: @r0 + } + } + accu_var: @x:1 + accu_init: { + CONSTANT [35] { value: false } + } + loop_condition: { + CALL [36] { + function: @not_strictly_false + args: { + CALL [37] { + function: !_ + args: { + IDENT [38] { + name: @x:1 + } + } + } + } + } + } + loop_step: { + CALL [39] { + function: _||_ + args: { + IDENT [40] { + name: @x:1 + } + CALL [41] { + function: _>_ + args: { + IDENT [42] { + name: @c:1 + } + CONSTANT [43] { value: 0 } + } + } + } + } + } + result: { + IDENT [44] { + name: @x:1 + } + } + } + } } } } } } } - loop_step: { - CALL [13] { - function: _||_ - args: { - IDENT [14] { - name: @x0:0 - } - CALL [15] { - function: _>_ - args: { - IDENT [16] { - name: @c0:0 + } + CALL [45] { + function: size + args: { + LIST [46] { + elements: { + COMPREHENSION [47] { + iter_var: @c:2 + iter_range: { + IDENT [48] { + name: @r1 + } + } + accu_var: @x:2 + accu_init: { + CONSTANT [49] { value: false } + } + loop_condition: { + CALL [50] { + function: @not_strictly_false + args: { + CALL [51] { + function: !_ + args: { + IDENT [52] { + name: @x:2 + } + } + } + } + } + } + loop_step: { + CALL [53] { + function: _||_ + args: { + IDENT [54] { + name: @x:2 + } + CALL [55] { + function: _>_ + args: { + IDENT [56] { + name: @c:2 + } + CONSTANT [57] { value: 1 } + } + } + } + } + } + result: { + IDENT [58] { + name: @x:2 } - CONSTANT [17] { value: 1 } } } } } } - result: { - IDENT [18] { - name: @x0:0 + } + } + } + CALL [59] { + function: size + args: { + LIST [60] { + elements: { + COMPREHENSION [61] { + iter_var: @c:3 + iter_range: { + IDENT [62] { + name: @r1 + } + } + accu_var: @x:3 + accu_init: { + CONSTANT [63] { value: false } + } + loop_condition: { + CALL [64] { + function: @not_strictly_false + args: { + CALL [65] { + function: !_ + args: { + IDENT [66] { + name: @x:3 + } + } + } + } + } + } + loop_step: { + CALL [67] { + function: _||_ + args: { + IDENT [68] { + name: @x:3 + } + CALL [69] { + function: _>_ + args: { + IDENT [70] { + name: @c:3 + } + CONSTANT [71] { value: 1 } + } + } + } + } + } + result: { + IDENT [72] { + name: @x:3 + } + } } } } @@ -1615,58 +1850,97 @@ CALL [1] { } } } + } + CONSTANT [73] { value: 4 } + } +} +Test case: MULTIPLE_MACROS_2 +Source: [[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == 'a')] + [['a'].exists(l, l == 'a')] == [true, true, true, true] +=====> +CALL [1] { + function: _==_ + args: { + COMPREHENSION [2] { + iter_var: #unused + iter_range: { + LIST [3] { + elements: { + } + } + } + accu_var: @r1 + accu_init: { + LIST [4] { + elements: { + CONSTANT [5] { value: "a" } + } + } + } loop_condition: { - CONSTANT [19] { value: false } + CONSTANT [6] { value: false } } loop_step: { - IDENT [20] { + IDENT [7] { name: @r1 } } result: { - CALL [21] { + CALL [8] { function: _+_ args: { - CALL [22] { + CALL [9] { function: _+_ args: { - COMPREHENSION [23] { + COMPREHENSION [10] { iter_var: #unused iter_range: { - LIST [24] { + LIST [11] { elements: { } } } accu_var: @r0 accu_init: { - CALL [25] { - function: size + LIST [12] { + elements: { + CONSTANT [13] { value: 1 } + } + } + } + loop_condition: { + CONSTANT [14] { value: false } + } + loop_step: { + IDENT [15] { + name: @r0 + } + } + result: { + CALL [16] { + function: _+_ args: { - LIST [26] { + LIST [17] { elements: { - COMPREHENSION [27] { - iter_var: @c0:0 + COMPREHENSION [18] { + iter_var: @c:0 iter_range: { - LIST [28] { - elements: { - CONSTANT [29] { value: 1 } - } + IDENT [19] { + name: @r0 } } - accu_var: @x0:0 + accu_var: @x:0 accu_init: { - CONSTANT [30] { value: false } + CONSTANT [20] { value: false } } loop_condition: { - CALL [31] { + CALL [21] { function: @not_strictly_false args: { - CALL [32] { + CALL [22] { function: !_ args: { - IDENT [33] { - name: @x0:0 + IDENT [23] { + name: @x:0 } } } @@ -1674,27 +1948,82 @@ CALL [1] { } } loop_step: { + CALL [24] { + function: _||_ + args: { + IDENT [25] { + name: @x:0 + } + CALL [26] { + function: _>_ + args: { + IDENT [27] { + name: @c:0 + } + CONSTANT [28] { value: 0 } + } + } + } + } + } + result: { + IDENT [29] { + name: @x:0 + } + } + } + } + } + LIST [30] { + elements: { + COMPREHENSION [31] { + iter_var: @c:1 + iter_range: { + IDENT [32] { + name: @r0 + } + } + accu_var: @x:1 + accu_init: { + CONSTANT [33] { value: false } + } + loop_condition: { CALL [34] { + function: @not_strictly_false + args: { + CALL [35] { + function: !_ + args: { + IDENT [36] { + name: @x:1 + } + } + } + } + } + } + loop_step: { + CALL [37] { function: _||_ args: { - IDENT [35] { - name: @x0:0 + IDENT [38] { + name: @x:1 } - CALL [36] { + CALL [39] { function: _>_ args: { - IDENT [37] { - name: @c0:0 + IDENT [40] { + name: @c:1 } - CONSTANT [38] { value: 0 } + CONSTANT [41] { value: 0 } } } } } } result: { - IDENT [39] { - name: @x0:0 + IDENT [42] { + name: @x:1 } } } @@ -1703,83 +2032,238 @@ CALL [1] { } } } - loop_condition: { - CONSTANT [40] { value: false } - } + } + LIST [43] { + elements: { + COMPREHENSION [44] { + iter_var: @c:2 + iter_range: { + IDENT [45] { + name: @r1 + } + } + accu_var: @x:2 + accu_init: { + CONSTANT [46] { value: false } + } + loop_condition: { + CALL [47] { + function: @not_strictly_false + args: { + CALL [48] { + function: !_ + args: { + IDENT [49] { + name: @x:2 + } + } + } + } + } + } + loop_step: { + CALL [50] { + function: _||_ + args: { + IDENT [51] { + name: @x:2 + } + CALL [52] { + function: _==_ + args: { + IDENT [53] { + name: @c:2 + } + CONSTANT [54] { value: "a" } + } + } + } + } + } + result: { + IDENT [55] { + name: @x:2 + } + } + } + } + } + } + } + LIST [56] { + elements: { + COMPREHENSION [57] { + iter_var: @c:3 + iter_range: { + IDENT [58] { + name: @r1 + } + } + accu_var: @x:3 + accu_init: { + CONSTANT [59] { value: false } + } + loop_condition: { + CALL [60] { + function: @not_strictly_false + args: { + CALL [61] { + function: !_ + args: { + IDENT [62] { + name: @x:3 + } + } + } + } + } + } loop_step: { - IDENT [41] { - name: @r0 - } - } - result: { - CALL [42] { - function: _+_ + CALL [63] { + function: _||_ args: { - IDENT [43] { - name: @r0 + IDENT [64] { + name: @x:3 } - IDENT [44] { - name: @r0 + CALL [65] { + function: _==_ + args: { + IDENT [66] { + name: @c:3 + } + CONSTANT [67] { value: "a" } + } } } } } - } - IDENT [45] { - name: @r1 + result: { + IDENT [68] { + name: @x:3 + } + } } } } - IDENT [46] { - name: @r1 - } } } } } - CONSTANT [47] { value: 4 } + LIST [69] { + elements: { + CONSTANT [70] { value: true } + CONSTANT [71] { value: true } + CONSTANT [72] { value: true } + CONSTANT [73] { value: true } + } + } } } -Test case: MULTIPLE_MACROS_2 -Source: [[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == 'a')] + [['a'].exists(l, l == 'a')] == [true, true, true, true] +Test case: MULTIPLE_MACROS_3 +Source: [1].exists(i, i > 0) && [1].exists(j, j > 0) && [1].exists(k, k > 1) && [2].exists(l, l > 1) =====> -CALL [1] { - function: _==_ - args: { - COMPREHENSION [2] { - iter_var: #unused - iter_range: { - LIST [3] { - elements: { - } - } +COMPREHENSION [1] { + iter_var: #unused + iter_range: { + LIST [2] { + elements: { } - accu_var: @r1 - accu_init: { - LIST [4] { - elements: { - COMPREHENSION [5] { - iter_var: @c0:1 + } + } + accu_var: @r0 + accu_init: { + LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + } + } + } + loop_condition: { + CONSTANT [5] { value: false } + } + loop_step: { + IDENT [6] { + name: @r0 + } + } + result: { + CALL [7] { + function: _&&_ + args: { + CALL [8] { + function: _&&_ + args: { + COMPREHENSION [9] { + iter_var: @c:0 iter_range: { - LIST [6] { - elements: { - CONSTANT [7] { value: "a" } + IDENT [10] { + name: @r0 + } + } + accu_var: @x:0 + accu_init: { + CONSTANT [11] { value: false } + } + loop_condition: { + CALL [12] { + function: @not_strictly_false + args: { + CALL [13] { + function: !_ + args: { + IDENT [14] { + name: @x:0 + } + } + } + } + } + } + loop_step: { + CALL [15] { + function: _||_ + args: { + IDENT [16] { + name: @x:0 + } + CALL [17] { + function: _>_ + args: { + IDENT [18] { + name: @c:0 + } + CONSTANT [19] { value: 0 } + } + } } } } - accu_var: @x0:1 + result: { + IDENT [20] { + name: @x:0 + } + } + } + COMPREHENSION [21] { + iter_var: @c:1 + iter_range: { + IDENT [22] { + name: @r0 + } + } + accu_var: @x:1 accu_init: { - CONSTANT [8] { value: false } + CONSTANT [23] { value: false } } loop_condition: { - CALL [9] { + CALL [24] { function: @not_strictly_false args: { - CALL [10] { + CALL [25] { function: !_ args: { - IDENT [11] { - name: @x0:1 + IDENT [26] { + name: @x:1 } } } @@ -1787,158 +2271,143 @@ CALL [1] { } } loop_step: { - CALL [12] { + CALL [27] { function: _||_ args: { - IDENT [13] { - name: @x0:1 + IDENT [28] { + name: @x:1 } - CALL [14] { - function: _==_ + CALL [29] { + function: _>_ args: { - IDENT [15] { - name: @c0:1 + IDENT [30] { + name: @c:1 } - CONSTANT [16] { value: "a" } + CONSTANT [31] { value: 0 } } } } } } result: { - IDENT [17] { - name: @x0:1 + IDENT [32] { + name: @x:1 } } } } } - } - loop_condition: { - CONSTANT [18] { value: false } - } - loop_step: { - IDENT [19] { - name: @r1 - } - } - result: { - CALL [20] { - function: _+_ + CALL [33] { + function: _&&_ args: { - CALL [21] { - function: _+_ - args: { - COMPREHENSION [22] { - iter_var: #unused - iter_range: { - LIST [23] { - elements: { + COMPREHENSION [34] { + iter_var: @c:2 + iter_range: { + IDENT [35] { + name: @r0 + } + } + accu_var: @x:2 + accu_init: { + CONSTANT [36] { value: false } + } + loop_condition: { + CALL [37] { + function: @not_strictly_false + args: { + CALL [38] { + function: !_ + args: { + IDENT [39] { + name: @x:2 + } } } } - accu_var: @r0 - accu_init: { - LIST [24] { - elements: { - COMPREHENSION [25] { - iter_var: @c0:0 - iter_range: { - LIST [26] { - elements: { - CONSTANT [27] { value: 1 } - } - } - } - accu_var: @x0:0 - accu_init: { - CONSTANT [28] { value: false } - } - loop_condition: { - CALL [29] { - function: @not_strictly_false - args: { - CALL [30] { - function: !_ - args: { - IDENT [31] { - name: @x0:0 - } - } - } - } - } - } - loop_step: { - CALL [32] { - function: _||_ - args: { - IDENT [33] { - name: @x0:0 - } - CALL [34] { - function: _>_ - args: { - IDENT [35] { - name: @c0:0 - } - CONSTANT [36] { value: 0 } - } - } - } - } - } - result: { - IDENT [37] { - name: @x0:0 - } - } + } + } + loop_step: { + CALL [40] { + function: _||_ + args: { + IDENT [41] { + name: @x:2 + } + CALL [42] { + function: _>_ + args: { + IDENT [43] { + name: @c:2 } + CONSTANT [44] { value: 1 } } } } - loop_condition: { - CONSTANT [38] { value: false } + } + } + result: { + IDENT [45] { + name: @x:2 + } + } + } + COMPREHENSION [46] { + iter_var: @c:3 + iter_range: { + LIST [47] { + elements: { + CONSTANT [48] { value: 2 } } - loop_step: { - IDENT [39] { - name: @r0 + } + } + accu_var: @x:3 + accu_init: { + CONSTANT [49] { value: false } + } + loop_condition: { + CALL [50] { + function: @not_strictly_false + args: { + CALL [51] { + function: !_ + args: { + IDENT [52] { + name: @x:3 + } + } } } - result: { - CALL [40] { - function: _+_ + } + } + loop_step: { + CALL [53] { + function: _||_ + args: { + IDENT [54] { + name: @x:3 + } + CALL [55] { + function: _>_ args: { - IDENT [41] { - name: @r0 - } - IDENT [42] { - name: @r0 + IDENT [56] { + name: @c:3 } + CONSTANT [57] { value: 1 } } } } } - IDENT [43] { - name: @r1 + } + result: { + IDENT [58] { + name: @x:3 } } } - IDENT [44] { - name: @r1 - } } } } } - LIST [45] { - elements: { - CONSTANT [46] { value: true } - CONSTANT [47] { value: true } - CONSTANT [48] { value: true } - CONSTANT [49] { value: true } - } - } } } Test case: NESTED_MACROS @@ -1975,13 +2444,13 @@ CALL [1] { } result: { COMPREHENSION [10] { - iter_var: @c0:0 + iter_var: @c:1 iter_range: { IDENT [11] { name: @r0 } } - accu_var: @x0:0 + accu_var: @x:1 accu_init: { LIST [12] { elements: { @@ -1996,18 +2465,18 @@ CALL [1] { function: _+_ args: { IDENT [15] { - name: @x0:0 + name: @x:1 } LIST [16] { elements: { COMPREHENSION [17] { - iter_var: @c1:0 + iter_var: @c:0 iter_range: { IDENT [18] { name: @r0 } } - accu_var: @x1:0 + accu_var: @x:0 accu_init: { LIST [19] { elements: { @@ -2022,7 +2491,7 @@ CALL [1] { function: _+_ args: { IDENT [22] { - name: @x1:0 + name: @x:0 } LIST [23] { elements: { @@ -2030,7 +2499,7 @@ CALL [1] { function: _+_ args: { IDENT [25] { - name: @c1:0 + name: @c:0 } CONSTANT [26] { value: 1 } } @@ -2042,7 +2511,7 @@ CALL [1] { } result: { IDENT [27] { - name: @x1:0 + name: @x:0 } } } @@ -2053,7 +2522,7 @@ CALL [1] { } result: { IDENT [28] { - name: @x0:0 + name: @x:1 } } } @@ -2110,7 +2579,7 @@ CALL [31] { function: _==_ args: { COMPREHENSION [30] { - iter_var: @c0:0 + iter_var: @c:1 iter_range: { LIST [1] { elements: { @@ -2119,7 +2588,7 @@ CALL [31] { } } } - accu_var: @x0:0 + accu_var: @x:1 accu_init: { LIST [24] { elements: { @@ -2134,12 +2603,12 @@ CALL [31] { function: _+_ args: { IDENT [26] { - name: @x0:0 + name: @x:1 } LIST [27] { elements: { COMPREHENSION [23] { - iter_var: @c1:0 + iter_var: @c:0 iter_range: { LIST [6] { elements: { @@ -2149,7 +2618,7 @@ CALL [31] { } } } - accu_var: @x1:0 + accu_var: @x:0 accu_init: { LIST [15] { elements: { @@ -2167,10 +2636,10 @@ CALL [31] { function: _==_ args: { IDENT [12] { - name: @c1:0 + name: @c:0 } IDENT [14] { - name: @c0:0 + name: @c:1 } } } @@ -2178,26 +2647,26 @@ CALL [31] { function: _+_ args: { IDENT [17] { - name: @x1:0 + name: @x:0 } LIST [18] { elements: { IDENT [11] { - name: @c1:0 + name: @c:0 } } } } } IDENT [20] { - name: @x1:0 + name: @x:0 } } } } result: { IDENT [22] { - name: @x1:0 + name: @x:0 } } } @@ -2208,7 +2677,7 @@ CALL [31] { } result: { IDENT [29] { - name: @x0:0 + name: @x:1 } } } @@ -2465,13 +2934,13 @@ COMPREHENSION [1] { } result: { COMPREHENSION [16] { - iter_var: @c0:0 + iter_var: @c:1 iter_range: { IDENT [17] { name: @r0 } } - accu_var: @x0:0 + accu_var: @x:1 accu_init: { LIST [18] { elements: { @@ -2486,18 +2955,18 @@ COMPREHENSION [1] { function: _+_ args: { IDENT [21] { - name: @x0:0 + name: @x:1 } LIST [22] { elements: { COMPREHENSION [23] { - iter_var: @c1:0 + iter_var: @c:0 iter_range: { IDENT [24] { name: @r0 } } - accu_var: @x1:0 + accu_var: @x:0 accu_init: { LIST [25] { elements: { @@ -2512,7 +2981,7 @@ COMPREHENSION [1] { function: _+_ args: { IDENT [28] { - name: @x1:0 + name: @x:0 } LIST [29] { elements: { @@ -2526,7 +2995,7 @@ COMPREHENSION [1] { } result: { IDENT [31] { - name: @x1:0 + name: @x:0 } } } @@ -2537,7 +3006,7 @@ COMPREHENSION [1] { } result: { IDENT [32] { - name: @x0:0 + name: @x:1 } } } @@ -2654,7 +3123,7 @@ COMPREHENSION [1] { function: _||_ args: { COMPREHENSION [16] { - iter_var: @c0:0 + iter_var: @c:0 iter_range: { LIST [17] { elements: { @@ -2673,7 +3142,7 @@ COMPREHENSION [1] { } } } - accu_var: @x0:0 + accu_var: @x:0 accu_init: { CONSTANT [22] { value: false } } @@ -2685,7 +3154,7 @@ COMPREHENSION [1] { function: !_ args: { IDENT [25] { - name: @x0:0 + name: @x:0 } } } @@ -2697,7 +3166,7 @@ COMPREHENSION [1] { function: _||_ args: { IDENT [27] { - name: @x0:0 + name: @x:0 } CALL [28] { function: _>_ @@ -2706,7 +3175,7 @@ COMPREHENSION [1] { function: _-_ args: { IDENT [30] { - name: @c0:0 + name: @c:0 } CONSTANT [31] { value: 1 } } @@ -2719,7 +3188,7 @@ COMPREHENSION [1] { } result: { IDENT [33] { - name: @x0:0 + name: @x:0 } } } @@ -2736,10 +3205,10 @@ Test case: MACRO_SHADOWED_VARIABLE_2 Source: ["foo", "bar"].map(x, [x + x, x + x]).map(x, [x + x, x + x]) =====> COMPREHENSION [1] { - iter_var: @c0:0 + iter_var: @c:1 iter_range: { COMPREHENSION [2] { - iter_var: @c1:0 + iter_var: @c:0 iter_range: { LIST [3] { elements: { @@ -2748,7 +3217,7 @@ COMPREHENSION [1] { } } } - accu_var: @x1:0 + accu_var: @x:0 accu_init: { LIST [6] { elements: { @@ -2763,7 +3232,7 @@ COMPREHENSION [1] { function: _+_ args: { IDENT [9] { - name: @x1:0 + name: @x:0 } LIST [10] { elements: { @@ -2781,10 +3250,10 @@ COMPREHENSION [1] { function: _+_ args: { IDENT [14] { - name: @c1:0 + name: @c:0 } IDENT [15] { - name: @c1:0 + name: @c:0 } } } @@ -2817,12 +3286,12 @@ COMPREHENSION [1] { } result: { IDENT [21] { - name: @x1:0 + name: @x:0 } } } } - accu_var: @x0:0 + accu_var: @x:1 accu_init: { LIST [22] { elements: { @@ -2837,7 +3306,7 @@ COMPREHENSION [1] { function: _+_ args: { IDENT [25] { - name: @x0:0 + name: @x:1 } LIST [26] { elements: { @@ -2855,10 +3324,10 @@ COMPREHENSION [1] { function: _+_ args: { IDENT [30] { - name: @c0:0 + name: @c:1 } IDENT [31] { - name: @c0:0 + name: @c:1 } } } @@ -2891,7 +3360,7 @@ COMPREHENSION [1] { } result: { IDENT [37] { - name: @x0:0 + name: @x:1 } } } @@ -4154,4 +4623,4 @@ CALL [1] { } } } -} +} \ No newline at end of file diff --git a/optimizer/src/test/resources/subexpression_unparsed.baseline b/optimizer/src/test/resources/subexpression_unparsed.baseline index 1c4c11f7b..831290039 100644 --- a/optimizer/src/test/resources/subexpression_unparsed.baseline +++ b/optimizer/src/test/resources/subexpression_unparsed.baseline @@ -274,65 +274,81 @@ Test case: MULTIPLE_MACROS_1 Source: size([[1].exists(i, i > 0)]) + size([[1].exists(j, j > 0)]) + size([[2].exists(k, k > 1)]) + size([[2].exists(l, l > 1)]) == 4 =====> Result: true -[CASCADED_BINDS]: cel.bind(@r1, size([[2].exists(@c0:0, @c0:0 > 1)]), cel.bind(@r0, size([[1].exists(@c0:0, @c0:0 > 0)]), @r0 + @r0) + @r1 + @r1) == 4 -[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([size([[1].exists(@c0:0, @c0:0 > 0)]), size([[2].exists(@c0:0, @c0:0 > 1)])], @index0 + @index0 + @index1 + @index1 == 4) -[BLOCK_RECURSION_DEPTH_1]: cel.@block([[1], @c0:0 > 0, @x0:0 || @index1, [2], @c0:0 > 1, @x0:0 || @index4], size([@index0.exists(@c0:0, @index1)]) + size([@index0.exists(@c0:0, @index1)]) + size([@index3.exists(@c0:0, @index4)]) + size([@index3.exists(@c0:0, @index4)]) == 4) -[BLOCK_RECURSION_DEPTH_2]: cel.@block([@x0:0 || @c0:0 > 0, @x0:0 || @c0:0 > 1, [1], [2]], size([@index2.exists(@c0:0, @c0:0 > 0)]) + size([@index2.exists(@c0:0, @c0:0 > 0)]) + size([@index3.exists(@c0:0, @c0:0 > 1)]) + size([@index3.exists(@c0:0, @c0:0 > 1)]) == 4) -[BLOCK_RECURSION_DEPTH_3]: cel.@block([[1].exists(@c0:0, @c0:0 > 0), [2].exists(@c0:0, @c0:0 > 1), size([@index0]), size([@index1]), @index2 + @index2 + @index3 + @index3], @index4 == 4) -[BLOCK_RECURSION_DEPTH_4]: cel.@block([[[1].exists(@c0:0, @c0:0 > 0)], [[2].exists(@c0:0, @c0:0 > 1)], size(@index0), size(@index1)], @index2 + @index2 + @index3 + @index3 == 4) -[BLOCK_RECURSION_DEPTH_5]: cel.@block([size([[1].exists(@c0:0, @c0:0 > 0)]), size([[2].exists(@c0:0, @c0:0 > 1)])], @index0 + @index0 + @index1 + @index1 == 4) -[BLOCK_RECURSION_DEPTH_6]: cel.@block([size([[1].exists(@c0:0, @c0:0 > 0)]), size([[2].exists(@c0:0, @c0:0 > 1)])], @index0 + @index0 + @index1 + @index1 == 4) -[BLOCK_RECURSION_DEPTH_7]: cel.@block([size([[1].exists(@c0:0, @c0:0 > 0)]), size([[2].exists(@c0:0, @c0:0 > 1)])], @index0 + @index0 + @index1 + @index1 == 4) -[BLOCK_RECURSION_DEPTH_8]: cel.@block([size([[1].exists(@c0:0, @c0:0 > 0)]), size([[2].exists(@c0:0, @c0:0 > 1)])], @index0 + @index0 + @index1 + @index1 == 4) -[BLOCK_RECURSION_DEPTH_9]: cel.@block([size([[1].exists(@c0:0, @c0:0 > 0)]), size([[2].exists(@c0:0, @c0:0 > 1)])], @index0 + @index0 + @index1 + @index1 == 4) +[CASCADED_BINDS]: cel.bind(@r1, [2], cel.bind(@r0, [1], size([@r0.exists(@c:0, @c:0 > 0)]) + size([@r0.exists(@c:1, @c:1 > 0)])) + size([@r1.exists(@c:2, @c:2 > 1)]) + size([@r1.exists(@c:3, @c:3 > 1)])) == 4 +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([[1], [2]], size([@index0.exists(@c:0, @c:0 > 0)]) + size([@index0.exists(@c:1, @c:1 > 0)]) + size([@index1.exists(@c:2, @c:2 > 1)]) + size([@index1.exists(@c:3, @c:3 > 1)]) == 4) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([[1], [2], @c:0 > 0, @x:0 || @index2, @c:1 > 0, @x:1 || @index4, @c:2 > 1, @x:2 || @index6, @c:3 > 1, @x:3 || @index8], size([@index0.exists(@c:0, @index2)]) + size([@index0.exists(@c:1, @index4)]) + size([@index1.exists(@c:2, @index6)]) + size([@index1.exists(@c:3, @index8)]) == 4) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([[1], [2], @x:0 || @c:0 > 0, @x:1 || @c:1 > 0, @x:2 || @c:2 > 1, @x:3 || @c:3 > 1], size([@index0.exists(@c:0, @c:0 > 0)]) + size([@index0.exists(@c:1, @c:1 > 0)]) + size([@index1.exists(@c:2, @c:2 > 1)]) + size([@index1.exists(@c:3, @c:3 > 1)]) == 4) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([[1], [2], @index0.exists(@c:0, @c:0 > 0), @index0.exists(@c:1, @c:1 > 0), size([@index2]) + size([@index3]), @index1.exists(@c:2, @c:2 > 1), @index4 + size([@index5]), @index1.exists(@c:3, @c:3 > 1), @index6 + size([@index7])], @index8 == 4) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([[1], [2], [@index0.exists(@c:0, @c:0 > 0)], [@index0.exists(@c:1, @c:1 > 0)], [@index1.exists(@c:2, @c:2 > 1)], [@index1.exists(@c:3, @c:3 > 1)], size(@index2) + size(@index3) + size(@index4) + size(@index5)], @index6 == 4) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([[1], [2], size([@index0.exists(@c:0, @c:0 > 0)]), size([@index0.exists(@c:1, @c:1 > 0)]), size([@index1.exists(@c:2, @c:2 > 1)]), size([@index1.exists(@c:3, @c:3 > 1)])], @index2 + @index3 + @index4 + @index5 == 4) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([[1], [2], size([@index0.exists(@c:0, @c:0 > 0)]) + size([@index0.exists(@c:1, @c:1 > 0)]), @index2 + size([@index1.exists(@c:2, @c:2 > 1)]), @index3 + size([@index1.exists(@c:3, @c:3 > 1)])], @index4 == 4) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([[1], [2], size([@index0.exists(@c:0, @c:0 > 0)]) + size([@index0.exists(@c:1, @c:1 > 0)]) + size([@index1.exists(@c:2, @c:2 > 1)])], @index2 + size([@index1.exists(@c:3, @c:3 > 1)]) == 4) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([[1], [2], size([@index0.exists(@c:0, @c:0 > 0)]) + size([@index0.exists(@c:1, @c:1 > 0)]) + size([@index1.exists(@c:2, @c:2 > 1)]) + size([@index1.exists(@c:3, @c:3 > 1)])], @index2 == 4) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([[1], [2]], size([@index0.exists(@c:0, @c:0 > 0)]) + size([@index0.exists(@c:1, @c:1 > 0)]) + size([@index1.exists(@c:2, @c:2 > 1)]) + size([@index1.exists(@c:3, @c:3 > 1)]) == 4) Test case: MULTIPLE_MACROS_2 Source: [[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == 'a')] + [['a'].exists(l, l == 'a')] == [true, true, true, true] =====> Result: true -[CASCADED_BINDS]: cel.bind(@r1, [["a"].exists(@c0:1, @c0:1 == "a")], cel.bind(@r0, [[1].exists(@c0:0, @c0:0 > 0)], @r0 + @r0) + @r1 + @r1) == [true, true, true, true] -[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([[[1].exists(@c0:0, @c0:0 > 0)], [["a"].exists(@c0:1, @c0:1 == "a")]], @index0 + @index0 + @index1 + @index1 == [true, true, true, true]) -[BLOCK_RECURSION_DEPTH_1]: cel.@block([[1], @c0:0 > 0, @x0:0 || @index1, ["a"], @c0:1 == "a", @x0:1 || @index4, [true, true, true, true]], [@index0.exists(@c0:0, @index1)] + [@index0.exists(@c0:0, @index1)] + [@index3.exists(@c0:1, @index4)] + [@index3.exists(@c0:1, @index4)] == @index6) -[BLOCK_RECURSION_DEPTH_2]: cel.@block([@x0:0 || @c0:0 > 0, @x0:1 || @c0:1 == "a", [1], ["a"], [true, true, true, true]], [@index2.exists(@c0:0, @c0:0 > 0)] + [@index2.exists(@c0:0, @c0:0 > 0)] + [@index3.exists(@c0:1, @c0:1 == "a")] + [@index3.exists(@c0:1, @c0:1 == "a")] == @index4) -[BLOCK_RECURSION_DEPTH_3]: cel.@block([[1].exists(@c0:0, @c0:0 > 0), ["a"].exists(@c0:1, @c0:1 == "a"), [@index0], [@index1], @index2 + @index2 + @index3 + @index3], @index4 == [true, true, true, true]) -[BLOCK_RECURSION_DEPTH_4]: cel.@block([[[1].exists(@c0:0, @c0:0 > 0)], [["a"].exists(@c0:1, @c0:1 == "a")]], @index0 + @index0 + @index1 + @index1 == [true, true, true, true]) -[BLOCK_RECURSION_DEPTH_5]: cel.@block([[[1].exists(@c0:0, @c0:0 > 0)], [["a"].exists(@c0:1, @c0:1 == "a")]], @index0 + @index0 + @index1 + @index1 == [true, true, true, true]) -[BLOCK_RECURSION_DEPTH_6]: cel.@block([[[1].exists(@c0:0, @c0:0 > 0)], [["a"].exists(@c0:1, @c0:1 == "a")]], @index0 + @index0 + @index1 + @index1 == [true, true, true, true]) -[BLOCK_RECURSION_DEPTH_7]: cel.@block([[[1].exists(@c0:0, @c0:0 > 0)], [["a"].exists(@c0:1, @c0:1 == "a")]], @index0 + @index0 + @index1 + @index1 == [true, true, true, true]) -[BLOCK_RECURSION_DEPTH_8]: cel.@block([[[1].exists(@c0:0, @c0:0 > 0)], [["a"].exists(@c0:1, @c0:1 == "a")]], @index0 + @index0 + @index1 + @index1 == [true, true, true, true]) -[BLOCK_RECURSION_DEPTH_9]: cel.@block([[[1].exists(@c0:0, @c0:0 > 0)], [["a"].exists(@c0:1, @c0:1 == "a")]], @index0 + @index0 + @index1 + @index1 == [true, true, true, true]) +[CASCADED_BINDS]: cel.bind(@r1, ["a"], cel.bind(@r0, [1], [@r0.exists(@c:0, @c:0 > 0)] + [@r0.exists(@c:1, @c:1 > 0)]) + [@r1.exists(@c:2, @c:2 == "a")] + [@r1.exists(@c:3, @c:3 == "a")]) == [true, true, true, true] +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([[1], ["a"]], [@index0.exists(@c:0, @c:0 > 0)] + [@index0.exists(@c:1, @c:1 > 0)] + [@index1.exists(@c:2, @c:2 == "a")] + [@index1.exists(@c:3, @c:3 == "a")] == [true, true, true, true]) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([[1], ["a"], @c:0 > 0, @x:0 || @index2, @c:1 > 0, @x:1 || @index4, @c:2 == "a", @x:2 || @index6, @c:3 == "a", @x:3 || @index8, [true, true, true, true]], [@index0.exists(@c:0, @index2)] + [@index0.exists(@c:1, @index4)] + [@index1.exists(@c:2, @index6)] + [@index1.exists(@c:3, @index8)] == @index10) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([[1], ["a"], @x:0 || @c:0 > 0, @x:1 || @c:1 > 0, @x:2 || @c:2 == "a", @x:3 || @c:3 == "a", [true, true, true, true]], [@index0.exists(@c:0, @c:0 > 0)] + [@index0.exists(@c:1, @c:1 > 0)] + [@index1.exists(@c:2, @c:2 == "a")] + [@index1.exists(@c:3, @c:3 == "a")] == @index6) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([[1], ["a"], @index0.exists(@c:0, @c:0 > 0), @index0.exists(@c:1, @c:1 > 0), @index1.exists(@c:2, @c:2 == "a"), [@index2] + [@index3] + [@index4], @index1.exists(@c:3, @c:3 == "a")], @index5 + [@index6] == [true, true, true, true]) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([[1], ["a"], [@index0.exists(@c:0, @c:0 > 0)], [@index0.exists(@c:1, @c:1 > 0)], [@index1.exists(@c:2, @c:2 == "a")], [@index1.exists(@c:3, @c:3 == "a")]], @index2 + @index3 + @index4 + @index5 == [true, true, true, true]) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([[1], ["a"], [@index0.exists(@c:0, @c:0 > 0)] + [@index0.exists(@c:1, @c:1 > 0)], @index2 + [@index1.exists(@c:2, @c:2 == "a")], @index3 + [@index1.exists(@c:3, @c:3 == "a")]], @index4 == [true, true, true, true]) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([[1], ["a"], [@index0.exists(@c:0, @c:0 > 0)] + [@index0.exists(@c:1, @c:1 > 0)] + [@index1.exists(@c:2, @c:2 == "a")]], @index2 + [@index1.exists(@c:3, @c:3 == "a")] == [true, true, true, true]) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([[1], ["a"], [@index0.exists(@c:0, @c:0 > 0)] + [@index0.exists(@c:1, @c:1 > 0)] + [@index1.exists(@c:2, @c:2 == "a")] + [@index1.exists(@c:3, @c:3 == "a")]], @index2 == [true, true, true, true]) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([[1], ["a"]], [@index0.exists(@c:0, @c:0 > 0)] + [@index0.exists(@c:1, @c:1 > 0)] + [@index1.exists(@c:2, @c:2 == "a")] + [@index1.exists(@c:3, @c:3 == "a")] == [true, true, true, true]) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([[1], ["a"]], [@index0.exists(@c:0, @c:0 > 0)] + [@index0.exists(@c:1, @c:1 > 0)] + [@index1.exists(@c:2, @c:2 == "a")] + [@index1.exists(@c:3, @c:3 == "a")] == [true, true, true, true]) + +Test case: MULTIPLE_MACROS_3 +Source: [1].exists(i, i > 0) && [1].exists(j, j > 0) && [1].exists(k, k > 1) && [2].exists(l, l > 1) +=====> +Result: false +[CASCADED_BINDS]: cel.bind(@r0, [1], @r0.exists(@c:0, @c:0 > 0) && @r0.exists(@c:1, @c:1 > 0) && @r0.exists(@c:2, @c:2 > 1) && [2].exists(@c:3, @c:3 > 1)) +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([[1]], @index0.exists(@c:0, @c:0 > 0) && @index0.exists(@c:1, @c:1 > 0) && @index0.exists(@c:2, @c:2 > 1) && [2].exists(@c:3, @c:3 > 1)) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([[1], @c:0 > 0, @x:0 || @index1, @c:1 > 0, @x:1 || @index3, @c:2 > 1, @x:2 || @index5, [2], @c:3 > 1, @x:3 || @index8], @index0.exists(@c:0, @index1) && @index0.exists(@c:1, @index3) && @index0.exists(@c:2, @index5) && @index7.exists(@c:3, @index8)) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([[1], @x:0 || @c:0 > 0, @x:1 || @c:1 > 0, @x:2 || @c:2 > 1, @x:3 || @c:3 > 1, [2]], @index0.exists(@c:0, @c:0 > 0) && @index0.exists(@c:1, @c:1 > 0) && @index0.exists(@c:2, @c:2 > 1) && @index5.exists(@c:3, @c:3 > 1)) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([[1], @index0.exists(@c:0, @c:0 > 0), @index0.exists(@c:1, @c:1 > 0), @index0.exists(@c:2, @c:2 > 1), [2].exists(@c:3, @c:3 > 1)], @index1 && @index2 && @index3 && @index4) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([[1], @index0.exists(@c:0, @c:0 > 0) && @index0.exists(@c:1, @c:1 > 0), @index0.exists(@c:2, @c:2 > 1) && [2].exists(@c:3, @c:3 > 1)], @index1 && @index2) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([[1]], @index0.exists(@c:0, @c:0 > 0) && @index0.exists(@c:1, @c:1 > 0) && @index0.exists(@c:2, @c:2 > 1) && [2].exists(@c:3, @c:3 > 1)) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([[1]], @index0.exists(@c:0, @c:0 > 0) && @index0.exists(@c:1, @c:1 > 0) && @index0.exists(@c:2, @c:2 > 1) && [2].exists(@c:3, @c:3 > 1)) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([[1]], @index0.exists(@c:0, @c:0 > 0) && @index0.exists(@c:1, @c:1 > 0) && @index0.exists(@c:2, @c:2 > 1) && [2].exists(@c:3, @c:3 > 1)) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([[1]], @index0.exists(@c:0, @c:0 > 0) && @index0.exists(@c:1, @c:1 > 0) && @index0.exists(@c:2, @c:2 > 1) && [2].exists(@c:3, @c:3 > 1)) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([[1]], @index0.exists(@c:0, @c:0 > 0) && @index0.exists(@c:1, @c:1 > 0) && @index0.exists(@c:2, @c:2 > 1) && [2].exists(@c:3, @c:3 > 1)) Test case: NESTED_MACROS Source: [1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [[2, 3, 4], [2, 3, 4], [2, 3, 4]] =====> Result: true -[CASCADED_BINDS]: cel.bind(@r0, [1, 2, 3], @r0.map(@c0:0, @r0.map(@c1:0, @c1:0 + 1))) == cel.bind(@r1, [2, 3, 4], [@r1, @r1, @r1]) -[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([[1, 2, 3], [2, 3, 4]], @index0.map(@c0:0, @index0.map(@c1:0, @c1:0 + 1)) == [@index1, @index1, @index1]) -[BLOCK_RECURSION_DEPTH_1]: cel.@block([[1, 2, 3], [2, 3, 4], @c1:0 + 1, [@index2], @x1:0 + @index3, [@index1, @index1, @index1]], @index0.map(@c0:0, @index0.map(@c1:0, @index2)) == @index5) -[BLOCK_RECURSION_DEPTH_2]: cel.@block([[1, 2, 3], [2, 3, 4], [@c1:0 + 1], @index0.map(@c1:0, @c1:0 + 1), @x0:0 + [@index3], @index0.map(@c0:0, @index3)], @index5 == [@index1, @index1, @index1]) -[BLOCK_RECURSION_DEPTH_3]: cel.@block([[1, 2, 3], [2, 3, 4], @x1:0 + [@c1:0 + 1], [@index0.map(@c1:0, @c1:0 + 1)]], @index0.map(@c0:0) == [@index1, @index1, @index1]) -[BLOCK_RECURSION_DEPTH_4]: cel.@block([[1, 2, 3], [2, 3, 4], @index0.map(@c1:0, @c1:0 + 1)], @index0.map(@c0:0, @index2) == [@index1, @index1, @index1]) -[BLOCK_RECURSION_DEPTH_5]: cel.@block([[1, 2, 3], [2, 3, 4], [@index0.map(@c1:0, @c1:0 + 1)]], @index0.map(@c0:0) == [@index1, @index1, @index1]) -[BLOCK_RECURSION_DEPTH_6]: cel.@block([[1, 2, 3], [2, 3, 4], @x0:0 + [@index0.map(@c1:0, @c1:0 + 1)]], @index0.map(@c0:0) == [@index1, @index1, @index1]) -[BLOCK_RECURSION_DEPTH_7]: cel.@block([[1, 2, 3], [2, 3, 4], @index0.map(@c0:0, @index0.map(@c1:0, @c1:0 + 1))], @index2 == [@index1, @index1, @index1]) -[BLOCK_RECURSION_DEPTH_8]: cel.@block([[1, 2, 3], [2, 3, 4]], @index0.map(@c0:0, @index0.map(@c1:0, @c1:0 + 1)) == [@index1, @index1, @index1]) -[BLOCK_RECURSION_DEPTH_9]: cel.@block([[1, 2, 3], [2, 3, 4]], @index0.map(@c0:0, @index0.map(@c1:0, @c1:0 + 1)) == [@index1, @index1, @index1]) +[CASCADED_BINDS]: cel.bind(@r0, [1, 2, 3], @r0.map(@c:1, @r0.map(@c:0, @c:0 + 1))) == cel.bind(@r1, [2, 3, 4], [@r1, @r1, @r1]) +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([[1, 2, 3], [2, 3, 4]], @index0.map(@c:1, @index0.map(@c:0, @c:0 + 1)) == [@index1, @index1, @index1]) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([[1, 2, 3], [2, 3, 4], @c:0 + 1, [@index2], @x:0 + @index3, [@index1, @index1, @index1]], @index0.map(@c:1, @index0.map(@c:0, @index2)) == @index5) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([[1, 2, 3], [2, 3, 4], [@c:0 + 1], @index0.map(@c:0, @c:0 + 1), @x:1 + [@index3], @index0.map(@c:1, @index3)], @index5 == [@index1, @index1, @index1]) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([[1, 2, 3], [2, 3, 4], @x:0 + [@c:0 + 1], [@index0.map(@c:0, @c:0 + 1)]], @index0.map(@c:1) == [@index1, @index1, @index1]) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([[1, 2, 3], [2, 3, 4], @index0.map(@c:0, @c:0 + 1)], @index0.map(@c:1, @index2) == [@index1, @index1, @index1]) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([[1, 2, 3], [2, 3, 4], [@index0.map(@c:0, @c:0 + 1)]], @index0.map(@c:1) == [@index1, @index1, @index1]) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([[1, 2, 3], [2, 3, 4], @x:1 + [@index0.map(@c:0, @c:0 + 1)]], @index0.map(@c:1) == [@index1, @index1, @index1]) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([[1, 2, 3], [2, 3, 4], @index0.map(@c:1, @index0.map(@c:0, @c:0 + 1))], @index2 == [@index1, @index1, @index1]) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([[1, 2, 3], [2, 3, 4]], @index0.map(@c:1, @index0.map(@c:0, @c:0 + 1)) == [@index1, @index1, @index1]) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([[1, 2, 3], [2, 3, 4]], @index0.map(@c:1, @index0.map(@c:0, @c:0 + 1)) == [@index1, @index1, @index1]) Test case: NESTED_MACROS_2 Source: [1, 2].map(y, [1, 2, 3].filter(x, x == y)) == [[1], [2]] =====> Result: true -[CASCADED_BINDS]: [1, 2].map(@c0:0, [1, 2, 3].filter(@c1:0, @c1:0 == @c0:0)) == [[1], [2]] -[BLOCK_COMMON_SUBEXPR_ONLY]: [1, 2].map(@c0:0, [1, 2, 3].filter(@c1:0, @c1:0 == @c0:0)) == [[1], [2]] -[BLOCK_RECURSION_DEPTH_1]: cel.@block([[1, 2], [1, 2, 3], @c1:0 == @c0:0, [@c1:0], @x1:0 + @index3, @index2 ? @index4 : @x1:0, [1], [2], [@index6, @index7]], @index0.map(@c0:0, @index1.filter(@c1:0, @index2)) == @index8) -[BLOCK_RECURSION_DEPTH_2]: cel.@block([@x1:0 + [@c1:0], (@c1:0 == @c0:0) ? @index0 : @x1:0, [1, 2, 3].filter(@c1:0, @c1:0 == @c0:0), @x0:0 + [@index2], [1, 2].map(@c0:0, @index2), [[1], [2]]], @index4 == @index5) -[BLOCK_RECURSION_DEPTH_3]: cel.@block([(@c1:0 == @c0:0) ? (@x1:0 + [@c1:0]) : @x1:0, [[1, 2, 3].filter(@c1:0, @c1:0 == @c0:0)]], [1, 2].map(@c0:0) == [[1], [2]]) -[BLOCK_RECURSION_DEPTH_4]: cel.@block([[1, 2, 3].filter(@c1:0, @c1:0 == @c0:0)], [1, 2].map(@c0:0, @index0) == [[1], [2]]) -[BLOCK_RECURSION_DEPTH_5]: cel.@block([[[1, 2, 3].filter(@c1:0, @c1:0 == @c0:0)]], [1, 2].map(@c0:0) == [[1], [2]]) -[BLOCK_RECURSION_DEPTH_6]: cel.@block([@x0:0 + [[1, 2, 3].filter(@c1:0, @c1:0 == @c0:0)]], [1, 2].map(@c0:0) == [[1], [2]]) -[BLOCK_RECURSION_DEPTH_7]: cel.@block([[1, 2].map(@c0:0, [1, 2, 3].filter(@c1:0, @c1:0 == @c0:0))], @index0 == [[1], [2]]) -[BLOCK_RECURSION_DEPTH_8]: [1, 2].map(@c0:0, [1, 2, 3].filter(@c1:0, @c1:0 == @c0:0)) == [[1], [2]] -[BLOCK_RECURSION_DEPTH_9]: [1, 2].map(@c0:0, [1, 2, 3].filter(@c1:0, @c1:0 == @c0:0)) == [[1], [2]] +[CASCADED_BINDS]: [1, 2].map(@c:1, [1, 2, 3].filter(@c:0, @c:0 == @c:1)) == [[1], [2]] +[BLOCK_COMMON_SUBEXPR_ONLY]: [1, 2].map(@c:1, [1, 2, 3].filter(@c:0, @c:0 == @c:1)) == [[1], [2]] +[BLOCK_RECURSION_DEPTH_1]: cel.@block([[1, 2], [1, 2, 3], @c:0 == @c:1, [@c:0], @x:0 + @index3, @index2 ? @index4 : @x:0, [1], [2], [@index6, @index7]], @index0.map(@c:1, @index1.filter(@c:0, @index2)) == @index8) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([@x:0 + [@c:0], (@c:0 == @c:1) ? @index0 : @x:0, [1, 2, 3].filter(@c:0, @c:0 == @c:1), @x:1 + [@index2], [1, 2].map(@c:1, @index2), [[1], [2]]], @index4 == @index5) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([(@c:0 == @c:1) ? (@x:0 + [@c:0]) : @x:0, [[1, 2, 3].filter(@c:0, @c:0 == @c:1)]], [1, 2].map(@c:1) == [[1], [2]]) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([[1, 2, 3].filter(@c:0, @c:0 == @c:1)], [1, 2].map(@c:1, @index0) == [[1], [2]]) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([[[1, 2, 3].filter(@c:0, @c:0 == @c:1)]], [1, 2].map(@c:1) == [[1], [2]]) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([@x:1 + [[1, 2, 3].filter(@c:0, @c:0 == @c:1)]], [1, 2].map(@c:1) == [[1], [2]]) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([[1, 2].map(@c:1, [1, 2, 3].filter(@c:0, @c:0 == @c:1))], @index0 == [[1], [2]]) +[BLOCK_RECURSION_DEPTH_8]: [1, 2].map(@c:1, [1, 2, 3].filter(@c:0, @c:0 == @c:1)) == [[1], [2]] +[BLOCK_RECURSION_DEPTH_9]: [1, 2].map(@c:1, [1, 2, 3].filter(@c:0, @c:0 == @c:1)) == [[1], [2]] Test case: INCLUSION_LIST Source: 1 in [1,2,3] && 2 in [1,2,3] && 3 in [3, [1,2,3]] && 1 in [1,2,3] @@ -370,49 +386,49 @@ Test case: MACRO_ITER_VAR_NOT_REFERENCED Source: [1,2].map(i, [1, 2].map(i, [3,4])) == [[[3, 4], [3, 4]], [[3, 4], [3, 4]]] =====> Result: true -[CASCADED_BINDS]: cel.bind(@r1, [3, 4], cel.bind(@r0, [1, 2], @r0.map(@c0:0, @r0.map(@c1:0, @r1))) == cel.bind(@r2, [@r1, @r1], [@r2, @r2])) -[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([[1, 2], [3, 4], [@index1, @index1]], @index0.map(@c0:0, @index0.map(@c1:0, @index1)) == [@index2, @index2]) -[BLOCK_RECURSION_DEPTH_1]: cel.@block([[1, 2], [3, 4], [@index1, @index1], [@index1], @x1:0 + @index3, [@index2, @index2]], @index0.map(@c0:0, @index0.map(@c1:0, @index1)) == @index5) -[BLOCK_RECURSION_DEPTH_2]: cel.@block([[[3, 4], [3, 4]], [1, 2], [[3, 4]], @index1.map(@c1:0, [3, 4]), @x0:0 + [@index3], @index1.map(@c0:0, @index3)], @index5 == [@index0, @index0]) -[BLOCK_RECURSION_DEPTH_3]: cel.@block([[[3, 4], [3, 4]], [1, 2], @x1:0 + [[3, 4]], [@index1.map(@c1:0, [3, 4])]], @index1.map(@c0:0) == [@index0, @index0]) -[BLOCK_RECURSION_DEPTH_4]: cel.@block([[[3, 4], [3, 4]], [1, 2], @index1.map(@c1:0, [3, 4])], @index1.map(@c0:0, @index2) == [@index0, @index0]) -[BLOCK_RECURSION_DEPTH_5]: cel.@block([[[3, 4], [3, 4]], [1, 2], [@index1.map(@c1:0, [3, 4])]], @index1.map(@c0:0) == [@index0, @index0]) -[BLOCK_RECURSION_DEPTH_6]: cel.@block([[[3, 4], [3, 4]], [1, 2], @x0:0 + [@index1.map(@c1:0, [3, 4])]], @index1.map(@c0:0) == [@index0, @index0]) -[BLOCK_RECURSION_DEPTH_7]: cel.@block([[[3, 4], [3, 4]], [1, 2], @index1.map(@c0:0, @index1.map(@c1:0, [3, 4]))], @index2 == [@index0, @index0]) -[BLOCK_RECURSION_DEPTH_8]: cel.@block([[[3, 4], [3, 4]], [1, 2]], @index1.map(@c0:0, @index1.map(@c1:0, [3, 4])) == [@index0, @index0]) -[BLOCK_RECURSION_DEPTH_9]: cel.@block([[[3, 4], [3, 4]], [1, 2]], @index1.map(@c0:0, @index1.map(@c1:0, [3, 4])) == [@index0, @index0]) +[CASCADED_BINDS]: cel.bind(@r1, [3, 4], cel.bind(@r0, [1, 2], @r0.map(@c:1, @r0.map(@c:0, @r1))) == cel.bind(@r2, [@r1, @r1], [@r2, @r2])) +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([[1, 2], [3, 4], [@index1, @index1]], @index0.map(@c:1, @index0.map(@c:0, @index1)) == [@index2, @index2]) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([[1, 2], [3, 4], [@index1, @index1], [@index1], @x:0 + @index3, [@index2, @index2]], @index0.map(@c:1, @index0.map(@c:0, @index1)) == @index5) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([[[3, 4], [3, 4]], [1, 2], [[3, 4]], @index1.map(@c:0, [3, 4]), @x:1 + [@index3], @index1.map(@c:1, @index3)], @index5 == [@index0, @index0]) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([[[3, 4], [3, 4]], [1, 2], @x:0 + [[3, 4]], [@index1.map(@c:0, [3, 4])]], @index1.map(@c:1) == [@index0, @index0]) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([[[3, 4], [3, 4]], [1, 2], @index1.map(@c:0, [3, 4])], @index1.map(@c:1, @index2) == [@index0, @index0]) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([[[3, 4], [3, 4]], [1, 2], [@index1.map(@c:0, [3, 4])]], @index1.map(@c:1) == [@index0, @index0]) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([[[3, 4], [3, 4]], [1, 2], @x:1 + [@index1.map(@c:0, [3, 4])]], @index1.map(@c:1) == [@index0, @index0]) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([[[3, 4], [3, 4]], [1, 2], @index1.map(@c:1, @index1.map(@c:0, [3, 4]))], @index2 == [@index0, @index0]) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([[[3, 4], [3, 4]], [1, 2]], @index1.map(@c:1, @index1.map(@c:0, [3, 4])) == [@index0, @index0]) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([[[3, 4], [3, 4]], [1, 2]], @index1.map(@c:1, @index1.map(@c:0, [3, 4])) == [@index0, @index0]) Test case: MACRO_SHADOWED_VARIABLE Source: [x - 1 > 3 ? x - 1 : 5].exists(x, x - 1 > 3) || x - 1 > 3 =====> Result: true -[CASCADED_BINDS]: cel.bind(@r0, x - 1, cel.bind(@r1, @r0 > 3, [@r1 ? @r0 : 5].exists(@c0:0, @c0:0 - 1 > 3) || @r1)) -[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([x - 1, @index0 > 3], [@index1 ? @index0 : 5].exists(@c0:0, @c0:0 - 1 > 3) || @index1) -[BLOCK_RECURSION_DEPTH_1]: cel.@block([x - 1, @index0 > 3, @index1 ? @index0 : 5, [@index2], @c0:0 - 1, @index4 > 3, @x0:0 || @index5], @index3.exists(@c0:0, @index5) || @index1) -[BLOCK_RECURSION_DEPTH_2]: cel.@block([x - 1 > 3, @index0 ? (x - 1) : 5, @c0:0 - 1 > 3, [@index1], @x0:0 || @index2], @index3.exists(@c0:0, @index2) || @index0) -[BLOCK_RECURSION_DEPTH_3]: cel.@block([x - 1 > 3, [@index0 ? (x - 1) : 5], @x0:0 || @c0:0 - 1 > 3, @index1.exists(@c0:0, @c0:0 - 1 > 3)], @index3 || @index0) -[BLOCK_RECURSION_DEPTH_4]: cel.@block([x - 1 > 3, [@index0 ? (x - 1) : 5].exists(@c0:0, @c0:0 - 1 > 3)], @index1 || @index0) -[BLOCK_RECURSION_DEPTH_5]: cel.@block([x - 1 > 3], [@index0 ? (x - 1) : 5].exists(@c0:0, @c0:0 - 1 > 3) || @index0) -[BLOCK_RECURSION_DEPTH_6]: cel.@block([x - 1 > 3], [@index0 ? (x - 1) : 5].exists(@c0:0, @c0:0 - 1 > 3) || @index0) -[BLOCK_RECURSION_DEPTH_7]: cel.@block([x - 1 > 3], [@index0 ? (x - 1) : 5].exists(@c0:0, @c0:0 - 1 > 3) || @index0) -[BLOCK_RECURSION_DEPTH_8]: cel.@block([x - 1 > 3], [@index0 ? (x - 1) : 5].exists(@c0:0, @c0:0 - 1 > 3) || @index0) -[BLOCK_RECURSION_DEPTH_9]: cel.@block([x - 1 > 3], [@index0 ? (x - 1) : 5].exists(@c0:0, @c0:0 - 1 > 3) || @index0) +[CASCADED_BINDS]: cel.bind(@r0, x - 1, cel.bind(@r1, @r0 > 3, [@r1 ? @r0 : 5].exists(@c:0, @c:0 - 1 > 3) || @r1)) +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([x - 1, @index0 > 3], [@index1 ? @index0 : 5].exists(@c:0, @c:0 - 1 > 3) || @index1) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([x - 1, @index0 > 3, @index1 ? @index0 : 5, [@index2], @c:0 - 1, @index4 > 3, @x:0 || @index5], @index3.exists(@c:0, @index5) || @index1) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([x - 1 > 3, @index0 ? (x - 1) : 5, @c:0 - 1 > 3, [@index1], @x:0 || @index2], @index3.exists(@c:0, @index2) || @index0) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([x - 1 > 3, [@index0 ? (x - 1) : 5], @x:0 || @c:0 - 1 > 3, @index1.exists(@c:0, @c:0 - 1 > 3)], @index3 || @index0) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([x - 1 > 3, [@index0 ? (x - 1) : 5].exists(@c:0, @c:0 - 1 > 3)], @index1 || @index0) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([x - 1 > 3], [@index0 ? (x - 1) : 5].exists(@c:0, @c:0 - 1 > 3) || @index0) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([x - 1 > 3], [@index0 ? (x - 1) : 5].exists(@c:0, @c:0 - 1 > 3) || @index0) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([x - 1 > 3], [@index0 ? (x - 1) : 5].exists(@c:0, @c:0 - 1 > 3) || @index0) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([x - 1 > 3], [@index0 ? (x - 1) : 5].exists(@c:0, @c:0 - 1 > 3) || @index0) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([x - 1 > 3], [@index0 ? (x - 1) : 5].exists(@c:0, @c:0 - 1 > 3) || @index0) Test case: MACRO_SHADOWED_VARIABLE_2 Source: ["foo", "bar"].map(x, [x + x, x + x]).map(x, [x + x, x + x]) =====> Result: [[[foofoo, foofoo, foofoo, foofoo], [foofoo, foofoo, foofoo, foofoo]], [[barbar, barbar, barbar, barbar], [barbar, barbar, barbar, barbar]]] -[CASCADED_BINDS]: ["foo", "bar"].map(@c1:0, cel.bind(@r0, @c1:0 + @c1:0, [@r0, @r0])).map(@c0:0, cel.bind(@r1, @c0:0 + @c0:0, [@r1, @r1])) -[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([@c1:0 + @c1:0, @c0:0 + @c0:0], ["foo", "bar"].map(@c1:0, [@index0, @index0]).map(@c0:0, [@index1, @index1])) -[BLOCK_RECURSION_DEPTH_1]: cel.@block([@c1:0 + @c1:0, @c0:0 + @c0:0, ["foo", "bar"], [@index0, @index0], [@index3], @x1:0 + @index4, [@index1, @index1], [@index6], @x0:0 + @index7], @index2.map(@c1:0, @index3).map(@c0:0, @index6)) -[BLOCK_RECURSION_DEPTH_2]: cel.@block([@c1:0 + @c1:0, @c0:0 + @c0:0, [[@index0, @index0]], ["foo", "bar"].map(@c1:0, [@index0, @index0]), [[@index1, @index1]]], @index3.map(@c0:0, [@index1, @index1])) -[BLOCK_RECURSION_DEPTH_3]: cel.@block([@c1:0 + @c1:0, @c0:0 + @c0:0, @x1:0 + [[@index0, @index0]], @x0:0 + [[@index1, @index1]]], ["foo", "bar"].map(@c1:0, [@index0, @index0]).map(@c0:0, [@index1, @index1])) -[BLOCK_RECURSION_DEPTH_4]: cel.@block([@c1:0 + @c1:0, @c0:0 + @c0:0, ["foo", "bar"].map(@c1:0, [@index0, @index0])], @index2.map(@c0:0, [@index1, @index1])) -[BLOCK_RECURSION_DEPTH_5]: cel.@block([@c1:0 + @c1:0, @c0:0 + @c0:0], ["foo", "bar"].map(@c1:0, [@index0, @index0]).map(@c0:0, [@index1, @index1])) -[BLOCK_RECURSION_DEPTH_6]: cel.@block([@c1:0 + @c1:0, @c0:0 + @c0:0], ["foo", "bar"].map(@c1:0, [@index0, @index0]).map(@c0:0, [@index1, @index1])) -[BLOCK_RECURSION_DEPTH_7]: cel.@block([@c1:0 + @c1:0, @c0:0 + @c0:0], ["foo", "bar"].map(@c1:0, [@index0, @index0]).map(@c0:0, [@index1, @index1])) -[BLOCK_RECURSION_DEPTH_8]: cel.@block([@c1:0 + @c1:0, @c0:0 + @c0:0], ["foo", "bar"].map(@c1:0, [@index0, @index0]).map(@c0:0, [@index1, @index1])) -[BLOCK_RECURSION_DEPTH_9]: cel.@block([@c1:0 + @c1:0, @c0:0 + @c0:0], ["foo", "bar"].map(@c1:0, [@index0, @index0]).map(@c0:0, [@index1, @index1])) +[CASCADED_BINDS]: ["foo", "bar"].map(@c:0, cel.bind(@r0, @c:0 + @c:0, [@r0, @r0])).map(@c:1, cel.bind(@r1, @c:1 + @c:1, [@r1, @r1])) +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([@c:0 + @c:0, @c:1 + @c:1], ["foo", "bar"].map(@c:0, [@index0, @index0]).map(@c:1, [@index1, @index1])) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([@c:0 + @c:0, @c:1 + @c:1, ["foo", "bar"], [@index0, @index0], [@index3], @x:0 + @index4, [@index1, @index1], [@index6], @x:1 + @index7], @index2.map(@c:0, @index3).map(@c:1, @index6)) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([@c:0 + @c:0, @c:1 + @c:1, [[@index0, @index0]], ["foo", "bar"].map(@c:0, [@index0, @index0]), [[@index1, @index1]]], @index3.map(@c:1, [@index1, @index1])) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([@c:0 + @c:0, @c:1 + @c:1, @x:0 + [[@index0, @index0]], @x:1 + [[@index1, @index1]]], ["foo", "bar"].map(@c:0, [@index0, @index0]).map(@c:1, [@index1, @index1])) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([@c:0 + @c:0, @c:1 + @c:1, ["foo", "bar"].map(@c:0, [@index0, @index0])], @index2.map(@c:1, [@index1, @index1])) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([@c:0 + @c:0, @c:1 + @c:1], ["foo", "bar"].map(@c:0, [@index0, @index0]).map(@c:1, [@index1, @index1])) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([@c:0 + @c:0, @c:1 + @c:1], ["foo", "bar"].map(@c:0, [@index0, @index0]).map(@c:1, [@index1, @index1])) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([@c:0 + @c:0, @c:1 + @c:1], ["foo", "bar"].map(@c:0, [@index0, @index0]).map(@c:1, [@index1, @index1])) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([@c:0 + @c:0, @c:1 + @c:1], ["foo", "bar"].map(@c:0, [@index0, @index0]).map(@c:1, [@index1, @index1])) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([@c:0 + @c:0, @c:1 + @c:1], ["foo", "bar"].map(@c:0, [@index0, @index0]).map(@c:1, [@index1, @index1])) Test case: PRESENCE_TEST Source: has({'a': true}.a) && {'a':true}['a'] @@ -668,4 +684,4 @@ Result: 31 [BLOCK_RECURSION_DEPTH_6]: cel.@block([pure_custom_func(msg.oneof_type.payload.single_int64), @index0 + pure_custom_func(msg.oneof_type.payload.single_int32) + @index0], @index1 + pure_custom_func(msg.single_int64)) [BLOCK_RECURSION_DEPTH_7]: cel.@block([pure_custom_func(msg.oneof_type.payload.single_int64)], @index0 + pure_custom_func(msg.oneof_type.payload.single_int32) + @index0 + pure_custom_func(msg.single_int64)) [BLOCK_RECURSION_DEPTH_8]: cel.@block([pure_custom_func(msg.oneof_type.payload.single_int64)], @index0 + pure_custom_func(msg.oneof_type.payload.single_int32) + @index0 + pure_custom_func(msg.single_int64)) -[BLOCK_RECURSION_DEPTH_9]: cel.@block([pure_custom_func(msg.oneof_type.payload.single_int64)], @index0 + pure_custom_func(msg.oneof_type.payload.single_int32) + @index0 + pure_custom_func(msg.single_int64)) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([pure_custom_func(msg.oneof_type.payload.single_int64)], @index0 + pure_custom_func(msg.oneof_type.payload.single_int32) + @index0 + pure_custom_func(msg.single_int64)) \ No newline at end of file diff --git a/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java b/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java index a7f2efe8d..7239edda3 100644 --- a/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java +++ b/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java @@ -790,7 +790,7 @@ private IntermediateResult evalStruct(ExecutionFrame frame, CelExpr expr, CelStr .orElseThrow( () -> new IllegalStateException( - "Could not find a reference for CelStruct expresison at ID: " + "Could not find a reference for CelStruct expression at ID: " + expr.id())); // Message creation. From 3ff9beb77a8fa04c4f921b6ea249a77901107310 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Wed, 1 May 2024 18:21:09 -0700 Subject: [PATCH 109/486] Clean up dangling source information from macro expansion PiperOrigin-RevId: 629898444 --- .../main/java/dev/cel/common/CelSource.java | 22 ++- .../dev/cel/common/ast/CelExprFactory.java | 26 +--- .../cel/common/ast/CelExprFactoryTest.java | 12 -- .../src/main/java/dev/cel/parser/Parser.java | 8 + .../parser/CelParserParameterizedTest.java | 15 ++ parser/src/test/resources/parser.baseline | 2 +- .../src/test/resources/source_info.baseline | 143 ++++++++++++++++++ 7 files changed, 192 insertions(+), 36 deletions(-) create mode 100644 parser/src/test/resources/source_info.baseline diff --git a/common/src/main/java/dev/cel/common/CelSource.java b/common/src/main/java/dev/cel/common/CelSource.java index 2422f7b20..595fbffca 100644 --- a/common/src/main/java/dev/cel/common/CelSource.java +++ b/common/src/main/java/dev/cel/common/CelSource.java @@ -49,7 +49,7 @@ public final class CelSource { private CelSource(Builder builder) { this.codePoints = checkNotNull(builder.codePoints); this.description = checkNotNull(builder.description); - this.positions = checkNotNull(builder.positions.buildOrThrow()); + this.positions = checkNotNull(ImmutableMap.copyOf(builder.positions)); this.lineOffsets = checkNotNull(ImmutableList.copyOf(builder.lineOffsets)); this.macroCalls = checkNotNull(ImmutableMap.copyOf(builder.macroCalls)); this.extensions = checkNotNull(builder.extensions.build()); @@ -208,7 +208,7 @@ public static final class Builder { private final CelCodePointArray codePoints; private final List lineOffsets; - private final ImmutableMap.Builder positions; + private final Map positions; private final Map macroCalls; private final ImmutableSet.Builder extensions; @@ -221,7 +221,7 @@ private Builder() { private Builder(CelCodePointArray codePoints, List lineOffsets) { this.codePoints = checkNotNull(codePoints); this.lineOffsets = checkNotNull(lineOffsets); - this.positions = ImmutableMap.builder(); + this.positions = new HashMap<>(); this.macroCalls = new HashMap<>(); this.extensions = ImmutableSet.builder(); this.description = ""; @@ -261,6 +261,18 @@ public Builder addPositions(long exprId, int position) { return this; } + @CanIgnoreReturnValue + public Builder clearPositions() { + this.positions.clear(); + return this; + } + + @CanIgnoreReturnValue + public Builder removePositions(long exprId) { + this.positions.remove(exprId); + return this; + } + @CanIgnoreReturnValue public Builder addMacroCalls(long exprId, CelExpr expr) { this.macroCalls.put(exprId, expr); @@ -329,8 +341,8 @@ public Optional getOffsetLocation(int offset) { } @CheckReturnValue - public ImmutableMap getPositionsMap() { - return this.positions.buildOrThrow(); + public Map getPositionsMap() { + return this.positions; } @CheckReturnValue diff --git a/common/src/main/java/dev/cel/common/ast/CelExprFactory.java b/common/src/main/java/dev/cel/common/ast/CelExprFactory.java index 814efc82b..08edbad6f 100644 --- a/common/src/main/java/dev/cel/common/ast/CelExprFactory.java +++ b/common/src/main/java/dev/cel/common/ast/CelExprFactory.java @@ -25,18 +25,12 @@ /** Factory for generating expression nodes. */ @Internal public class CelExprFactory { - - private final CelExprIdGeneratorFactory.ExprIdGenerator idGenerator; + private long exprId = 0L; public static CelExprFactory newInstance() { return new CelExprFactory(); } - public static CelExprFactory newInstance( - CelExprIdGeneratorFactory.ExprIdGenerator exprIdGenerator) { - return new CelExprFactory(exprIdGenerator); - } - /** Create a new constant expression. */ public final CelExpr newConstant(CelConstant constant) { return CelExpr.newBuilder().setId(nextExprId()).setConstant(constant).build(); @@ -545,19 +539,15 @@ public final CelExpr newSelect(CelExpr operand, String field, boolean testOnly) /** Returns the next unique expression ID. */ protected long nextExprId() { - return idGenerator.generate( - /* exprId= */ -1); // Unconditionally generate next unique ID (i.e: no renumbering). + return ++exprId; } - protected CelExprFactory() { - this(CelExprIdGeneratorFactory.newMonotonicIdGenerator(0)); + /** Attempts to decrement the next expr ID if possible. */ + protected void maybeDeleteId(long id) { + if (id == exprId - 1) { + exprId--; + } } - private CelExprFactory(CelExprIdGeneratorFactory.MonotonicIdGenerator idGenerator) { - this((unused) -> idGenerator.nextExprId()); - } - - private CelExprFactory(CelExprIdGeneratorFactory.ExprIdGenerator exprIdGenerator) { - idGenerator = exprIdGenerator; - } + protected CelExprFactory() {} } diff --git a/common/src/test/java/dev/cel/common/ast/CelExprFactoryTest.java b/common/src/test/java/dev/cel/common/ast/CelExprFactoryTest.java index 30e8f5e41..f3d77ea9e 100644 --- a/common/src/test/java/dev/cel/common/ast/CelExprFactoryTest.java +++ b/common/src/test/java/dev/cel/common/ast/CelExprFactoryTest.java @@ -16,7 +16,6 @@ import static com.google.common.truth.Truth.assertThat; -import dev.cel.common.ast.CelExprIdGeneratorFactory.StableIdGenerator; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -38,15 +37,4 @@ public void nextExprId_startingDefaultIsOne() { assertThat(exprFactory.nextExprId()).isEqualTo(1L); assertThat(exprFactory.nextExprId()).isEqualTo(2L); } - - @Test - public void nextExprId_usingStableIdGenerator() { - StableIdGenerator stableIdGenerator = CelExprIdGeneratorFactory.newStableIdGenerator(0); - CelExprFactory exprFactory = CelExprFactory.newInstance(stableIdGenerator::nextExprId); - - assertThat(exprFactory.nextExprId()).isEqualTo(1L); - assertThat(exprFactory.nextExprId()).isEqualTo(2L); - assertThat(stableIdGenerator.hasId(-1)).isFalse(); - assertThat(stableIdGenerator.hasId(0)).isFalse(); - } } diff --git a/parser/src/main/java/dev/cel/parser/Parser.java b/parser/src/main/java/dev/cel/parser/Parser.java index b98a748d5..d61cf3c45 100644 --- a/parser/src/main/java/dev/cel/parser/Parser.java +++ b/parser/src/main/java/dev/cel/parser/Parser.java @@ -660,6 +660,7 @@ private Optional visitMacro( CelExpr.newBuilder().setCall(callExpr.build()).build()); } + exprFactory.maybeDeleteId(expr.id()); return expandedMacro; } @@ -895,6 +896,7 @@ private CelExpr macroOrCall( ImmutableList arguments = visitExprListContext(args); Optional errorArg = arguments.stream().filter(ERROR::equals).findAny(); if (errorArg.isPresent()) { + sourceInfo.clearPositions(); // Any arguments passed in to the macro may fail parsing. // Stop the macro expansion in this case as the result of the macro will be a parse failure. return ERROR; @@ -1109,6 +1111,12 @@ private long nextExprId(int position) { return exprId; } + @Override + protected void maybeDeleteId(long id) { + sourceInfo.removePositions(id); + super.maybeDeleteId(id); + } + @Override public long copyExprId(long id) { return nextExprId(getPosition(id)); diff --git a/parser/src/test/java/dev/cel/parser/CelParserParameterizedTest.java b/parser/src/test/java/dev/cel/parser/CelParserParameterizedTest.java index 599a5478c..a013c4ea3 100644 --- a/parser/src/test/java/dev/cel/parser/CelParserParameterizedTest.java +++ b/parser/src/test/java/dev/cel/parser/CelParserParameterizedTest.java @@ -32,6 +32,7 @@ import com.google.protobuf.Descriptors.FieldDescriptor; import com.google.protobuf.Descriptors.OneofDescriptor; import com.google.testing.junit.testparameterinjector.TestParameterInjector; +import dev.cel.common.CelAbstractSyntaxTree; import dev.cel.common.CelOptions; import dev.cel.common.CelProtoAbstractSyntaxTree; import dev.cel.common.CelSource; @@ -248,6 +249,11 @@ public void parser_errors() { runTest(parserWithoutOptionalSupport, "[?a, ?b]"); } + @Test + public void source_info() throws Exception { + runSourceInfoTest("[{}, {'field': true}].exists(i, has(i.field))"); + } + private void runTest(CelParser parser, String expression) { runTest(parser, expression, true); } @@ -287,6 +293,15 @@ private void runTest(CelParser parser, String expression, boolean validateParseO testOutput().println(); } + private void runSourceInfoTest(String expression) throws Exception { + CelAbstractSyntaxTree ast = PARSER.parse(expression).getAst(); + SourceInfo sourceInfo = + CelProtoAbstractSyntaxTree.fromCelAst(ast).toParsedExpr().getSourceInfo(); + testOutput().println("I: " + expression); + testOutput().println("=====>"); + testOutput().println("S: " + sourceInfo); + } + private String convertMacroCallsToString(SourceInfo sourceInfo) { KindAndIdAdorner macroCallsAdorner = new KindAndIdAdorner(sourceInfo); // Sort in ascending order so that nested macro calls are always in the same order for tests diff --git a/parser/src/test/resources/parser.baseline b/parser/src/test/resources/parser.baseline index 79dd0ae65..1b75ece60 100644 --- a/parser/src/test/resources/parser.baseline +++ b/parser/src/test/resources/parser.baseline @@ -1543,7 +1543,7 @@ L: noop_macro( I: get_constant_macro() =====> P: 10^#1:int64# -L: 10^#1[1,18]# +L: 10^#1[NO_POS]# M: get_constant_macro()^#0:Expr.Call# I: a.?b[?0] && a[?c] diff --git a/parser/src/test/resources/source_info.baseline b/parser/src/test/resources/source_info.baseline new file mode 100644 index 000000000..153a49822 --- /dev/null +++ b/parser/src/test/resources/source_info.baseline @@ -0,0 +1,143 @@ +I: [{}, {'field': true}].exists(i, has(i.field)) +=====> +S: location: "" +line_offsets: 46 +positions { + key: 1 + value: 0 +} +positions { + key: 2 + value: 1 +} +positions { + key: 3 + value: 5 +} +positions { + key: 4 + value: 13 +} +positions { + key: 5 + value: 6 +} +positions { + key: 6 + value: 15 +} +positions { + key: 8 + value: 29 +} +positions { + key: 10 + value: 36 +} +positions { + key: 11 + value: 37 +} +positions { + key: 12 + value: 35 +} +positions { + key: 13 + value: 28 +} +positions { + key: 14 + value: 28 +} +positions { + key: 15 + value: 28 +} +positions { + key: 16 + value: 28 +} +positions { + key: 17 + value: 28 +} +positions { + key: 18 + value: 28 +} +positions { + key: 19 + value: 28 +} +positions { + key: 20 + value: 28 +} +macro_calls { + key: 12 + value { + call_expr { + function: "has" + args { + id: 11 + select_expr { + operand { + id: 10 + ident_expr { + name: "i" + } + } + field: "field" + } + } + } + } +} +macro_calls { + key: 20 + value { + call_expr { + target { + id: 1 + list_expr { + elements { + id: 2 + struct_expr { + } + } + elements { + id: 3 + struct_expr { + entries { + id: 4 + map_key { + id: 5 + const_expr { + string_value: "field" + } + } + value { + id: 6 + const_expr { + bool_value: true + } + } + } + } + } + } + } + function: "exists" + args { + id: 8 + ident_expr { + name: "i" + } + } + args { + id: 12 + } + } + } +} From d513f33403f9a9ea4245b496a6cc652aaf0248ef Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Wed, 1 May 2024 19:00:08 -0700 Subject: [PATCH 110/486] Do not re-use ID twice in exists_one macro PiperOrigin-RevId: 629906268 --- .../java/dev/cel/parser/CelStandardMacro.java | 12 ++++++----- parser/src/test/resources/parser.baseline | 20 +++++++++---------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/parser/src/main/java/dev/cel/parser/CelStandardMacro.java b/parser/src/main/java/dev/cel/parser/CelStandardMacro.java index 3d93e8531..3ea54f9e4 100644 --- a/parser/src/main/java/dev/cel/parser/CelStandardMacro.java +++ b/parser/src/main/java/dev/cel/parser/CelStandardMacro.java @@ -170,20 +170,22 @@ private static Optional expandExistsOneMacro( return Optional.of(reportArgumentError(exprFactory, arg0)); } CelExpr arg1 = checkNotNull(arguments.get(1)); - CelExpr zeroExpr = exprFactory.newIntLiteral(0); - CelExpr oneExpr = exprFactory.newIntLiteral(1); - CelExpr accuInit = zeroExpr; + CelExpr accuInit = exprFactory.newIntLiteral(0); CelExpr condition = exprFactory.newBoolLiteral(true); CelExpr step = exprFactory.newGlobalCall( Operator.CONDITIONAL.getFunction(), arg1, exprFactory.newGlobalCall( - Operator.ADD.getFunction(), exprFactory.newIdentifier(ACCUMULATOR_VAR), oneExpr), + Operator.ADD.getFunction(), + exprFactory.newIdentifier(ACCUMULATOR_VAR), + exprFactory.newIntLiteral(1)), exprFactory.newIdentifier(ACCUMULATOR_VAR)); CelExpr result = exprFactory.newGlobalCall( - Operator.EQUALS.getFunction(), exprFactory.newIdentifier(ACCUMULATOR_VAR), oneExpr); + Operator.EQUALS.getFunction(), + exprFactory.newIdentifier(ACCUMULATOR_VAR), + exprFactory.newIntLiteral(1)); return Optional.of( exprFactory.fold( arg0.ident().name(), target, ACCUMULATOR_VAR, accuInit, condition, step, result)); diff --git a/parser/src/test/resources/parser.baseline b/parser/src/test/resources/parser.baseline index 1b75ece60..455cf24dd 100644 --- a/parser/src/test/resources/parser.baseline +++ b/parser/src/test/resources/parser.baseline @@ -739,21 +739,21 @@ P: __comprehension__( // Init 0^#5:int64#, // LoopCondition - true^#7:bool#, + true^#6:bool#, // LoopStep _?_:_( f^#4:Expr.Ident#, _+_( - __result__^#8:Expr.Ident#, - 1^#6:int64# + __result__^#7:Expr.Ident#, + 1^#8:int64# )^#9:Expr.Call#, __result__^#10:Expr.Ident# )^#11:Expr.Call#, // Result _==_( __result__^#12:Expr.Ident#, - 1^#6:int64# - )^#13:Expr.Call#)^#14:Expr.Comprehension# + 1^#13:int64# + )^#14:Expr.Call#)^#15:Expr.Comprehension# L: __comprehension__( // Variable v, @@ -764,21 +764,21 @@ L: __comprehension__( // Init 0^#5[1,12]#, // LoopCondition - true^#7[1,12]#, + true^#6[1,12]#, // LoopStep _?_:_( f^#4[1,16]#, _+_( - __result__^#8[1,12]#, - 1^#6[1,12]# + __result__^#7[1,12]#, + 1^#8[1,12]# )^#9[1,12]#, __result__^#10[1,12]# )^#11[1,12]#, // Result _==_( __result__^#12[1,12]#, - 1^#6[1,12]# - )^#13[1,12]#)^#14[1,12]# + 1^#13[1,12]# + )^#14[1,12]#)^#15[1,12]# M: m^#1:Expr.Ident#.exists_one( v^#3:Expr.Ident#, f^#4:Expr.Ident# From 1b4eeee7dde55d55eb2a7a55e8839bee6abca61b Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Wed, 1 May 2024 19:40:53 -0700 Subject: [PATCH 111/486] Release 0.5.0 PiperOrigin-RevId: 629913123 --- README.md | 4 ++-- publish/cel_version.bzl | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 83b42cb51..8d40e9e85 100644 --- a/README.md +++ b/README.md @@ -55,14 +55,14 @@ CEL-Java is available in Maven Central Repository. [Download the JARs here][8] o dev.cel cel - 0.4.1 + 0.5.0 ``` **Gradle** ```gradle -implementation 'dev.cel:cel:0.4.1' +implementation 'dev.cel:cel:0.5.0' ``` Then run this example: diff --git a/publish/cel_version.bzl b/publish/cel_version.bzl index 23c4f0e6c..271103327 100644 --- a/publish/cel_version.bzl +++ b/publish/cel_version.bzl @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. """Maven artifact version for CEL.""" -CEL_VERSION = "0.4.1" +CEL_VERSION = "0.5.0" From 1ea0a28999383726313f2aba18eff7273eeae44f Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Thu, 2 May 2024 11:15:19 -0700 Subject: [PATCH 112/486] Add code for Exercise 5 Codelabs PiperOrigin-RevId: 630122276 --- codelab/README.md | 9 +- codelab/src/main/codelab/BUILD.bazel | 3 + codelab/src/main/codelab/Exercise5.java | 73 ++++++++++ .../src/main/codelab/solutions/BUILD.bazel | 3 + .../src/main/codelab/solutions/Exercise5.java | 80 +++++++++++ codelab/src/test/codelab/BUILD.bazel | 16 +++ codelab/src/test/codelab/Exercise5Test.java | 64 +++++++++ .../src/test/codelab/solutions/BUILD.bazel | 15 ++ .../test/codelab/solutions/Exercise5Test.java | 64 +++++++++ common/BUILD.bazel | 5 + .../src/main/java/dev/cel/common/BUILD.bazel | 13 ++ .../dev/cel/common/CelProtoJsonAdapter.java | 136 ++++++++++++++++++ .../java/dev/cel/common/internal/BUILD.bazel | 2 +- .../dev/cel/common/internal/ProtoAdapter.java | 120 +++------------- .../src/test/java/dev/cel/common/BUILD.bazel | 2 + .../cel/common/CelProtoJsonAdapterTest.java | 80 +++++++++++ 16 files changed, 580 insertions(+), 105 deletions(-) create mode 100644 codelab/src/main/codelab/Exercise5.java create mode 100644 codelab/src/main/codelab/solutions/Exercise5.java create mode 100644 codelab/src/test/codelab/Exercise5Test.java create mode 100644 codelab/src/test/codelab/solutions/Exercise5Test.java create mode 100644 common/src/main/java/dev/cel/common/CelProtoJsonAdapter.java create mode 100644 common/src/test/java/dev/cel/common/CelProtoJsonAdapterTest.java diff --git a/codelab/README.md b/codelab/README.md index 29065f0b1..7142a97b4 100644 --- a/codelab/README.md +++ b/codelab/README.md @@ -298,7 +298,8 @@ CelAbstractSyntaxTree compile(String expression, String variableName, CelType va The compiler's `addVar` method allows us to declare variables. Note that you must supply the type of the variable being declared. Supported CEL types can be found [here](https://github.com/google/cel-java/tree/main/common/src/main/java/dev/cel/common/types). -Best practice: You may have noticed addVar has an overloaded method which accepts a proto based Type instead of the CEL-Java native CelType used in this example. While the two types are functionally equivalent, we recommend using the native types whenever possible. +> [!TIP] +> Best practice: You may have noticed addVar has an overloaded method which accepts a proto based Type instead of the CEL-Java native CelType used in this example. While the two types are functionally equivalent, we recommend using the native types whenever possible. Let's make the evaluation work now. Copy into the eval method: @@ -628,7 +629,9 @@ private static boolean mapContainsKeyValue(Object[] args) { } ``` -Best practice: Use `Unary` or `Binary` helper interfaces to improve compile-time correctness for any overload implementations with 2 arguments or fewer. +> [!TIP] +> Best practice: Use `Unary` or `Binary` helper interfaces to improve compile-time correctness for any overload implementations with 2 arguments or fewer. -Best practice: Declare overload ids according to their types and function names. e.g. targetType_func_argType_argType. In the case where argType is a type param, use a descriptive name instead of the simple type name. +> [!TIP] +> Best practice: Declare overload ids according to their types and function names. e.g. targetType_func_argType_argType. In the case where argType is a type param, use a descriptive name instead of the simple type name. diff --git a/codelab/src/main/codelab/BUILD.bazel b/codelab/src/main/codelab/BUILD.bazel index b5c135639..badfc74f2 100644 --- a/codelab/src/main/codelab/BUILD.bazel +++ b/codelab/src/main/codelab/BUILD.bazel @@ -9,15 +9,18 @@ java_library( name = "codelab", srcs = glob(["*.java"]), deps = [ + "@maven//:com_google_protobuf_protobuf_java", # unuseddeps: keep "@maven//:com_google_api_grpc_proto_google_common_protos", # unuseddeps: keep "@maven//:com_google_guava_guava", # unuseddeps: keep "//common", # unuseddeps: keep "//common:compiler_common", # unuseddeps: keep + "//common:proto_json_adapter", # unuseddeps: keep "//common/types", # unuseddeps: keep "//common/types:type_providers", # unuseddeps: keep "//compiler", # unuseddeps: keep "//compiler:compiler_builder", # unuseddeps: keep "//runtime", # unuseddeps: keep + "@maven//:com_google_protobuf_protobuf_java_util", # unuseddeps: keep # ], ) diff --git a/codelab/src/main/codelab/Exercise5.java b/codelab/src/main/codelab/Exercise5.java new file mode 100644 index 000000000..eca2a5df7 --- /dev/null +++ b/codelab/src/main/codelab/Exercise5.java @@ -0,0 +1,73 @@ +// Copyright 2024 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 codelab; + +import dev.cel.common.CelAbstractSyntaxTree; +import dev.cel.common.CelValidationException; +import dev.cel.compiler.CelCompiler; +import dev.cel.compiler.CelCompilerFactory; +import dev.cel.runtime.CelEvaluationException; +import dev.cel.runtime.CelRuntime; +import dev.cel.runtime.CelRuntimeFactory; +import java.util.Map; + +/** + * Exercise5 covers how to build complex objects as CEL literals. + * + *

Given the input variable "time", construct a JWT with an expiry of 5 minutes + */ +final class Exercise5 { + + /** + * Compiles the input expression. + * + * @throws IllegalArgumentException If the expression is malformed due to syntactic or semantic + * errors. + */ + CelAbstractSyntaxTree compile(String expression) { + CelCompiler celCompiler = + CelCompilerFactory.standardCelCompilerBuilder() + // Declare the 'time' variable here as a Timestamp. + .build(); + + try { + return celCompiler.compile(expression).getAst(); + } catch (CelValidationException e) { + throw new IllegalArgumentException("Failed to compile expression.", e); + } + } + + /** + * Evaluates the compiled AST with the user provided parameter values. + * + * @throws IllegalArgumentException If the compiled expression in AST fails to evaluate. + */ + Object eval(CelAbstractSyntaxTree ast, Map parameterValues) { + CelRuntime celRuntime = CelRuntimeFactory.standardCelRuntimeBuilder().build(); + + try { + CelRuntime.Program program = celRuntime.createProgram(ast); + return program.eval(parameterValues); + } catch (CelEvaluationException e) { + throw new IllegalArgumentException("Evaluation error has occurred.", e); + } + } + + /** Converts the evaluated result into a JSON string using protobuf's google.protobuf.Struct. */ + @SuppressWarnings("DoNotCallSuggester") + String toJson(Map map) { + throw new UnsupportedOperationException("To be implemented"); + } +} diff --git a/codelab/src/main/codelab/solutions/BUILD.bazel b/codelab/src/main/codelab/solutions/BUILD.bazel index c6bc0a0fe..3e4be9874 100644 --- a/codelab/src/main/codelab/solutions/BUILD.bazel +++ b/codelab/src/main/codelab/solutions/BUILD.bazel @@ -11,6 +11,7 @@ java_library( deps = [ "//common", "//common:compiler_common", + "//common:proto_json_adapter", "//common/types", "//common/types:type_providers", "//compiler", @@ -18,5 +19,7 @@ java_library( "//runtime", "@maven//:com_google_api_grpc_proto_google_common_protos", "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", + "@maven//:com_google_protobuf_protobuf_java_util", ], ) diff --git a/codelab/src/main/codelab/solutions/Exercise5.java b/codelab/src/main/codelab/solutions/Exercise5.java new file mode 100644 index 000000000..e948adfed --- /dev/null +++ b/codelab/src/main/codelab/solutions/Exercise5.java @@ -0,0 +1,80 @@ +// Copyright 2024 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 codelab.solutions; + +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.Struct; +import com.google.protobuf.util.JsonFormat; +import dev.cel.common.CelAbstractSyntaxTree; +import dev.cel.common.CelProtoJsonAdapter; +import dev.cel.common.CelValidationException; +import dev.cel.common.types.SimpleType; +import dev.cel.compiler.CelCompiler; +import dev.cel.compiler.CelCompilerFactory; +import dev.cel.runtime.CelEvaluationException; +import dev.cel.runtime.CelRuntime; +import dev.cel.runtime.CelRuntimeFactory; +import java.util.Map; + +/** + * Exercise5 covers how to build complex objects as CEL literals. + * + *

Given the input variable "time", construct a JWT with an expiry of 5 minutes + */ +final class Exercise5 { + + /** + * Compiles the input expression. + * + * @throws IllegalArgumentException If the expression is malformed due to syntactic or semantic + * errors. + */ + CelAbstractSyntaxTree compile(String expression) { + CelCompiler celCompiler = + CelCompilerFactory.standardCelCompilerBuilder() + .addVar("time", SimpleType.TIMESTAMP) + .build(); + + try { + return celCompiler.compile(expression).getAst(); + } catch (CelValidationException e) { + throw new IllegalArgumentException("Failed to compile expression.", e); + } + } + + /** + * Evaluates the compiled AST with the user provided parameter values. + * + * @throws IllegalArgumentException If the compiled expression in AST fails to evaluate. + */ + Object eval(CelAbstractSyntaxTree ast, Map parameterValues) { + CelRuntime celRuntime = CelRuntimeFactory.standardCelRuntimeBuilder().build(); + + try { + CelRuntime.Program program = celRuntime.createProgram(ast); + return program.eval(parameterValues); + } catch (CelEvaluationException e) { + throw new IllegalArgumentException("Evaluation error has occurred.", e); + } + } + + /** Converts the evaluated result into a JSON string using protobuf's google.protobuf.Struct. */ + String toJson(Map map) throws InvalidProtocolBufferException { + // Convert the map into google.protobuf.Struct using the CEL provided helper function + Struct jsonStruct = CelProtoJsonAdapter.adaptToJsonStructValue(map); + // Then use Protobuf's JsonFormat to produce a JSON string output. + return JsonFormat.printer().omittingInsignificantWhitespace().print(jsonStruct); + } +} diff --git a/codelab/src/test/codelab/BUILD.bazel b/codelab/src/test/codelab/BUILD.bazel index 40025f21d..784da09ab 100644 --- a/codelab/src/test/codelab/BUILD.bazel +++ b/codelab/src/test/codelab/BUILD.bazel @@ -66,6 +66,22 @@ java_test( ], ) +java_test( + name = "Exercise5Test", + srcs = ["Exercise5Test.java"], + tags = ["notap"], + test_class = "codelab.Exercise5Test", + deps = [ + "//:java_truth", + "//codelab", + "//common", + "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java_util", + "@maven//:com_google_testparameterinjector_test_parameter_injector", + "@maven//:junit_junit", + ], +) + test_suite( name = "exercise_test_suite", tags = ["notap"], diff --git a/codelab/src/test/codelab/Exercise5Test.java b/codelab/src/test/codelab/Exercise5Test.java new file mode 100644 index 000000000..7035ff742 --- /dev/null +++ b/codelab/src/test/codelab/Exercise5Test.java @@ -0,0 +1,64 @@ +// Copyright 2024 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 codelab; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.common.collect.ImmutableMap; +import com.google.protobuf.util.Timestamps; +import com.google.testing.junit.testparameterinjector.TestParameterInjector; +import dev.cel.common.CelAbstractSyntaxTree; +import java.util.Map; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(TestParameterInjector.class) +public final class Exercise5Test { + private final Exercise5 exercise5 = new Exercise5(); + + @Test + public void evaluate_jwtWithTimeVariable_producesJsonString() throws Exception { + // Note the quoted keys in the CEL map literal. For proto messages the field names are unquoted + // as they represent well-defined identifiers. + String jwt = + "{'sub': 'serviceAccount:delegate@acme.co'," + + "'aud': 'my-project'," + + "'iss': 'auth.acme.com:12350'," + + "'iat': time," + + "'nbf': time," + + "'exp': time + duration('300s')," + + "'extra_claims': {" + + "'group': 'admin'" + + "}}"; + CelAbstractSyntaxTree ast = exercise5.compile(jwt); + + // The output of the program is a map type. + @SuppressWarnings("unchecked") + Map evaluatedResult = + (Map) + exercise5.eval(ast, ImmutableMap.of("time", Timestamps.fromSeconds(1698361778))); + String jsonOutput = exercise5.toJson(evaluatedResult); + + assertThat(jsonOutput) + .isEqualTo( + "{\"sub\":\"serviceAccount:delegate@acme.co\"," + + "\"aud\":\"my-project\"," + + "\"iss\":\"auth.acme.com:12350\"," + + "\"iat\":\"2023-10-26T23:09:38Z\"," + + "\"nbf\":\"2023-10-26T23:09:38Z\"," + + "\"exp\":\"2023-10-26T23:14:38Z\"," + + "\"extra_claims\":{\"group\":\"admin\"}}"); + } +} diff --git a/codelab/src/test/codelab/solutions/BUILD.bazel b/codelab/src/test/codelab/solutions/BUILD.bazel index c368a8353..92b66a917 100644 --- a/codelab/src/test/codelab/solutions/BUILD.bazel +++ b/codelab/src/test/codelab/solutions/BUILD.bazel @@ -61,3 +61,18 @@ java_test( "@maven//:junit_junit", ], ) + +java_test( + name = "Exercise5Test", + srcs = ["Exercise5Test.java"], + test_class = "codelab.solutions.Exercise5Test", + deps = [ + "//:java_truth", + "//codelab:solutions", + "//common", + "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java_util", + "@maven//:com_google_testparameterinjector_test_parameter_injector", + "@maven//:junit_junit", + ], +) diff --git a/codelab/src/test/codelab/solutions/Exercise5Test.java b/codelab/src/test/codelab/solutions/Exercise5Test.java new file mode 100644 index 000000000..e7a105a94 --- /dev/null +++ b/codelab/src/test/codelab/solutions/Exercise5Test.java @@ -0,0 +1,64 @@ +// Copyright 2024 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 codelab.solutions; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.common.collect.ImmutableMap; +import com.google.protobuf.util.Timestamps; +import com.google.testing.junit.testparameterinjector.TestParameterInjector; +import dev.cel.common.CelAbstractSyntaxTree; +import java.util.Map; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(TestParameterInjector.class) +public final class Exercise5Test { + private final Exercise5 exercise5 = new Exercise5(); + + @Test + public void evaluate_jwtWithTimeVariable_producesJsonString() throws Exception { + // Note the quoted keys in the CEL map literal. For proto messages the field names are unquoted + // as they represent well-defined identifiers. + String jwt = + "{'sub': 'serviceAccount:delegate@acme.co'," + + "'aud': 'my-project'," + + "'iss': 'auth.acme.com:12350'," + + "'iat': time," + + "'nbf': time," + + "'exp': time + duration('300s')," + + "'extra_claims': {" + + "'group': 'admin'" + + "}}"; + CelAbstractSyntaxTree ast = exercise5.compile(jwt); + + // The output of the program is a map type. + @SuppressWarnings("unchecked") + Map evaluatedResult = + (Map) + exercise5.eval(ast, ImmutableMap.of("time", Timestamps.fromSeconds(1698361778))); + String jsonOutput = exercise5.toJson(evaluatedResult); + + assertThat(jsonOutput) + .isEqualTo( + "{\"sub\":\"serviceAccount:delegate@acme.co\"," + + "\"aud\":\"my-project\"," + + "\"iss\":\"auth.acme.com:12350\"," + + "\"iat\":\"2023-10-26T23:09:38Z\"," + + "\"nbf\":\"2023-10-26T23:09:38Z\"," + + "\"exp\":\"2023-10-26T23:14:38Z\"," + + "\"extra_claims\":{\"group\":\"admin\"}}"); + } +} diff --git a/common/BUILD.bazel b/common/BUILD.bazel index 7ad38b830..649c49186 100644 --- a/common/BUILD.bazel +++ b/common/BUILD.bazel @@ -54,3 +54,8 @@ java_library( visibility = ["//visibility:public"], exports = ["//common/src/main/java/dev/cel/common:runtime_exception"], ) + +java_library( + name = "proto_json_adapter", + exports = ["//common/src/main/java/dev/cel/common:proto_json_adapter"], +) diff --git a/common/src/main/java/dev/cel/common/BUILD.bazel b/common/src/main/java/dev/cel/common/BUILD.bazel index de5995c9b..633279a0b 100644 --- a/common/src/main/java/dev/cel/common/BUILD.bazel +++ b/common/src/main/java/dev/cel/common/BUILD.bazel @@ -162,3 +162,16 @@ java_library( "@maven//:com_google_guava_guava", ], ) + +java_library( + name = "proto_json_adapter", + srcs = ["CelProtoJsonAdapter.java"], + tags = [ + ], + deps = [ + "@maven//:com_google_errorprone_error_prone_annotations", + "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", + "@maven//:com_google_protobuf_protobuf_java_util", + ], +) diff --git a/common/src/main/java/dev/cel/common/CelProtoJsonAdapter.java b/common/src/main/java/dev/cel/common/CelProtoJsonAdapter.java new file mode 100644 index 000000000..74c52f397 --- /dev/null +++ b/common/src/main/java/dev/cel/common/CelProtoJsonAdapter.java @@ -0,0 +1,136 @@ +// Copyright 2024 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.common; + +import com.google.common.primitives.UnsignedLong; +import com.google.errorprone.annotations.Immutable; +import com.google.protobuf.ByteString; +import com.google.protobuf.Duration; +import com.google.protobuf.ListValue; +import com.google.protobuf.NullValue; +import com.google.protobuf.Struct; +import com.google.protobuf.Timestamp; +import com.google.protobuf.Value; +import com.google.protobuf.util.Durations; +import com.google.protobuf.util.Timestamps; +import java.util.Base64; +import java.util.Map; + +/** + * {@code CelProtoJsonAdapter} is a utility to handle conversion from Java native objects + * representing CEL values to Protobuf's structured value which maps to JSON object schema. + */ +@Immutable +public final class CelProtoJsonAdapter { + private static final long JSON_MAX_INT_VALUE = (1L << 53) - 1; + private static final long JSON_MIN_INT_VALUE = -JSON_MAX_INT_VALUE; + private static final UnsignedLong JSON_MAX_UINT_VALUE = + UnsignedLong.fromLongBits(JSON_MAX_INT_VALUE); + + /** + * Adapts a map to a JSON Struct. + * + * @throws ClassCastException If the key is not a string literal + * @throws IllegalArgumentException If any of the map's value is not convertible to a canonical + * JSON representation defined by protobuf. + */ + public static Struct adaptToJsonStructValue(Map map) { + Struct.Builder struct = Struct.newBuilder(); + for (Map.Entry entry : map.entrySet()) { + String key = entry.getKey(); + Object keyValue = entry.getValue(); + + struct.putFields(key, adaptValueToJsonValue(keyValue)); + } + return struct.build(); + } + + /** + * Adapts a native Java object to a JSON value. + * + * @throws IllegalArgumentException If the value is not convertible to a canonical JSON * + * representation defined by protobuf. + */ + @SuppressWarnings("unchecked") + public static Value adaptValueToJsonValue(Object value) { + Value.Builder json = Value.newBuilder(); + if (value == null || value instanceof NullValue) { + return json.setNullValue(NullValue.NULL_VALUE).build(); + } + if (value instanceof Boolean) { + return json.setBoolValue((Boolean) value).build(); + } + if (value instanceof Integer || value instanceof Long) { + long longValue = ((Number) value).longValue(); + if (longValue < JSON_MIN_INT_VALUE || longValue > JSON_MAX_INT_VALUE) { + return json.setStringValue(Long.toString(longValue)).build(); + } + return json.setNumberValue((double) longValue).build(); + } + if (value instanceof UnsignedLong) { + if (((UnsignedLong) value).compareTo(JSON_MAX_UINT_VALUE) > 0) { + return json.setStringValue(((UnsignedLong) value).toString()).build(); + } + return json.setNumberValue((double) ((UnsignedLong) value).longValue()).build(); + } + if (value instanceof Float || value instanceof Double) { + return json.setNumberValue(((Number) value).doubleValue()).build(); + } + if (value instanceof ByteString) { + return json.setStringValue( + Base64.getEncoder().encodeToString(((ByteString) value).toByteArray())) + .build(); + } + if (value instanceof String) { + return json.setStringValue((String) value).build(); + } + if (value instanceof Map) { + Struct struct = adaptToJsonStructValue((Map) value); + return json.setStructValue(struct).build(); + } + if (value instanceof Iterable) { + ListValue listValue = adaptToJsonListValue((Iterable) value); + return json.setListValue(listValue).build(); + } + if (value instanceof Timestamp) { + // CEL follows the proto3 to JSON conversion which formats as an RFC 3339 encoded JSON string. + String ts = Timestamps.toString((Timestamp) value); + return json.setStringValue(ts).build(); + } + if (value instanceof Duration) { + String duration = Durations.toString((Duration) value); + return json.setStringValue(duration).build(); + } + + throw new IllegalArgumentException( + String.format("Value %s cannot be adapted to a JSON Value.", value)); + } + + /** + * Adapts an iterable to a JSON list value. + * + * @throws IllegalArgumentException If any of the map's value is not convertible to a canonical + * JSON representation defined by protobuf. + */ + public static ListValue adaptToJsonListValue(Iterable value) { + ListValue.Builder jsonList = ListValue.newBuilder(); + for (Object elem : value) { + jsonList.addValues(adaptValueToJsonValue(elem)); + } + return jsonList.build(); + } + + private CelProtoJsonAdapter() {} +} diff --git a/common/src/main/java/dev/cel/common/internal/BUILD.bazel b/common/src/main/java/dev/cel/common/internal/BUILD.bazel index b76338cef..0ea165ae1 100644 --- a/common/src/main/java/dev/cel/common/internal/BUILD.bazel +++ b/common/src/main/java/dev/cel/common/internal/BUILD.bazel @@ -121,6 +121,7 @@ java_library( ":well_known_proto", "//:auto_value", "//common:error_codes", + "//common:proto_json_adapter", "//common:runtime_exception", "//common/annotations", "@cel_spec//proto/cel/expr:expr_java_proto", @@ -128,7 +129,6 @@ java_library( "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", - "@maven//:com_google_protobuf_protobuf_java_util", "@maven//:org_jspecify_jspecify", ], ) diff --git a/common/src/main/java/dev/cel/common/internal/ProtoAdapter.java b/common/src/main/java/dev/cel/common/internal/ProtoAdapter.java index 194e8260d..e4b12f841 100644 --- a/common/src/main/java/dev/cel/common/internal/ProtoAdapter.java +++ b/common/src/main/java/dev/cel/common/internal/ProtoAdapter.java @@ -50,13 +50,11 @@ import com.google.protobuf.UInt32Value; import com.google.protobuf.UInt64Value; import com.google.protobuf.Value; -import com.google.protobuf.util.Durations; -import com.google.protobuf.util.Timestamps; import dev.cel.common.CelErrorCode; +import dev.cel.common.CelProtoJsonAdapter; import dev.cel.common.CelRuntimeException; import dev.cel.common.annotations.Internal; import java.util.ArrayList; -import java.util.Base64; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -324,6 +322,7 @@ private BidiConverter fieldToValueConverter(FieldDescriptor fieldDescriptor) { * protoTypeName} will indicate an alternative packaging of the value which needs to be * considered, such as a packing an {@code google.protobuf.StringValue} into a {@code Any} value. */ + @SuppressWarnings("unchecked") public Optional adaptValueToProto(Object value, String protoTypeName) { WellKnownProto wellKnownProto = WellKnownProto.getByDescriptorName(protoTypeName); if (wellKnownProto == null) { @@ -336,11 +335,24 @@ public Optional adaptValueToProto(Object value, String protoTypeName) { case ANY_VALUE: return Optional.ofNullable(adaptValueToAny(value)); case JSON_VALUE: - return Optional.ofNullable(adaptValueToJsonValue(value)); + try { + return Optional.of(CelProtoJsonAdapter.adaptValueToJsonValue(value)); + } catch (RuntimeException e) { + return Optional.empty(); + } case JSON_LIST_VALUE: - return Optional.ofNullable(adaptValueToJsonListValue(value)); + try { + return Optional.of(CelProtoJsonAdapter.adaptToJsonListValue((Iterable) value)); + } catch (RuntimeException e) { + return Optional.empty(); + } case JSON_STRUCT_VALUE: - return Optional.ofNullable(adaptValueToJsonStructValue(value)); + try { + return Optional.of( + CelProtoJsonAdapter.adaptToJsonStructValue((Map) value)); + } catch (RuntimeException e) { + return Optional.empty(); + } case BOOL_VALUE: if (value instanceof Boolean) { return Optional.of(BoolValue.of((Boolean) value)); @@ -422,101 +434,7 @@ public Optional adaptValueToProto(Object value, String protoTypeName) { private @Nullable Any maybePackAny(Object value, WellKnownProto wellKnownProto) { Optional protoValue = adaptValueToProto(value, wellKnownProto.typeName()); - if (protoValue.isPresent()) { - return Any.pack(protoValue.get()); - } - return null; - } - - private static final long JSON_MAX_INT_VALUE = (1L << 53) - 1; - private static final long JSON_MIN_INT_VALUE = -JSON_MAX_INT_VALUE; - private static final UnsignedLong JSON_MAX_UINT_VALUE = - UnsignedLong.fromLongBits(JSON_MAX_INT_VALUE); - - private @Nullable Value adaptValueToJsonValue(Object value) { - Value.Builder json = Value.newBuilder(); - if (value == null || value instanceof NullValue) { - return json.setNullValue(NullValue.NULL_VALUE).build(); - } - if (value instanceof Boolean) { - return json.setBoolValue((Boolean) value).build(); - } - if (value instanceof Integer || value instanceof Long) { - long longValue = ((Number) value).longValue(); - if (longValue < JSON_MIN_INT_VALUE || longValue > JSON_MAX_INT_VALUE) { - return json.setStringValue(Long.toString(longValue)).build(); - } - return json.setNumberValue((double) longValue).build(); - } - if (value instanceof UnsignedLong) { - if (((UnsignedLong) value).compareTo(JSON_MAX_UINT_VALUE) > 0) { - return json.setStringValue(((UnsignedLong) value).toString()).build(); - } - return json.setNumberValue((double) ((UnsignedLong) value).longValue()).build(); - } - if (value instanceof Float || value instanceof Double) { - return json.setNumberValue(((Number) value).doubleValue()).build(); - } - if (value instanceof ByteString) { - return json.setStringValue( - Base64.getEncoder().encodeToString(((ByteString) value).toByteArray())) - .build(); - } - if (value instanceof String) { - return json.setStringValue((String) value).build(); - } - if (value instanceof Map) { - Struct struct = adaptValueToJsonStructValue(value); - if (struct != null) { - return json.setStructValue(struct).build(); - } - } - if (value instanceof Iterable) { - ListValue listValue = adaptValueToJsonListValue(value); - if (listValue != null) { - return json.setListValue(listValue).build(); - } - } - if (value instanceof Timestamp) { - // CEL follows the proto3 to JSON conversion which formats as an RFC 3339 encoded JSON string. - String ts = Timestamps.toString((Timestamp) value); - return json.setStringValue(ts).build(); - } - if (value instanceof Duration) { - String duration = Durations.toString((Duration) value); - return json.setStringValue(duration).build(); - } - return null; - } - - private @Nullable ListValue adaptValueToJsonListValue(Object value) { - if (!(value instanceof Iterable)) { - return null; - } - Iterable list = (Iterable) value; - ListValue.Builder jsonList = ListValue.newBuilder(); - for (Object elem : list) { - jsonList.addValues(adaptValueToJsonValue(elem)); - } - return jsonList.build(); - } - - private @Nullable Struct adaptValueToJsonStructValue(Object value) { - if (!(value instanceof Map)) { - return null; - } - Map map = (Map) value; - Struct.Builder struct = Struct.newBuilder(); - for (Map.Entry entry : map.entrySet()) { - Object key = entry.getKey(); - Object keyValue = entry.getValue(); - if (!(key instanceof String)) { - // Not a valid map key type for JSON. - return null; - } - struct.putFields((String) key, adaptValueToJsonValue(keyValue)); - } - return struct.build(); + return protoValue.map(Any::pack).orElse(null); } private @Nullable Message adaptValueToDouble(Object value) { diff --git a/common/src/test/java/dev/cel/common/BUILD.bazel b/common/src/test/java/dev/cel/common/BUILD.bazel index d22f00e7f..e7ca691ed 100644 --- a/common/src/test/java/dev/cel/common/BUILD.bazel +++ b/common/src/test/java/dev/cel/common/BUILD.bazel @@ -14,6 +14,7 @@ java_library( "//common:compiler_common", "//common:features", "//common:options", + "//common:proto_json_adapter", "//common:proto_v1alpha1_ast", "//common/ast", "//common/internal", @@ -25,6 +26,7 @@ java_library( "@maven//:com_google_api_grpc_proto_google_common_protos", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", + "@maven//:com_google_testparameterinjector_test_parameter_injector", "@maven//:com_google_truth_extensions_truth_proto_extension", "@maven//:junit_junit", "@maven//:org_antlr_antlr4_runtime", diff --git a/common/src/test/java/dev/cel/common/CelProtoJsonAdapterTest.java b/common/src/test/java/dev/cel/common/CelProtoJsonAdapterTest.java new file mode 100644 index 000000000..e7ccd5233 --- /dev/null +++ b/common/src/test/java/dev/cel/common/CelProtoJsonAdapterTest.java @@ -0,0 +1,80 @@ +// Copyright 2024 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.common; + +import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; +import static org.junit.Assert.assertThrows; + +import com.google.common.collect.ImmutableMap; +import com.google.common.primitives.UnsignedLong; +import com.google.protobuf.ByteString; +import com.google.protobuf.ListValue; +import com.google.protobuf.Struct; +import com.google.protobuf.Value; +import com.google.testing.junit.testparameterinjector.TestParameterInjector; +import java.util.Arrays; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(TestParameterInjector.class) +public class CelProtoJsonAdapterTest { + + @Test + public void adaptValueToJsonValue_asymmetricJsonConversion() { + assertThat(CelProtoJsonAdapter.adaptValueToJsonValue(UnsignedLong.valueOf(1L))) + .isEqualTo(Value.newBuilder().setNumberValue(1).build()); + assertThat(CelProtoJsonAdapter.adaptValueToJsonValue(UnsignedLong.fromLongBits(-1L))) + .isEqualTo(Value.newBuilder().setStringValue(Long.toUnsignedString(-1L)).build()); + assertThat(CelProtoJsonAdapter.adaptValueToJsonValue(1L)) + .isEqualTo(Value.newBuilder().setNumberValue(1).build()); + assertThat(CelProtoJsonAdapter.adaptValueToJsonValue(Long.MAX_VALUE)) + .isEqualTo(Value.newBuilder().setStringValue(Long.toString(Long.MAX_VALUE)).build()); + assertThat(CelProtoJsonAdapter.adaptValueToJsonValue(ByteString.copyFromUtf8("foo"))) + .isEqualTo(Value.newBuilder().setStringValue("Zm9v").build()); + } + + @Test + public void adaptValueToJsonList() { + ListValue listValue = CelProtoJsonAdapter.adaptToJsonListValue(Arrays.asList("hello", "world")); + + assertThat(listValue) + .isEqualTo( + ListValue.newBuilder() + .addValues(Value.newBuilder().setStringValue("hello")) + .addValues(Value.newBuilder().setStringValue("world")) + .build()); + } + + @Test + public void adaptToJsonStructValue() { + Struct struct = CelProtoJsonAdapter.adaptToJsonStructValue(ImmutableMap.of("key", "value")); + + assertThat(struct) + .isEqualTo( + Struct.newBuilder() + .putFields("key", Value.newBuilder().setStringValue("value").build()) + .build()); + } + + @Test + public void adaptValueToJsonValue_unsupportedJsonConversion() { + assertThrows( + ClassCastException.class, + () -> CelProtoJsonAdapter.adaptValueToJsonValue(ImmutableMap.of(1, 1))); + assertThrows( + IllegalArgumentException.class, + () -> CelProtoJsonAdapter.adaptValueToJsonValue(CelSource.newBuilder().build())); + } +} From 81f67b5e50a9a9866022e186916a61c22bee1b76 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Thu, 2 May 2024 13:02:32 -0700 Subject: [PATCH 113/486] Add code for Exercise 6 Codelabs PiperOrigin-RevId: 630153668 --- codelab/README.md | 6 +- codelab/src/main/codelab/Exercise6.java | 73 +++++++++++++ .../src/main/codelab/solutions/Exercise6.java | 75 +++++++++++++ codelab/src/test/codelab/BUILD.bazel | 18 ++++ codelab/src/test/codelab/Exercise6Test.java | 102 ++++++++++++++++++ .../src/test/codelab/solutions/BUILD.bazel | 17 +++ .../test/codelab/solutions/Exercise6Test.java | 102 ++++++++++++++++++ 7 files changed, 392 insertions(+), 1 deletion(-) create mode 100644 codelab/src/main/codelab/Exercise6.java create mode 100644 codelab/src/main/codelab/solutions/Exercise6.java create mode 100644 codelab/src/test/codelab/Exercise6Test.java create mode 100644 codelab/src/test/codelab/solutions/Exercise6Test.java diff --git a/codelab/README.md b/codelab/README.md index 7142a97b4..825783620 100644 --- a/codelab/README.md +++ b/codelab/README.md @@ -16,6 +16,7 @@ Some key areas covered are: * [Creating variables](#creating-variables) * [Commutatibe logical AND/OR](#logical-andor) * [Adding custom functions](#custom-functions) +* [Building Protos](#building-protos) ### Prerequisites This codelab builds upon a basic understanding of Protocol Buffers and Java. @@ -299,7 +300,7 @@ CelAbstractSyntaxTree compile(String expression, String variableName, CelType va The compiler's `addVar` method allows us to declare variables. Note that you must supply the type of the variable being declared. Supported CEL types can be found [here](https://github.com/google/cel-java/tree/main/common/src/main/java/dev/cel/common/types). > [!TIP] -> Best practice: You may have noticed addVar has an overloaded method which accepts a proto based Type instead of the CEL-Java native CelType used in this example. While the two types are functionally equivalent, we recommend using the native types whenever possible. +> Best practice: You may have noticed `addVar` has an overloaded method which accepts a proto based Type instead of the CEL-Java native CelType used in this example. While the two types are functionally equivalent, we recommend using the native types whenever possible. Let's make the evaluation work now. Copy into the eval method: @@ -635,3 +636,6 @@ private static boolean mapContainsKeyValue(Object[] args) { > [!TIP] > Best practice: Declare overload ids according to their types and function names. e.g. targetType_func_argType_argType. In the case where argType is a type param, use a descriptive name instead of the simple type name. +## Building Protos + +CEL can also build protobuf messages for any message type compiled into the application. \ No newline at end of file diff --git a/codelab/src/main/codelab/Exercise6.java b/codelab/src/main/codelab/Exercise6.java new file mode 100644 index 000000000..9991fb566 --- /dev/null +++ b/codelab/src/main/codelab/Exercise6.java @@ -0,0 +1,73 @@ +// Copyright 2024 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 codelab; + +import com.google.rpc.context.AttributeContext.Request; +import dev.cel.common.CelAbstractSyntaxTree; +import dev.cel.common.CelValidationException; +import dev.cel.common.types.StructTypeReference; +import dev.cel.compiler.CelCompiler; +import dev.cel.compiler.CelCompilerFactory; +import dev.cel.runtime.CelEvaluationException; +import dev.cel.runtime.CelRuntime; +import dev.cel.runtime.CelRuntimeFactory; +import java.util.Map; + +/** + * Exercise6 describes how to build proto message types within CEL. + * + *

Given an input `jwt` and time `now` construct a `google.rpc.context.AttributeContext.Request` + * with the `time` and `auth` fields populated according to the + * google.rpc.context.AttributeContext.Request specification. + */ +final class Exercise6 { + + /** + * Compiles the input expression. + * + * @throws IllegalArgumentException If the expression is malformed due to syntactic or semantic + * errors. + */ + CelAbstractSyntaxTree compile(String expression) { + CelCompiler celCompiler = + CelCompilerFactory.standardCelCompilerBuilder() + // Set the container here for "google.rpc.context.AttributeContext" + // Declare variables for "jwt" and "now" here + .addMessageTypes(Request.getDescriptor()) + .setResultType(StructTypeReference.create(Request.getDescriptor().getFullName())) + .build(); + + try { + return celCompiler.compile(expression).getAst(); + } catch (CelValidationException e) { + throw new IllegalArgumentException("Failed to compile expression.", e); + } + } + + /** Evaluates the compiled AST with the user provided parameter values. */ + Object eval(CelAbstractSyntaxTree ast, Map parameterValues) { + CelRuntime celRuntime = + CelRuntimeFactory.standardCelRuntimeBuilder() + .addMessageTypes(Request.getDescriptor()) + .build(); + + try { + CelRuntime.Program program = celRuntime.createProgram(ast); + return program.eval(parameterValues); + } catch (CelEvaluationException e) { + throw new IllegalArgumentException("Evaluation error has occurred.", e); + } + } +} diff --git a/codelab/src/main/codelab/solutions/Exercise6.java b/codelab/src/main/codelab/solutions/Exercise6.java new file mode 100644 index 000000000..beb9d27ee --- /dev/null +++ b/codelab/src/main/codelab/solutions/Exercise6.java @@ -0,0 +1,75 @@ +// Copyright 2024 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 codelab.solutions; + +import com.google.rpc.context.AttributeContext.Request; +import dev.cel.common.CelAbstractSyntaxTree; +import dev.cel.common.CelValidationException; +import dev.cel.common.types.SimpleType; +import dev.cel.common.types.StructTypeReference; +import dev.cel.compiler.CelCompiler; +import dev.cel.compiler.CelCompilerFactory; +import dev.cel.runtime.CelEvaluationException; +import dev.cel.runtime.CelRuntime; +import dev.cel.runtime.CelRuntimeFactory; +import java.util.Map; + +/** + * Exercise6 describes how to build proto message types within CEL. + * + *

Given an input `jwt` and time `now` construct a `google.rpc.context.AttributeContext.Request` + * with the `time` and `auth` fields populated according to the + * google.rpc.context.AttributeContext.Request specification. + */ +final class Exercise6 { + + /** + * Compiles the input expression. + * + * @throws IllegalArgumentException If the expression is malformed due to syntactic or semantic + * errors. + */ + CelAbstractSyntaxTree compile(String expression) { + CelCompiler celCompiler = + CelCompilerFactory.standardCelCompilerBuilder() + .setContainer("google.rpc.context.AttributeContext") + .addVar("jwt", SimpleType.DYN) + .addVar("now", SimpleType.TIMESTAMP) + .addMessageTypes(Request.getDescriptor()) + .setResultType(StructTypeReference.create(Request.getDescriptor().getFullName())) + .build(); + + try { + return celCompiler.compile(expression).getAst(); + } catch (CelValidationException e) { + throw new IllegalArgumentException("Failed to compile expression.", e); + } + } + + /** Evaluates the compiled AST with the user provided parameter values. */ + Object eval(CelAbstractSyntaxTree ast, Map parameterValues) { + CelRuntime celRuntime = + CelRuntimeFactory.standardCelRuntimeBuilder() + .addMessageTypes(Request.getDescriptor()) + .build(); + + try { + CelRuntime.Program program = celRuntime.createProgram(ast); + return program.eval(parameterValues); + } catch (CelEvaluationException e) { + throw new IllegalArgumentException("Evaluation error has occurred.", e); + } + } +} diff --git a/codelab/src/test/codelab/BUILD.bazel b/codelab/src/test/codelab/BUILD.bazel index 784da09ab..94ae17c97 100644 --- a/codelab/src/test/codelab/BUILD.bazel +++ b/codelab/src/test/codelab/BUILD.bazel @@ -82,6 +82,24 @@ java_test( ], ) +java_test( + name = "Exercise6Test", + srcs = ["Exercise6Test.java"], + tags = ["notap"], + test_class = "codelab.Exercise6Test", + deps = [ + "//:java_truth", + "//codelab", + "//common", + "@maven//:com_google_api_grpc_proto_google_common_protos", + "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", + "@maven//:com_google_protobuf_protobuf_java_util", + "@maven//:com_google_testparameterinjector_test_parameter_injector", + "@maven//:junit_junit", + ], +) + test_suite( name = "exercise_test_suite", tags = ["notap"], diff --git a/codelab/src/test/codelab/Exercise6Test.java b/codelab/src/test/codelab/Exercise6Test.java new file mode 100644 index 000000000..ed3c49bd4 --- /dev/null +++ b/codelab/src/test/codelab/Exercise6Test.java @@ -0,0 +1,102 @@ +// Copyright 2024 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 codelab; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.common.collect.ImmutableMap; +import com.google.protobuf.Struct; +import com.google.protobuf.Timestamp; +import com.google.protobuf.Value; +import com.google.protobuf.util.Timestamps; +import com.google.rpc.context.AttributeContext; +import com.google.testing.junit.testparameterinjector.TestParameterInjector; +import dev.cel.common.CelAbstractSyntaxTree; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(TestParameterInjector.class) +public final class Exercise6Test { + private final Exercise6 exercise6 = new Exercise6(); + + @Test + public void evaluate_constructAttributeContext() { + // Given JSON web token and the current time as input variables, + // Setup an expression to construct an AttributeContext protobuf object. + // + // Note: the field names within the proto message types are not quoted as they + // are well-defined names composed of valid identifier characters. Also, note + // that when building nested proto objects, the message name needs to prefix + // the object construction. + String expression = + "Request{\n" + + "auth: Auth{" + + " principal: jwt.iss + '/' + jwt.sub," + + " audiences: [jwt.aud]," + + " presenter: 'azp' in jwt ? jwt.azp : ''," + + " claims: jwt" + + "}," + + "time: now" + + "}"; + // Values for `now` and `jwt` variables to be passed into the runtime + Timestamp now = Timestamps.now(); + ImmutableMap jwt = + ImmutableMap.of( + "sub", "serviceAccount:delegate@acme.co", + "aud", "my-project", + "iss", "auth.acme.com:12350", + "extra_claims", ImmutableMap.of("group", "admin")); + AttributeContext.Request expectedMessage = + AttributeContext.Request.newBuilder() + .setTime(now) + .setAuth( + AttributeContext.Auth.newBuilder() + .setPrincipal("auth.acme.com:12350/serviceAccount:delegate@acme.co") + .addAudiences("my-project") + .setClaims( + Struct.newBuilder() + .putAllFields( + ImmutableMap.of( + "sub", newStringValue("serviceAccount:delegate@acme.co"), + "aud", newStringValue("my-project"), + "iss", newStringValue("auth.acme.com:12350"))) + .putFields( + "extra_claims", + Value.newBuilder() + .setStructValue( + Struct.newBuilder() + .putFields("group", newStringValue("admin")) + .build()) + .build()))) + .build(); + + // Compile the `Request` message construction expression and validate that + // the resulting expression type matches the fully qualified message name. + CelAbstractSyntaxTree ast = exercise6.compile(expression); + AttributeContext.Request evaluatedResult = + (AttributeContext.Request) + exercise6.eval( + ast, + ImmutableMap.of( + "now", now, + "jwt", jwt)); + + assertThat(evaluatedResult).isEqualTo(expectedMessage); + } + + private static Value newStringValue(String value) { + return Value.newBuilder().setStringValue(value).build(); + } +} diff --git a/codelab/src/test/codelab/solutions/BUILD.bazel b/codelab/src/test/codelab/solutions/BUILD.bazel index 92b66a917..2d33cb1cd 100644 --- a/codelab/src/test/codelab/solutions/BUILD.bazel +++ b/codelab/src/test/codelab/solutions/BUILD.bazel @@ -76,3 +76,20 @@ java_test( "@maven//:junit_junit", ], ) + +java_test( + name = "Exercise6Test", + srcs = ["Exercise6Test.java"], + test_class = "codelab.solutions.Exercise6Test", + deps = [ + "//:java_truth", + "//codelab:solutions", + "//common", + "@maven//:com_google_api_grpc_proto_google_common_protos", + "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", + "@maven//:com_google_protobuf_protobuf_java_util", + "@maven//:com_google_testparameterinjector_test_parameter_injector", + "@maven//:junit_junit", + ], +) diff --git a/codelab/src/test/codelab/solutions/Exercise6Test.java b/codelab/src/test/codelab/solutions/Exercise6Test.java new file mode 100644 index 000000000..0c31a05e8 --- /dev/null +++ b/codelab/src/test/codelab/solutions/Exercise6Test.java @@ -0,0 +1,102 @@ +// Copyright 2024 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 codelab.solutions; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.common.collect.ImmutableMap; +import com.google.protobuf.Struct; +import com.google.protobuf.Timestamp; +import com.google.protobuf.Value; +import com.google.protobuf.util.Timestamps; +import com.google.rpc.context.AttributeContext; +import com.google.testing.junit.testparameterinjector.TestParameterInjector; +import dev.cel.common.CelAbstractSyntaxTree; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(TestParameterInjector.class) +public final class Exercise6Test { + private final Exercise6 exercise6 = new Exercise6(); + + @Test + public void evaluate_constructAttributeContext() { + // Given JSON web token and the current time as input variables, + // Setup an expression to construct an AttributeContext protobuf object. + // + // Note: the field names within the proto message types are not quoted as they + // are well-defined names composed of valid identifier characters. Also, note + // that when building nested proto objects, the message name needs to prefix + // the object construction. + String expression = + "Request{\n" + + "auth: Auth{" + + " principal: jwt.iss + '/' + jwt.sub," + + " audiences: [jwt.aud]," + + " presenter: 'azp' in jwt ? jwt.azp : ''," + + " claims: jwt" + + "}," + + "time: now" + + "}"; + // Values for `now` and `jwt` variables to be passed into the runtime + Timestamp now = Timestamps.now(); + ImmutableMap jwt = + ImmutableMap.of( + "sub", "serviceAccount:delegate@acme.co", + "aud", "my-project", + "iss", "auth.acme.com:12350", + "extra_claims", ImmutableMap.of("group", "admin")); + AttributeContext.Request expectedMessage = + AttributeContext.Request.newBuilder() + .setTime(now) + .setAuth( + AttributeContext.Auth.newBuilder() + .setPrincipal("auth.acme.com:12350/serviceAccount:delegate@acme.co") + .addAudiences("my-project") + .setClaims( + Struct.newBuilder() + .putAllFields( + ImmutableMap.of( + "sub", newStringValue("serviceAccount:delegate@acme.co"), + "aud", newStringValue("my-project"), + "iss", newStringValue("auth.acme.com:12350"))) + .putFields( + "extra_claims", + Value.newBuilder() + .setStructValue( + Struct.newBuilder() + .putFields("group", newStringValue("admin")) + .build()) + .build()))) + .build(); + + // Compile the `Request` message construction expression and validate that + // the resulting expression type matches the fully qualified message name. + CelAbstractSyntaxTree ast = exercise6.compile(expression); + AttributeContext.Request evaluatedResult = + (AttributeContext.Request) + exercise6.eval( + ast, + ImmutableMap.of( + "now", now, + "jwt", jwt)); + + assertThat(evaluatedResult).isEqualTo(expectedMessage); + } + + private static Value newStringValue(String value) { + return Value.newBuilder().setStringValue(value).build(); + } +} From 27a9ecd7967cd4c321934e2407d2e15f08a3d8c8 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Thu, 2 May 2024 14:37:25 -0700 Subject: [PATCH 114/486] Release 0.5.1 POM.xml had gone missing in 0.5.0 artifact in maven central (even though the hashes for it are present). We're working with Sonatype to resolve the issue, but the only solution is to publish a new artifact. There are no actual changes from 0.5.0. PiperOrigin-RevId: 630182641 --- README.md | 4 ++-- publish/cel_version.bzl | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 8d40e9e85..738d0e866 100644 --- a/README.md +++ b/README.md @@ -55,14 +55,14 @@ CEL-Java is available in Maven Central Repository. [Download the JARs here][8] o dev.cel cel - 0.5.0 + 0.5.1 ``` **Gradle** ```gradle -implementation 'dev.cel:cel:0.5.0' +implementation 'dev.cel:cel:0.5.1' ``` Then run this example: diff --git a/publish/cel_version.bzl b/publish/cel_version.bzl index 271103327..9f043258b 100644 --- a/publish/cel_version.bzl +++ b/publish/cel_version.bzl @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. """Maven artifact version for CEL.""" -CEL_VERSION = "0.5.0" +CEL_VERSION = "0.5.1" From 20a042007ad4e42a4ae77584aa6371874085eff9 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Thu, 2 May 2024 15:23:13 -0700 Subject: [PATCH 115/486] Add code for Exercise 7 Codelabs PiperOrigin-RevId: 630195206 --- codelab/src/main/codelab/BUILD.bazel | 8 +- codelab/src/main/codelab/Exercise7.java | 72 ++++++++++++++++++ .../src/main/codelab/solutions/BUILD.bazel | 1 + .../src/main/codelab/solutions/Exercise7.java | 74 +++++++++++++++++++ codelab/src/test/codelab/BUILD.bazel | 15 ++++ codelab/src/test/codelab/Exercise7Test.java | 60 +++++++++++++++ .../src/test/codelab/solutions/BUILD.bazel | 14 ++++ .../test/codelab/solutions/Exercise7Test.java | 60 +++++++++++++++ 8 files changed, 300 insertions(+), 4 deletions(-) create mode 100644 codelab/src/main/codelab/Exercise7.java create mode 100644 codelab/src/main/codelab/solutions/Exercise7.java create mode 100644 codelab/src/test/codelab/Exercise7Test.java create mode 100644 codelab/src/test/codelab/solutions/Exercise7Test.java diff --git a/codelab/src/main/codelab/BUILD.bazel b/codelab/src/main/codelab/BUILD.bazel index badfc74f2..c5ede3a1a 100644 --- a/codelab/src/main/codelab/BUILD.bazel +++ b/codelab/src/main/codelab/BUILD.bazel @@ -9,9 +9,6 @@ java_library( name = "codelab", srcs = glob(["*.java"]), deps = [ - "@maven//:com_google_protobuf_protobuf_java", # unuseddeps: keep - "@maven//:com_google_api_grpc_proto_google_common_protos", # unuseddeps: keep - "@maven//:com_google_guava_guava", # unuseddeps: keep "//common", # unuseddeps: keep "//common:compiler_common", # unuseddeps: keep "//common:proto_json_adapter", # unuseddeps: keep @@ -19,8 +16,11 @@ java_library( "//common/types:type_providers", # unuseddeps: keep "//compiler", # unuseddeps: keep "//compiler:compiler_builder", # unuseddeps: keep + "//parser:macro", # unuseddeps: keep "//runtime", # unuseddeps: keep + "@maven//:com_google_api_grpc_proto_google_common_protos", # unuseddeps: keep + "@maven//:com_google_guava_guava", # unuseddeps: keep + "@maven//:com_google_protobuf_protobuf_java", # unuseddeps: keep "@maven//:com_google_protobuf_protobuf_java_util", # unuseddeps: keep - # ], ) diff --git a/codelab/src/main/codelab/Exercise7.java b/codelab/src/main/codelab/Exercise7.java new file mode 100644 index 000000000..ce2efd88e --- /dev/null +++ b/codelab/src/main/codelab/Exercise7.java @@ -0,0 +1,72 @@ +// Copyright 2024 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 codelab; + +import com.google.rpc.context.AttributeContext.Request; +import dev.cel.common.CelAbstractSyntaxTree; +import dev.cel.common.CelValidationException; +import dev.cel.common.types.SimpleType; +import dev.cel.compiler.CelCompiler; +import dev.cel.compiler.CelCompilerFactory; +import dev.cel.runtime.CelEvaluationException; +import dev.cel.runtime.CelRuntime; +import dev.cel.runtime.CelRuntimeFactory; +import java.util.Map; + +/** + * Exercise7 introduces macros for dealing with repeated fields and maps. + * + *

Determine whether the `jwt.extra_claims` has at least one key that starts with the `group` + * prefix, and ensure that all group-like keys have list values containing only strings that end + * with '@acme.co`. + */ +final class Exercise7 { + + /** + * Compiles the input expression. + * + * @throws IllegalArgumentException If the expression is malformed due to syntactic or semantic + * errors. + */ + CelAbstractSyntaxTree compile(String expression) { + CelCompiler celCompiler = + CelCompilerFactory.standardCelCompilerBuilder() + .addVar("jwt", SimpleType.DYN) + // Set the macros here for `all`, `filter` and `exists`. + .setResultType(SimpleType.BOOL) + .build(); + + try { + return celCompiler.compile(expression).getAst(); + } catch (CelValidationException e) { + throw new IllegalArgumentException("Failed to compile expression.", e); + } + } + + /** Evaluates the compiled AST with the user provided parameter values. */ + Object eval(CelAbstractSyntaxTree ast, Map parameterValues) { + CelRuntime celRuntime = + CelRuntimeFactory.standardCelRuntimeBuilder() + .addMessageTypes(Request.getDescriptor()) + .build(); + + try { + CelRuntime.Program program = celRuntime.createProgram(ast); + return program.eval(parameterValues); + } catch (CelEvaluationException e) { + throw new IllegalArgumentException("Evaluation error has occurred.", e); + } + } +} diff --git a/codelab/src/main/codelab/solutions/BUILD.bazel b/codelab/src/main/codelab/solutions/BUILD.bazel index 3e4be9874..40b18fca1 100644 --- a/codelab/src/main/codelab/solutions/BUILD.bazel +++ b/codelab/src/main/codelab/solutions/BUILD.bazel @@ -16,6 +16,7 @@ java_library( "//common/types:type_providers", "//compiler", "//compiler:compiler_builder", + "//parser:macro", "//runtime", "@maven//:com_google_api_grpc_proto_google_common_protos", "@maven//:com_google_guava_guava", diff --git a/codelab/src/main/codelab/solutions/Exercise7.java b/codelab/src/main/codelab/solutions/Exercise7.java new file mode 100644 index 000000000..e5be29171 --- /dev/null +++ b/codelab/src/main/codelab/solutions/Exercise7.java @@ -0,0 +1,74 @@ +// Copyright 2024 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 codelab.solutions; + +import com.google.rpc.context.AttributeContext.Request; +import dev.cel.common.CelAbstractSyntaxTree; +import dev.cel.common.CelValidationException; +import dev.cel.common.types.SimpleType; +import dev.cel.compiler.CelCompiler; +import dev.cel.compiler.CelCompilerFactory; +import dev.cel.parser.CelStandardMacro; +import dev.cel.runtime.CelEvaluationException; +import dev.cel.runtime.CelRuntime; +import dev.cel.runtime.CelRuntimeFactory; +import java.util.Map; + +/** + * Exercise7 introduces macros for dealing with repeated fields and maps. + * + *

Determine whether the `jwt.extra_claims` has at least one key that starts with the `group` + * prefix, and ensure that all group-like keys have list values containing only strings that end + * with '@acme.co`. + */ +final class Exercise7 { + + /** + * Compiles the input expression. + * + * @throws IllegalArgumentException If the expression is malformed due to syntactic or semantic + * errors. + */ + CelAbstractSyntaxTree compile(String expression) { + CelCompiler celCompiler = + CelCompilerFactory.standardCelCompilerBuilder() + .addVar("jwt", SimpleType.DYN) + .setStandardMacros( + CelStandardMacro.ALL, CelStandardMacro.FILTER, CelStandardMacro.EXISTS) + .setResultType(SimpleType.BOOL) + .build(); + + try { + return celCompiler.compile(expression).getAst(); + } catch (CelValidationException e) { + throw new IllegalArgumentException("Failed to compile expression.", e); + } + } + + /** Evaluates the compiled AST with the user provided parameter values. */ + Object eval(CelAbstractSyntaxTree ast, Map parameterValues) { + CelRuntime celRuntime = + CelRuntimeFactory.standardCelRuntimeBuilder() + .addMessageTypes(Request.getDescriptor()) + .build(); + + try { + CelRuntime.Program program = celRuntime.createProgram(ast); + return program.eval(parameterValues); + } catch (CelEvaluationException e) { + throw new IllegalArgumentException("Evaluation error has occurred.", e); + } + } +} diff --git a/codelab/src/test/codelab/BUILD.bazel b/codelab/src/test/codelab/BUILD.bazel index 94ae17c97..5a979c968 100644 --- a/codelab/src/test/codelab/BUILD.bazel +++ b/codelab/src/test/codelab/BUILD.bazel @@ -100,6 +100,21 @@ java_test( ], ) +java_test( + name = "Exercise7Test", + srcs = ["Exercise7Test.java"], + tags = ["notap"], + test_class = "codelab.Exercise7Test", + deps = [ + "//:java_truth", + "//codelab", + "//common", + "@maven//:com_google_guava_guava", + "@maven//:com_google_testparameterinjector_test_parameter_injector", + "@maven//:junit_junit", + ], +) + test_suite( name = "exercise_test_suite", tags = ["notap"], diff --git a/codelab/src/test/codelab/Exercise7Test.java b/codelab/src/test/codelab/Exercise7Test.java new file mode 100644 index 000000000..2caf0e4f9 --- /dev/null +++ b/codelab/src/test/codelab/Exercise7Test.java @@ -0,0 +1,60 @@ +// Copyright 2024 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 codelab; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.testing.junit.testparameterinjector.TestParameterInjector; +import dev.cel.common.CelAbstractSyntaxTree; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(TestParameterInjector.class) +public final class Exercise7Test { + private final Exercise7 exercise7 = new Exercise7(); + + @Test + public void evaluate_checkJwtClaimsWithMacro_evaluatesToTrue() { + String expression = + "jwt.extra_claims.exists(c, c.startsWith('group'))" + + " && jwt.extra_claims" + + ".filter(c, c.startsWith('group'))" + + ".all(c, jwt.extra_claims[c]" + + ".all(g, g.endsWith('@acme.co')))"; + ImmutableMap jwt = + ImmutableMap.of( + "sub", + "serviceAccount:delegate@acme.co", + "aud", + "my-project", + "iss", + "auth.acme.com:12350", + "extra_claims", + ImmutableMap.of("group1", ImmutableList.of("admin@acme.co", "analyst@acme.co")), + "labels", + ImmutableList.of("metadata", "prod", "pii"), + "groupN", + ImmutableList.of("forever@acme.co")); + CelAbstractSyntaxTree ast = exercise7.compile(expression); + + // Evaluate a complex-ish JWT with two groups that satisfy the criteria. + // Output: true. + boolean evaluatedResult = (boolean) exercise7.eval(ast, ImmutableMap.of("jwt", jwt)); + + assertThat(evaluatedResult).isTrue(); + } +} diff --git a/codelab/src/test/codelab/solutions/BUILD.bazel b/codelab/src/test/codelab/solutions/BUILD.bazel index 2d33cb1cd..5c139b613 100644 --- a/codelab/src/test/codelab/solutions/BUILD.bazel +++ b/codelab/src/test/codelab/solutions/BUILD.bazel @@ -93,3 +93,17 @@ java_test( "@maven//:junit_junit", ], ) + +java_test( + name = "Exercise7Test", + srcs = ["Exercise7Test.java"], + test_class = "codelab.solutions.Exercise7Test", + deps = [ + "//:java_truth", + "//codelab:solutions", + "//common", + "@maven//:com_google_guava_guava", + "@maven//:com_google_testparameterinjector_test_parameter_injector", + "@maven//:junit_junit", + ], +) diff --git a/codelab/src/test/codelab/solutions/Exercise7Test.java b/codelab/src/test/codelab/solutions/Exercise7Test.java new file mode 100644 index 000000000..be0fe8af1 --- /dev/null +++ b/codelab/src/test/codelab/solutions/Exercise7Test.java @@ -0,0 +1,60 @@ +// Copyright 2024 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 codelab.solutions; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.testing.junit.testparameterinjector.TestParameterInjector; +import dev.cel.common.CelAbstractSyntaxTree; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(TestParameterInjector.class) +public final class Exercise7Test { + private final Exercise7 exercise7 = new Exercise7(); + + @Test + public void evaluate_checkJwtClaimsWithMacro_evaluatesToTrue() { + String expression = + "jwt.extra_claims.exists(c, c.startsWith('group'))" + + " && jwt.extra_claims" + + ".filter(c, c.startsWith('group'))" + + ".all(c, jwt.extra_claims[c]" + + ".all(g, g.endsWith('@acme.co')))"; + ImmutableMap jwt = + ImmutableMap.of( + "sub", + "serviceAccount:delegate@acme.co", + "aud", + "my-project", + "iss", + "auth.acme.com:12350", + "extra_claims", + ImmutableMap.of("group1", ImmutableList.of("admin@acme.co", "analyst@acme.co")), + "labels", + ImmutableList.of("metadata", "prod", "pii"), + "groupN", + ImmutableList.of("forever@acme.co")); + CelAbstractSyntaxTree ast = exercise7.compile(expression); + + // Evaluate a complex-ish JWT with two groups that satisfy the criteria. + // Output: true. + boolean evaluatedResult = (boolean) exercise7.eval(ast, ImmutableMap.of("jwt", jwt)); + + assertThat(evaluatedResult).isTrue(); + } +} From c30f417656d15400573452888b0ad783623c4bb3 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Mon, 6 May 2024 15:11:09 -0700 Subject: [PATCH 116/486] Remove deprecated create methods PiperOrigin-RevId: 631198940 --- .../main/java/dev/cel/common/ast/CelExpr.java | 67 ++----------------- .../dev/cel/common/ast/CelExprConverter.java | 4 +- .../common/ast/CelExprV1Alpha1Converter.java | 4 +- 3 files changed, 10 insertions(+), 65 deletions(-) diff --git a/common/src/main/java/dev/cel/common/ast/CelExpr.java b/common/src/main/java/dev/cel/common/ast/CelExpr.java index 0868daa13..9960ae395 100644 --- a/common/src/main/java/dev/cel/common/ast/CelExpr.java +++ b/common/src/main/java/dev/cel/common/ast/CelExpr.java @@ -23,7 +23,6 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.errorprone.annotations.CheckReturnValue; import com.google.errorprone.annotations.Immutable; -import com.google.errorprone.annotations.InlineMe; import dev.cel.common.ast.CelExpr.ExprKind.Kind; import java.util.ArrayList; import java.util.Arrays; @@ -90,15 +89,6 @@ public CelCall call() { return exprKind().call(); } - /** - * @deprecated Use {@link #list()} instead. - */ - @Deprecated - @InlineMe(replacement = "this.list()") - public final CelList createList() { - return list(); - } - /** * {@inheritDoc} * @@ -106,16 +96,7 @@ public final CelList createList() { */ @Override public CelList list() { - return exprKind().createList(); - } - - /** - * @deprecated Use {@link #list()} instead. - */ - @Deprecated - @InlineMe(replacement = "this.struct()") - public final CelStruct createStruct() { - return struct(); + return exprKind().list(); } /** @@ -125,16 +106,7 @@ public final CelStruct createStruct() { */ @Override public CelStruct struct() { - return exprKind().createStruct(); - } - - /** - * @deprecated Use {@link #list()} instead. - */ - @Deprecated - @InlineMe(replacement = "this.map()") - public final CelMap createMap() { - return map(); + return exprKind().struct(); } /** @@ -144,7 +116,7 @@ public final CelMap createMap() { */ @Override public CelMap map() { - return exprKind().createMap(); + return exprKind().map(); } /** @@ -203,7 +175,7 @@ public CelCall callOrDefault() { */ public CelList listOrDefault() { return exprKind().getKind().equals(ExprKind.Kind.LIST) - ? exprKind().createList() + ? exprKind().list() : CelList.newBuilder().build(); } @@ -213,7 +185,7 @@ public CelList listOrDefault() { */ public CelStruct structOrDefault() { return exprKind().getKind().equals(ExprKind.Kind.STRUCT) - ? exprKind().createStruct() + ? exprKind().struct() : CelStruct.newBuilder().build(); } @@ -223,7 +195,7 @@ public CelStruct structOrDefault() { */ public CelMap mapOrDefault() { return exprKind().getKind().equals(ExprKind.Kind.MAP) - ? exprKind().createMap() + ? exprKind().map() : CelMap.newBuilder().build(); } @@ -405,37 +377,10 @@ public enum Kind { public abstract CelList list(); - /** - * @deprecated Use {@link #list()} instead. - */ - @Deprecated - @InlineMe(replacement = "this.list()") - public final CelList createList() { - return list(); - } - public abstract CelStruct struct(); - /** - * @deprecated Use {@link #struct()} instead. - */ - @Deprecated - @InlineMe(replacement = "this.struct()") - public final CelStruct createStruct() { - return struct(); - } - public abstract CelMap map(); - /** - * @deprecated Use {@link #map()} instead. - */ - @Deprecated - @InlineMe(replacement = "this.map()") - public final CelMap createMap() { - return map(); - } - public abstract CelComprehension comprehension(); } diff --git a/common/src/main/java/dev/cel/common/ast/CelExprConverter.java b/common/src/main/java/dev/cel/common/ast/CelExprConverter.java index 994ea3210..bb36575f0 100644 --- a/common/src/main/java/dev/cel/common/ast/CelExprConverter.java +++ b/common/src/main/java/dev/cel/common/ast/CelExprConverter.java @@ -76,9 +76,9 @@ public static Expr fromCelExpr(CelExpr celExpr) { .addAllOptionalIndices(celCreateList.optionalIndices())) .build(); case STRUCT: - return expr.setStructExpr(celStructToExprStruct(celExprKind.createStruct())).build(); + return expr.setStructExpr(celStructToExprStruct(celExprKind.struct())).build(); case MAP: - return expr.setStructExpr(celMapToExprStruct(celExprKind.createMap())).build(); + return expr.setStructExpr(celMapToExprStruct(celExprKind.map())).build(); case COMPREHENSION: CelExpr.CelComprehension celComprehension = celExprKind.comprehension(); return expr.setComprehensionExpr( diff --git a/common/src/main/java/dev/cel/common/ast/CelExprV1Alpha1Converter.java b/common/src/main/java/dev/cel/common/ast/CelExprV1Alpha1Converter.java index 794d78f8b..85a9ae665 100644 --- a/common/src/main/java/dev/cel/common/ast/CelExprV1Alpha1Converter.java +++ b/common/src/main/java/dev/cel/common/ast/CelExprV1Alpha1Converter.java @@ -76,9 +76,9 @@ public static Expr fromCelExpr(CelExpr celExpr) { .addAllOptionalIndices(celCreateList.optionalIndices())) .build(); case STRUCT: - return expr.setStructExpr(celStructToExprStruct(celExprKind.createStruct())).build(); + return expr.setStructExpr(celStructToExprStruct(celExprKind.struct())).build(); case MAP: - return expr.setStructExpr(celMapToExprStruct(celExprKind.createMap())).build(); + return expr.setStructExpr(celMapToExprStruct(celExprKind.map())).build(); case COMPREHENSION: CelExpr.CelComprehension celComprehension = celExprKind.comprehension(); return expr.setComprehensionExpr( From 2a8789f8fc1383bb7992de8366a3cb73b2bbed1e Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Mon, 6 May 2024 16:03:56 -0700 Subject: [PATCH 117/486] Variable name cleanups from removing create modifier PiperOrigin-RevId: 631214133 --- .../test/java/dev/cel/bundle/CelImplTest.java | 6 +- .../java/dev/cel/checker/ExprChecker.java | 42 ++++++----- .../main/java/dev/cel/common/ast/CelExpr.java | 2 +- .../dev/cel/common/ast/CelExprConverter.java | 16 ++--- .../dev/cel/common/ast/CelExprFormatter.java | 26 +++---- .../common/ast/CelExprV1Alpha1Converter.java | 16 ++--- .../dev/cel/common/ast/CelExprVisitor.java | 12 ++-- .../dev/cel/common/ast/CelMutableExpr.java | 36 +++++----- .../common/ast/CelMutableExprConverter.java | 37 +++++----- .../java/dev/cel/common/ast/Expression.java | 2 +- .../navigation/CelNavigableExprVisitor.java | 8 +-- .../navigation/ExprPropertyCalculator.java | 8 +-- .../cel/common/ast/CelExprFormatterTest.java | 6 +- .../java/dev/cel/common/ast/CelExprTest.java | 59 ++++++++------- .../cel/common/ast/CelExprVisitorTest.java | 18 ++--- .../ast/CelMutableExprConverterTest.java | 12 ++-- .../cel/common/ast/CelMutableExprTest.java | 72 +++++++++---------- .../CelNavigableExprVisitorTest.java | 8 +-- .../dev/cel/optimizer/MutableExprVisitor.java | 14 ++-- .../optimizers/ConstantFoldingOptimizer.java | 20 +++--- .../dev/cel/parser/CelUnparserVisitor.java | 22 +++--- .../java/dev/cel/runtime/CelRuntimeTest.java | 6 +- 22 files changed, 221 insertions(+), 227 deletions(-) diff --git a/bundle/src/test/java/dev/cel/bundle/CelImplTest.java b/bundle/src/test/java/dev/cel/bundle/CelImplTest.java index fc4304657..f1b1dfb00 100644 --- a/bundle/src/test/java/dev/cel/bundle/CelImplTest.java +++ b/bundle/src/test/java/dev/cel/bundle/CelImplTest.java @@ -486,9 +486,9 @@ public void compile_withOptionalTypes() throws Exception { CelAbstractSyntaxTree ast = cel.compile("[?a]").getAst(); - CelList createList = ast.getExpr().list(); - assertThat(createList.optionalIndices()).containsExactly(0); - assertThat(createList.elements()).containsExactly(CelExpr.ofIdent(2, "a")); + CelList list = ast.getExpr().list(); + assertThat(list.optionalIndices()).containsExactly(0); + assertThat(list.elements()).containsExactly(CelExpr.ofIdent(2, "a")); } @Test diff --git a/checker/src/main/java/dev/cel/checker/ExprChecker.java b/checker/src/main/java/dev/cel/checker/ExprChecker.java index dd5d79f35..658c7db06 100644 --- a/checker/src/main/java/dev/cel/checker/ExprChecker.java +++ b/checker/src/main/java/dev/cel/checker/ExprChecker.java @@ -355,10 +355,10 @@ private CelExpr visit(CelExpr expr, CelExpr.CelCall call) { } @CheckReturnValue - private CelExpr visit(CelExpr expr, CelExpr.CelStruct createStruct) { + private CelExpr visit(CelExpr expr, CelExpr.CelStruct struct) { // Determine the type of the message. CelType messageType = SimpleType.ERROR; - CelIdentDecl decl = env.lookupIdent(getPosition(expr), inContainer, createStruct.messageName()); + CelIdentDecl decl = env.lookupIdent(getPosition(expr), inContainer, struct.messageName()); env.setRef(expr, CelReference.newBuilder().setName(decl.name()).build()); CelType type = decl.type(); if (type.kind() != CelKind.ERROR) { @@ -383,7 +383,7 @@ private CelExpr visit(CelExpr expr, CelExpr.CelStruct createStruct) { } // Check the field initializers. - ImmutableList entriesList = createStruct.entries(); + ImmutableList entriesList = struct.entries(); for (int i = 0; i < entriesList.size(); i++) { CelExpr.CelStruct.Entry entry = entriesList.get(i); CelExpr visitedValueExpr = visit(entry.value()); @@ -414,10 +414,10 @@ private CelExpr visit(CelExpr expr, CelExpr.CelStruct createStruct) { } @CheckReturnValue - private CelExpr visit(CelExpr expr, CelExpr.CelMap createMap) { + private CelExpr visit(CelExpr expr, CelExpr.CelMap map) { CelType mapKeyType = null; CelType mapValueType = null; - ImmutableList entriesList = createMap.entries(); + ImmutableList entriesList = map.entries(); for (int i = 0; i < entriesList.size(); i++) { CelExpr.CelMap.Entry entry = entriesList.get(i); CelExpr visitedMapKeyExpr = visit(entry.key()); @@ -455,10 +455,10 @@ private CelExpr visit(CelExpr expr, CelExpr.CelMap createMap) { } @CheckReturnValue - private CelExpr visit(CelExpr expr, CelExpr.CelList createList) { + private CelExpr visit(CelExpr expr, CelExpr.CelList list) { CelType elemsType = null; - ImmutableList elementsList = createList.elements(); - HashSet optionalIndices = new HashSet<>(createList.optionalIndices()); + ImmutableList elementsList = list.elements(); + HashSet optionalIndices = new HashSet<>(list.optionalIndices()); for (int i = 0; i < elementsList.size(); i++) { CelExpr visitedElem = visit(elementsList.get(i)); if (namespacedDeclarations && !visitedElem.equals(elementsList.get(i))) { @@ -853,27 +853,25 @@ private static CelExpr replaceListElementSubtree(CelExpr expr, CelExpr element, } private static CelExpr replaceStructEntryValueSubtree(CelExpr expr, CelExpr newValue, int index) { - CelExpr.CelStruct createStruct = expr.struct(); + CelExpr.CelStruct struct = expr.struct(); CelExpr.CelStruct.Entry newEntry = - createStruct.entries().get(index).toBuilder().setValue(newValue).build(); - createStruct = createStruct.toBuilder().setEntry(index, newEntry).build(); - return expr.toBuilder().setStruct(createStruct).build(); + struct.entries().get(index).toBuilder().setValue(newValue).build(); + struct = struct.toBuilder().setEntry(index, newEntry).build(); + return expr.toBuilder().setStruct(struct).build(); } private static CelExpr replaceMapEntryKeySubtree(CelExpr expr, CelExpr newKey, int index) { - CelExpr.CelMap createMap = expr.map(); - CelExpr.CelMap.Entry newEntry = - createMap.entries().get(index).toBuilder().setKey(newKey).build(); - createMap = createMap.toBuilder().setEntry(index, newEntry).build(); - return expr.toBuilder().setMap(createMap).build(); + CelExpr.CelMap map = expr.map(); + CelExpr.CelMap.Entry newEntry = map.entries().get(index).toBuilder().setKey(newKey).build(); + map = map.toBuilder().setEntry(index, newEntry).build(); + return expr.toBuilder().setMap(map).build(); } private static CelExpr replaceMapEntryValueSubtree(CelExpr expr, CelExpr newValue, int index) { - CelExpr.CelMap createMap = expr.map(); - CelExpr.CelMap.Entry newEntry = - createMap.entries().get(index).toBuilder().setValue(newValue).build(); - createMap = createMap.toBuilder().setEntry(index, newEntry).build(); - return expr.toBuilder().setMap(createMap).build(); + CelExpr.CelMap map = expr.map(); + CelExpr.CelMap.Entry newEntry = map.entries().get(index).toBuilder().setValue(newValue).build(); + map = map.toBuilder().setEntry(index, newEntry).build(); + return expr.toBuilder().setMap(map).build(); } private static CelExpr replaceComprehensionAccuInitSubtree(CelExpr expr, CelExpr newAccuInit) { diff --git a/common/src/main/java/dev/cel/common/ast/CelExpr.java b/common/src/main/java/dev/cel/common/ast/CelExpr.java index 9960ae395..6af628551 100644 --- a/common/src/main/java/dev/cel/common/ast/CelExpr.java +++ b/common/src/main/java/dev/cel/common/ast/CelExpr.java @@ -112,7 +112,7 @@ public CelStruct struct() { /** * {@inheritDoc} * - * @throws UnsupportedOperationException if expression is not {@link Kind#createMap}. + * @throws UnsupportedOperationException if expression is not {@link Kind#MAP}. */ @Override public CelMap map() { diff --git a/common/src/main/java/dev/cel/common/ast/CelExprConverter.java b/common/src/main/java/dev/cel/common/ast/CelExprConverter.java index bb36575f0..dd99b3128 100644 --- a/common/src/main/java/dev/cel/common/ast/CelExprConverter.java +++ b/common/src/main/java/dev/cel/common/ast/CelExprConverter.java @@ -69,11 +69,11 @@ public static Expr fromCelExpr(CelExpr celExpr) { celCall.target().ifPresent(target -> callBuilder.setTarget(fromCelExpr(target))); return expr.setCallExpr(callBuilder).build(); case LIST: - CelExpr.CelList celCreateList = celExprKind.list(); + CelExpr.CelList celList = celExprKind.list(); return expr.setListExpr( CreateList.newBuilder() - .addAllElements(fromCelExprList(celCreateList.elements())) - .addAllOptionalIndices(celCreateList.optionalIndices())) + .addAllElements(fromCelExprList(celList.elements())) + .addAllOptionalIndices(celList.optionalIndices())) .build(); case STRUCT: return expr.setStructExpr(celStructToExprStruct(celExprKind.struct())).build(); @@ -270,9 +270,9 @@ public static Constant celConstantToExprConstant(CelConstant celConstant) { throw new IllegalStateException("unsupported constant case: " + celConstant.getKind()); } - private static CreateStruct celStructToExprStruct(CelExpr.CelStruct celCreateStruct) { + private static CreateStruct celStructToExprStruct(CelExpr.CelStruct celStruct) { ImmutableList.Builder entries = ImmutableList.builder(); - for (CelExpr.CelStruct.Entry celStructExprEntry : celCreateStruct.entries()) { + for (CelExpr.CelStruct.Entry celStructExprEntry : celStruct.entries()) { entries.add( CreateStruct.Entry.newBuilder() .setId(celStructExprEntry.id()) @@ -283,14 +283,14 @@ private static CreateStruct celStructToExprStruct(CelExpr.CelStruct celCreateStr } return CreateStruct.newBuilder() - .setMessageName(celCreateStruct.messageName()) + .setMessageName(celStruct.messageName()) .addAllEntries(entries.build()) .build(); } - private static CreateStruct celMapToExprStruct(CelExpr.CelMap celCreateMap) { + private static CreateStruct celMapToExprStruct(CelExpr.CelMap celMap) { ImmutableList.Builder entries = ImmutableList.builder(); - for (CelExpr.CelMap.Entry celMapEntry : celCreateMap.entries()) { + for (CelExpr.CelMap.Entry celMapEntry : celMap.entries()) { CreateStruct.Entry exprMapEntry = CreateStruct.Entry.newBuilder() .setId(celMapEntry.id()) diff --git a/common/src/main/java/dev/cel/common/ast/CelExprFormatter.java b/common/src/main/java/dev/cel/common/ast/CelExprFormatter.java index 177f3e45f..b56422cbb 100644 --- a/common/src/main/java/dev/cel/common/ast/CelExprFormatter.java +++ b/common/src/main/java/dev/cel/common/ast/CelExprFormatter.java @@ -52,13 +52,13 @@ private void formatExpr(CelExpr celExpr) { appendCall(celExpr.call()); break; case LIST: - appendCreateList(celExpr.list()); + appendList(celExpr.list()); break; case STRUCT: - appendCreateStruct(celExpr.struct()); + appendStruct(celExpr.struct()); break; case MAP: - appendCreateMap(celExpr.map()); + appendMap(celExpr.map()); break; case COMPREHENSION: appendComprehension(celExpr.comprehension()); @@ -152,23 +152,23 @@ private void appendCall(CelExpr.CelCall celCall) { outdent(); } - private void appendCreateList(CelExpr.CelList celCreateList) { + private void appendList(CelExpr.CelList celList) { indent(); append("elements: {"); indent(); - for (CelExpr expr : celCreateList.elements()) { + for (CelExpr expr : celList.elements()) { appendNewline(); formatExpr(expr); } outdent(); appendNewline(); append("}"); - if (!celCreateList.optionalIndices().isEmpty()) { + if (!celList.optionalIndices().isEmpty()) { appendNewline(); append("optional_indices: ["); - for (int i = 0; i < celCreateList.optionalIndices().size(); i++) { + for (int i = 0; i < celList.optionalIndices().size(); i++) { appendWithoutIndent(String.valueOf(i)); - if (i != celCreateList.optionalIndices().size() - 1) { + if (i != celList.optionalIndices().size() - 1) { appendWithoutIndent(", "); } } @@ -177,12 +177,12 @@ private void appendCreateList(CelExpr.CelList celCreateList) { outdent(); } - private void appendCreateStruct(CelExpr.CelStruct celCreateStruct) { + private void appendStruct(CelExpr.CelStruct celStruct) { indent(); - appendWithNewline("name: " + celCreateStruct.messageName()); + appendWithNewline("name: " + celStruct.messageName()); append("entries: {"); indent(); - for (CelExpr.CelStruct.Entry entry : celCreateStruct.entries()) { + for (CelExpr.CelStruct.Entry entry : celStruct.entries()) { appendNewline(); appendWithNewline(String.format("ENTRY [%d] {", entry.id())); indent(); @@ -205,10 +205,10 @@ private void appendCreateStruct(CelExpr.CelStruct celCreateStruct) { outdent(); } - private void appendCreateMap(CelExpr.CelMap celCreateMap) { + private void appendMap(CelExpr.CelMap celMap) { indent(); boolean firstLine = true; - for (CelExpr.CelMap.Entry entry : celCreateMap.entries()) { + for (CelExpr.CelMap.Entry entry : celMap.entries()) { if (!firstLine) { appendNewline(); } else { diff --git a/common/src/main/java/dev/cel/common/ast/CelExprV1Alpha1Converter.java b/common/src/main/java/dev/cel/common/ast/CelExprV1Alpha1Converter.java index 85a9ae665..10b9b347c 100644 --- a/common/src/main/java/dev/cel/common/ast/CelExprV1Alpha1Converter.java +++ b/common/src/main/java/dev/cel/common/ast/CelExprV1Alpha1Converter.java @@ -69,11 +69,11 @@ public static Expr fromCelExpr(CelExpr celExpr) { celCall.target().ifPresent(target -> callBuilder.setTarget(fromCelExpr(target))); return expr.setCallExpr(callBuilder).build(); case LIST: - CelExpr.CelList celCreateList = celExprKind.list(); + CelExpr.CelList celList = celExprKind.list(); return expr.setListExpr( CreateList.newBuilder() - .addAllElements(fromCelExprList(celCreateList.elements())) - .addAllOptionalIndices(celCreateList.optionalIndices())) + .addAllElements(fromCelExprList(celList.elements())) + .addAllOptionalIndices(celList.optionalIndices())) .build(); case STRUCT: return expr.setStructExpr(celStructToExprStruct(celExprKind.struct())).build(); @@ -270,9 +270,9 @@ public static Constant celConstantToExprConstant(CelConstant celConstant) { throw new IllegalStateException("unsupported constant case: " + celConstant.getKind()); } - private static CreateStruct celStructToExprStruct(CelExpr.CelStruct celCreateStruct) { + private static CreateStruct celStructToExprStruct(CelExpr.CelStruct celStruct) { ImmutableList.Builder entries = ImmutableList.builder(); - for (CelExpr.CelStruct.Entry celStructExprEntry : celCreateStruct.entries()) { + for (CelExpr.CelStruct.Entry celStructExprEntry : celStruct.entries()) { entries.add( CreateStruct.Entry.newBuilder() .setId(celStructExprEntry.id()) @@ -283,14 +283,14 @@ private static CreateStruct celStructToExprStruct(CelExpr.CelStruct celCreateStr } return Expr.CreateStruct.newBuilder() - .setMessageName(celCreateStruct.messageName()) + .setMessageName(celStruct.messageName()) .addAllEntries(entries.build()) .build(); } - private static CreateStruct celMapToExprStruct(CelExpr.CelMap celCreateMap) { + private static CreateStruct celMapToExprStruct(CelExpr.CelMap celMap) { ImmutableList.Builder entries = ImmutableList.builder(); - for (CelExpr.CelMap.Entry celMapEntry : celCreateMap.entries()) { + for (CelExpr.CelMap.Entry celMapEntry : celMap.entries()) { CreateStruct.Entry exprMapEntry = CreateStruct.Entry.newBuilder() .setId(celMapEntry.id()) diff --git a/common/src/main/java/dev/cel/common/ast/CelExprVisitor.java b/common/src/main/java/dev/cel/common/ast/CelExprVisitor.java index 2dc1074eb..a5a6cdf17 100644 --- a/common/src/main/java/dev/cel/common/ast/CelExprVisitor.java +++ b/common/src/main/java/dev/cel/common/ast/CelExprVisitor.java @@ -108,23 +108,23 @@ protected void visit(CelExpr expr, CelCall call) { } /** Visit a {@code CelStruct} expression. */ - protected void visit(CelExpr expr, CelStruct createStruct) { - for (CelStruct.Entry entry : createStruct.entries()) { + protected void visit(CelExpr expr, CelStruct struct) { + for (CelStruct.Entry entry : struct.entries()) { visit(entry.value()); } } /** Visit a {@code CelMap} expression. */ - protected void visit(CelExpr expr, CelMap createMap) { - for (CelMap.Entry entry : createMap.entries()) { + protected void visit(CelExpr expr, CelMap map) { + for (CelMap.Entry entry : map.entries()) { visit(entry.key()); visit(entry.value()); } } /** Visit a {@code CelList} expression. */ - protected void visit(CelExpr expr, CelList createList) { - for (CelExpr elem : createList.elements()) { + protected void visit(CelExpr expr, CelList list) { + for (CelExpr elem : list.elements()) { visit(elem); } } diff --git a/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java b/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java index d267d7b8b..c97d36886 100644 --- a/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java +++ b/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java @@ -973,28 +973,28 @@ public static CelMutableExpr ofCall(long id, CelMutableCall mutableCall) { return new CelMutableExpr(id, mutableCall); } - public static CelMutableExpr ofList(CelMutableList mutableCreateList) { - return ofList(0, mutableCreateList); + public static CelMutableExpr ofList(CelMutableList mutableList) { + return ofList(0, mutableList); } - public static CelMutableExpr ofList(long id, CelMutableList mutableCreateList) { - return new CelMutableExpr(id, mutableCreateList); + public static CelMutableExpr ofList(long id, CelMutableList mutableList) { + return new CelMutableExpr(id, mutableList); } - public static CelMutableExpr ofStruct(CelMutableStruct mutableCreateStruct) { - return ofStruct(0, mutableCreateStruct); + public static CelMutableExpr ofStruct(CelMutableStruct mutableStruct) { + return ofStruct(0, mutableStruct); } - public static CelMutableExpr ofStruct(long id, CelMutableStruct mutableCreateStruct) { - return new CelMutableExpr(id, mutableCreateStruct); + public static CelMutableExpr ofStruct(long id, CelMutableStruct mutableStruct) { + return new CelMutableExpr(id, mutableStruct); } - public static CelMutableExpr ofMap(CelMutableMap mutableCreateMap) { - return ofMap(0, mutableCreateMap); + public static CelMutableExpr ofMap(CelMutableMap mutableMap) { + return ofMap(0, mutableMap); } - public static CelMutableExpr ofMap(long id, CelMutableMap mutableCreateMap) { - return new CelMutableExpr(id, mutableCreateMap); + public static CelMutableExpr ofMap(long id, CelMutableMap mutableMap) { + return new CelMutableExpr(id, mutableMap); } public static CelMutableExpr ofComprehension( @@ -1027,19 +1027,19 @@ private CelMutableExpr(long id, CelMutableCall mutableCall) { setCall(mutableCall); } - private CelMutableExpr(long id, CelMutableList mutableCreateList) { + private CelMutableExpr(long id, CelMutableList mutableList) { this.id = id; - setList(mutableCreateList); + setList(mutableList); } - private CelMutableExpr(long id, CelMutableStruct mutableCreateStruct) { + private CelMutableExpr(long id, CelMutableStruct mutableStruct) { this.id = id; - setStruct(mutableCreateStruct); + setStruct(mutableStruct); } - private CelMutableExpr(long id, CelMutableMap mutableCreateMap) { + private CelMutableExpr(long id, CelMutableMap mutableMap) { this.id = id; - setMap(mutableCreateMap); + setMap(mutableMap); } private CelMutableExpr(long id, CelMutableComprehension mutableComprehension) { diff --git a/common/src/main/java/dev/cel/common/ast/CelMutableExprConverter.java b/common/src/main/java/dev/cel/common/ast/CelMutableExprConverter.java index 57d4e9dc8..9362f8307 100644 --- a/common/src/main/java/dev/cel/common/ast/CelMutableExprConverter.java +++ b/common/src/main/java/dev/cel/common/ast/CelMutableExprConverter.java @@ -104,9 +104,9 @@ private static List fromCelExprList(Iterable celExprLis return mutableExprList; } - private static CelMutableStruct fromCelStructToMutableStruct(CelStruct celCreateStruct) { + private static CelMutableStruct fromCelStructToMutableStruct(CelStruct celStruct) { List entries = new ArrayList<>(); - for (CelStruct.Entry celStructExprEntry : celCreateStruct.entries()) { + for (CelStruct.Entry celStructExprEntry : celStruct.entries()) { entries.add( CelMutableStruct.Entry.create( celStructExprEntry.id(), @@ -115,12 +115,12 @@ private static CelMutableStruct fromCelStructToMutableStruct(CelStruct celCreate celStructExprEntry.optionalEntry())); } - return CelMutableStruct.create(celCreateStruct.messageName(), entries); + return CelMutableStruct.create(celStruct.messageName(), entries); } - private static CelMutableMap fromCelMapToMutableMap(CelMap celCreateMap) { + private static CelMutableMap fromCelMapToMutableMap(CelMap celMap) { List entries = new ArrayList<>(); - for (CelMap.Entry celMapExprEntry : celCreateMap.entries()) { + for (CelMap.Entry celMapExprEntry : celMap.entries()) { entries.add( CelMutableMap.Entry.create( celMapExprEntry.id(), @@ -153,23 +153,20 @@ public static CelExpr fromMutableExpr(CelMutableExpr mutableExpr) { mutableCall.target().map(CelMutableExprConverter::fromMutableExpr); return CelExpr.ofCall(id, targetExpr, mutableCall.function(), args); case LIST: - CelMutableList mutableCreateList = mutableExpr.list(); + CelMutableList mutableList = mutableExpr.list(); return CelExpr.ofList( id, - fromMutableExprList(mutableCreateList.elements()), - ImmutableList.copyOf(mutableCreateList.optionalIndices())); + fromMutableExprList(mutableList.elements()), + ImmutableList.copyOf(mutableList.optionalIndices())); case STRUCT: - CelMutableStruct mutableCreateStruct = mutableExpr.struct(); + CelMutableStruct mutableStruct = mutableExpr.struct(); return CelExpr.newBuilder() .setId(id) - .setStruct(fromMutableStructToCelStruct(mutableCreateStruct)) + .setStruct(fromMutableStructToCelStruct(mutableStruct)) .build(); case MAP: - CelMutableMap mutableCreateMap = mutableExpr.map(); - return CelExpr.newBuilder() - .setId(id) - .setMap(fromMutableMapToCelMap(mutableCreateMap)) - .build(); + CelMutableMap mutableMap = mutableExpr.map(); + return CelExpr.newBuilder().setId(id).setMap(fromMutableMapToCelMap(mutableMap)).build(); case COMPREHENSION: CelMutableComprehension mutableComprehension = mutableExpr.comprehension(); return CelExpr.ofComprehension( @@ -197,9 +194,9 @@ private static ImmutableList fromMutableExprList( return celExprList.build(); } - private static CelStruct fromMutableStructToCelStruct(CelMutableStruct mutableCreateStruct) { + private static CelStruct fromMutableStructToCelStruct(CelMutableStruct mutableStruct) { List entries = new ArrayList<>(); - for (CelMutableStruct.Entry mutableStructEntry : mutableCreateStruct.entries()) { + for (CelMutableStruct.Entry mutableStructEntry : mutableStruct.entries()) { entries.add( CelExpr.ofStructEntry( mutableStructEntry.id(), @@ -209,14 +206,14 @@ private static CelStruct fromMutableStructToCelStruct(CelMutableStruct mutableCr } return CelStruct.newBuilder() - .setMessageName(mutableCreateStruct.messageName()) + .setMessageName(mutableStruct.messageName()) .addEntries(entries) .build(); } - private static CelMap fromMutableMapToCelMap(CelMutableMap mutableCreateMap) { + private static CelMap fromMutableMapToCelMap(CelMutableMap mutableMap) { List entries = new ArrayList<>(); - for (CelMutableMap.Entry mutableMapEntry : mutableCreateMap.entries()) { + for (CelMutableMap.Entry mutableMapEntry : mutableMap.entries()) { entries.add( CelExpr.ofMapEntry( mutableMapEntry.id(), diff --git a/common/src/main/java/dev/cel/common/ast/Expression.java b/common/src/main/java/dev/cel/common/ast/Expression.java index ed06af8b9..67d0304be 100644 --- a/common/src/main/java/dev/cel/common/ast/Expression.java +++ b/common/src/main/java/dev/cel/common/ast/Expression.java @@ -114,7 +114,7 @@ interface List { * The indices within the elements list which are marked as optional elements. * *

When an optional-typed value is present, the value it contains is included in the list. If - * the optional-typed value is absent, the list element is omitted from the CreateList result. + * the optional-typed value is absent, the list element is omitted from the list result. */ java.util.List optionalIndices(); } diff --git a/common/src/main/java/dev/cel/common/navigation/CelNavigableExprVisitor.java b/common/src/main/java/dev/cel/common/navigation/CelNavigableExprVisitor.java index b59acdd13..c8eb57d53 100644 --- a/common/src/main/java/dev/cel/common/navigation/CelNavigableExprVisitor.java +++ b/common/src/main/java/dev/cel/common/navigation/CelNavigableExprVisitor.java @@ -137,8 +137,8 @@ private void visit(T navigableExpr, Expression.Call call) { visitExprList(call.args(), navigableExpr); } - private void visit(T navigableExpr, List createList) { - visitExprList(createList.elements(), navigableExpr); + private void visit(T navigableExpr, List list) { + visitExprList(list.elements(), navigableExpr); } private void visit(T navigableExpr, Expression.Select selectExpr) { @@ -170,8 +170,8 @@ private void visitMap(T navigableExpr, Expression.Map> m } } - private void visitExprList(java.util.List createListExpr, T parent) { - for (E expr : createListExpr) { + private void visitExprList(java.util.List list, T parent) { + for (E expr : list) { visit(newNavigableChild(parent, expr)); } } diff --git a/common/src/main/java/dev/cel/common/navigation/ExprPropertyCalculator.java b/common/src/main/java/dev/cel/common/navigation/ExprPropertyCalculator.java index b35682ef3..c90c1f2f9 100644 --- a/common/src/main/java/dev/cel/common/navigation/ExprPropertyCalculator.java +++ b/common/src/main/java/dev/cel/common/navigation/ExprPropertyCalculator.java @@ -94,8 +94,8 @@ private ExprProperty visit(Expression.Call call) { return ExprProperty.merge(visitedArgument, visitedTarget); } - private ExprProperty visit(List createList) { - return visitExprList(createList.elements()); + private ExprProperty visit(List list) { + return visitExprList(list.elements()); } private ExprProperty visit(Expression.Select selectExpr) { @@ -129,9 +129,9 @@ private ExprProperty visitMap(Expression.Map> map) { return visitedProperty; } - private ExprProperty visitExprList(java.util.List createListExpr) { + private ExprProperty visitExprList(java.util.List list) { ExprProperty visitedProperty = ExprProperty.create(0, 0); - for (E expr : createListExpr) { + for (E expr : list) { visitedProperty = ExprProperty.merge(visitedProperty, visit(expr)); } return visitedProperty; diff --git a/common/src/test/java/dev/cel/common/ast/CelExprFormatterTest.java b/common/src/test/java/dev/cel/common/ast/CelExprFormatterTest.java index b77c23834..be0652982 100644 --- a/common/src/test/java/dev/cel/common/ast/CelExprFormatterTest.java +++ b/common/src/test/java/dev/cel/common/ast/CelExprFormatterTest.java @@ -136,7 +136,7 @@ public void call_member() throws Exception { } @Test - public void create_list() throws Exception { + public void list() throws Exception { CelCompiler celCompiler = CelCompilerFactory.standardCelCompilerBuilder() .addLibraries(CelOptionalLibrary.INSTANCE) @@ -170,7 +170,7 @@ public void create_list() throws Exception { } @Test - public void create_struct() throws Exception { + public void struct() throws Exception { CelCompiler celCompiler = CelCompilerFactory.standardCelCompilerBuilder() .setContainer("dev.cel.testing.testdata.proto3") @@ -220,7 +220,7 @@ public void create_struct() throws Exception { } @Test - public void create_map() throws Exception { + public void map() throws Exception { CelCompiler celCompiler = CelCompilerFactory.standardCelCompilerBuilder() .setContainer("dev.cel.testing.testdata.proto3") diff --git a/common/src/test/java/dev/cel/common/ast/CelExprTest.java b/common/src/test/java/dev/cel/common/ast/CelExprTest.java index ec4cceeab..9f0228008 100644 --- a/common/src/test/java/dev/cel/common/ast/CelExprTest.java +++ b/common/src/test/java/dev/cel/common/ast/CelExprTest.java @@ -66,10 +66,9 @@ private enum BuilderExprKindTestCase { .build()) .build(), Kind.SELECT), - CREATE_MAP(CelExpr.newBuilder().setMap(CelMap.newBuilder().build()).build(), Kind.MAP), - CREATE_LIST(CelExpr.newBuilder().setList(CelList.newBuilder().build()).build(), Kind.LIST), - CREATE_STRUCT( - CelExpr.newBuilder().setStruct(CelStruct.newBuilder().build()).build(), Kind.STRUCT), + MAP(CelExpr.newBuilder().setMap(CelMap.newBuilder().build()).build(), Kind.MAP), + LIST(CelExpr.newBuilder().setList(CelList.newBuilder().build()).build(), Kind.LIST), + STRUCT(CelExpr.newBuilder().setStruct(CelStruct.newBuilder().build()).build(), Kind.STRUCT), COMPREHENSION( CelExpr.newBuilder() .setComprehension( @@ -198,27 +197,27 @@ public void celExprBuilder_setSelect() { } @Test - public void celExprBuilder_setCreateList() { - CelList celCreateList = + public void celExprBuilder_setList() { + CelList celList = CelList.newBuilder().addElements(CelExpr.ofConstant(1, CelConstant.ofValue(2))).build(); - CelExpr celExpr = CelExpr.newBuilder().setList(celCreateList).build(); + CelExpr celExpr = CelExpr.newBuilder().setList(celList).build(); - assertThat(celExpr.list()).isEqualTo(celCreateList); - assertThat(celExpr.toBuilder().list()).isEqualTo(celCreateList); + assertThat(celExpr.list()).isEqualTo(celList); + assertThat(celExpr.toBuilder().list()).isEqualTo(celList); } @Test - public void createListBuilder_getArgs() { - CelList celCreateList = + public void listBuilder_getArgs() { + CelList celList = CelList.newBuilder().addElements(CelExpr.ofConstant(1, CelConstant.ofValue(2))).build(); - assertThat(celCreateList.toBuilder().getElements()) + assertThat(celList.toBuilder().getElements()) .containsExactly(CelExpr.ofConstant(1, CelConstant.ofValue(2))); } @Test - public void celExprBuilder_setCreateList_setElementByIndex() { - CelList celCreateList = + public void celExprBuilder_setList_setElementByIndex() { + CelList celList = CelList.newBuilder() .addElements( CelExpr.ofConstant(5, CelConstant.ofValue("hello")), @@ -228,7 +227,7 @@ public void celExprBuilder_setCreateList_setElementByIndex() { CelExpr celExpr = CelExpr.newBuilder() .setList( - celCreateList.toBuilder() + celList.toBuilder() .setElement(1, CelExpr.ofConstant(7, CelConstant.ofValue("world"))) .build()) .build(); @@ -243,8 +242,8 @@ public void celExprBuilder_setCreateList_setElementByIndex() { } @Test - public void celExprBuilder_setCreateStruct() { - CelStruct celCreateStruct = + public void celExprBuilder_setStruct() { + CelStruct celStruct = CelStruct.newBuilder() .addEntries( CelStruct.Entry.newBuilder() @@ -253,16 +252,16 @@ public void celExprBuilder_setCreateStruct() { .setFieldKey("field_key") .build()) .build(); - CelExpr celExpr = CelExpr.newBuilder().setStruct(celCreateStruct).build(); + CelExpr celExpr = CelExpr.newBuilder().setStruct(celStruct).build(); assertThat(celExpr.struct().entries().get(0).optionalEntry()).isFalse(); - assertThat(celExpr.struct()).isEqualTo(celCreateStruct); - assertThat(celExpr.toBuilder().struct()).isEqualTo(celCreateStruct); + assertThat(celExpr.struct()).isEqualTo(celStruct); + assertThat(celExpr.toBuilder().struct()).isEqualTo(celStruct); } @Test - public void createStructBuilder_getArgs() { - CelStruct celCreateStruct = + public void structBuilder_getArgs() { + CelStruct celStruct = CelStruct.newBuilder() .addEntries( CelStruct.Entry.newBuilder() @@ -272,7 +271,7 @@ public void createStructBuilder_getArgs() { .build()) .build(); - assertThat(celCreateStruct.toBuilder().getEntries()) + assertThat(celStruct.toBuilder().getEntries()) .containsExactly( CelStruct.Entry.newBuilder() .setId(1) @@ -282,8 +281,8 @@ public void createStructBuilder_getArgs() { } @Test - public void celExprBuilder_setCreateStruct_setEntryByIndex() { - CelStruct celCreateStruct = + public void celExprBuilder_setStruct_setEntryByIndex() { + CelStruct celStruct = CelStruct.newBuilder() .addEntries( CelStruct.Entry.newBuilder() @@ -302,7 +301,7 @@ public void celExprBuilder_setCreateStruct_setEntryByIndex() { CelExpr celExpr = CelExpr.newBuilder() .setStruct( - celCreateStruct.toBuilder() + celStruct.toBuilder() .setEntry( 1, CelStruct.Entry.newBuilder() @@ -460,7 +459,7 @@ public void getDefault_matchedKind_returnsUnderlyingExpression( } @Test - public void celCreateMapEntry_keyOrValueNotSet_throws() { + public void celMapEntry_keyOrValueNotSet_throws() { assertThrows(IllegalStateException.class, () -> CelMap.Entry.newBuilder().build()); assertThrows( IllegalStateException.class, @@ -471,7 +470,7 @@ public void celCreateMapEntry_keyOrValueNotSet_throws() { } @Test - public void celCreateMapEntry_default() { + public void celMapEntry_default() { CelMap.Entry entry = CelMap.Entry.newBuilder().setKey(CelExpr.ofNotSet(1)).setValue(CelExpr.ofNotSet(2)).build(); @@ -480,7 +479,7 @@ public void celCreateMapEntry_default() { } @Test - public void celCreateStructEntry_fieldKeyOrValueNotSet_throws() { + public void celStructEntry_fieldKeyOrValueNotSet_throws() { assertThrows(IllegalStateException.class, () -> CelStruct.Entry.newBuilder().build()); assertThrows( IllegalStateException.class, @@ -491,7 +490,7 @@ public void celCreateStructEntry_fieldKeyOrValueNotSet_throws() { } @Test - public void celCreateStructEntry_default() { + public void celStructEntry_default() { CelStruct.Entry entry = CelStruct.Entry.newBuilder().setFieldKey("fieldKey").setValue(CelExpr.ofNotSet(1)).build(); diff --git a/common/src/test/java/dev/cel/common/ast/CelExprVisitorTest.java b/common/src/test/java/dev/cel/common/ast/CelExprVisitorTest.java index 2ba8da806..cdb3de525 100644 --- a/common/src/test/java/dev/cel/common/ast/CelExprVisitorTest.java +++ b/common/src/test/java/dev/cel/common/ast/CelExprVisitorTest.java @@ -124,21 +124,21 @@ protected void visit(CelExpr expr, CelCall call) { } @Override - protected void visit(CelExpr expr, CelStruct createStruct) { - visitedReference.setStruct(createStruct); - super.visit(expr, createStruct); + protected void visit(CelExpr expr, CelStruct struct) { + visitedReference.setStruct(struct); + super.visit(expr, struct); } @Override - protected void visit(CelExpr expr, CelMap createMap) { - visitedReference.setMap(createMap); - super.visit(expr, createMap); + protected void visit(CelExpr expr, CelMap map) { + visitedReference.setMap(map); + super.visit(expr, map); } @Override - protected void visit(CelExpr expr, CelList createList) { - visitedReference.setList(createList); - super.visit(expr, createList); + protected void visit(CelExpr expr, CelList list) { + visitedReference.setList(list); + super.visit(expr, list); } @Override diff --git a/common/src/test/java/dev/cel/common/ast/CelMutableExprConverterTest.java b/common/src/test/java/dev/cel/common/ast/CelMutableExprConverterTest.java index 9fb2140a0..b8eb22e42 100644 --- a/common/src/test/java/dev/cel/common/ast/CelMutableExprConverterTest.java +++ b/common/src/test/java/dev/cel/common/ast/CelMutableExprConverterTest.java @@ -199,7 +199,7 @@ public void convertCelCall_toMutableCall() { } @Test - public void convertMutableCreateList_toCelList() { + public void convertMutableList_toCelList() { CelMutableExpr mutableExpr = CelMutableExpr.ofList( 1L, @@ -222,7 +222,7 @@ public void convertMutableCreateList_toCelList() { } @Test - public void convertCelList_toMutableCreateList() { + public void convertCelList_toMutableList() { CelExpr celExpr = CelExpr.ofList( 1L, @@ -245,7 +245,7 @@ public void convertCelList_toMutableCreateList() { } @Test - public void convertMutableCreateStruct_toCelStruct() { + public void convertMutableStruct_toCelStruct() { CelMutableExpr mutableExpr = CelMutableExpr.ofStruct( 8L, @@ -275,7 +275,7 @@ public void convertMutableCreateStruct_toCelStruct() { } @Test - public void convertCelStruct_toMutableCreateStruct() { + public void convertCelStruct_toMutableStruct() { CelExpr celExpr = CelExpr.ofStruct( 8L, @@ -305,7 +305,7 @@ public void convertCelStruct_toMutableCreateStruct() { } @Test - public void convertMutableCreateMap_toCelMap() { + public void convertMutableMap_toCelMap() { CelMutableExpr mutableExpr = CelMutableExpr.ofMap( 9L, @@ -332,7 +332,7 @@ public void convertMutableCreateMap_toCelMap() { } @Test - public void convertCelMap_toMutableCreateMap() { + public void convertCelMap_toMutableMap() { CelExpr celExpr = CelExpr.ofMap( 9L, diff --git a/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java b/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java index 906c3dab8..3ce4051db 100644 --- a/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java +++ b/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java @@ -351,20 +351,20 @@ public void ofList_withId() { } @Test - public void mutableCreateList_setElementAtIndex() { - CelMutableList createList = + public void mutableList_setElementAtIndex() { + CelMutableList list = CelMutableList.create(CelMutableExpr.ofConstant(CelConstant.ofValue("element1"))); - createList.setElement(0, CelMutableExpr.ofConstant(CelConstant.ofValue("hello"))); + list.setElement(0, CelMutableExpr.ofConstant(CelConstant.ofValue("hello"))); - assertThat(createList.elements()) + assertThat(list.elements()) .containsExactly(CelMutableExpr.ofConstant(CelConstant.ofValue("hello"))); - assertThat(createList.elements()).isInstanceOf(ArrayList.class); + assertThat(list.elements()).isInstanceOf(ArrayList.class); } @Test @SuppressWarnings("ReferenceEquality") // test only on iterating through elements - public void mutableCreateList_deepCopy() { + public void mutableList_deepCopy() { CelMutableExpr mutableExpr = CelMutableExpr.ofList( CelMutableList.create( @@ -421,8 +421,8 @@ public void ofStruct_withId() { } @Test - public void mutableCreateStruct_setEntryAtIndex() { - CelMutableStruct createStruct = + public void mutableStruct_setEntryAtIndex() { + CelMutableStruct struct = CelMutableStruct.create( "message", ImmutableList.of( @@ -435,23 +435,23 @@ public void mutableCreateStruct_setEntryAtIndex() { CelMutableExpr.ofConstant(CelConstant.ofValue("value2")), /* optionalEntry= */ true); - createStruct.setEntry(0, newEntry); + struct.setEntry(0, newEntry); - assertThat(createStruct.entries()).containsExactly(newEntry); + assertThat(struct.entries()).containsExactly(newEntry); } @Test - public void mutableCreateStructEntry_setters() { - CelMutableStruct.Entry createStructEntry = + public void mutableStructEntry_setters() { + CelMutableStruct.Entry structEntry = CelMutableStruct.Entry.create( 1L, "field", CelMutableExpr.ofConstant(CelConstant.ofValue("value"))); - createStructEntry.setId(2L); - createStructEntry.setFieldKey("field2"); - createStructEntry.setValue(CelMutableExpr.ofConstant(CelConstant.ofValue("value2"))); - createStructEntry.setOptionalEntry(true); + structEntry.setId(2L); + structEntry.setFieldKey("field2"); + structEntry.setValue(CelMutableExpr.ofConstant(CelConstant.ofValue("value2"))); + structEntry.setOptionalEntry(true); - assertThat(createStructEntry) + assertThat(structEntry) .isEqualTo( CelMutableStruct.Entry.create( 2L, "field2", CelMutableExpr.ofConstant(CelConstant.ofValue("value2")), true)); @@ -459,7 +459,7 @@ public void mutableCreateStructEntry_setters() { @Test @SuppressWarnings("ReferenceEquality") // test only on iterating through elements - public void mutableCreateStruct_deepCopy() { + public void mutableStruct_deepCopy() { CelMutableExpr mutableExpr = CelMutableExpr.ofStruct( 8L, @@ -524,8 +524,8 @@ public void ofMap_withId() { } @Test - public void mutableCreateMap_setEntryAtIndex() { - CelMutableMap createMap = + public void mutableMap_setEntryAtIndex() { + CelMutableMap map = CelMutableMap.create( ImmutableList.of( CelMutableMap.Entry.create( @@ -539,25 +539,25 @@ public void mutableCreateMap_setEntryAtIndex() { CelMutableExpr.ofConstant(CelConstant.ofValue("value2")), /* optionalEntry= */ true); - createMap.setEntry(0, newEntry); + map.setEntry(0, newEntry); - assertThat(createMap.entries()).containsExactly(newEntry); + assertThat(map.entries()).containsExactly(newEntry); } @Test - public void mutableCreateMapEntry_setters() { - CelMutableMap.Entry createMapEntry = + public void mutableMapEntry_setters() { + CelMutableMap.Entry mapEntry = CelMutableMap.Entry.create( 1L, CelMutableExpr.ofConstant(CelConstant.ofValue("key")), CelMutableExpr.ofConstant(CelConstant.ofValue("value"))); - createMapEntry.setId(2L); - createMapEntry.setKey(CelMutableExpr.ofConstant(CelConstant.ofValue("key2"))); - createMapEntry.setValue(CelMutableExpr.ofConstant(CelConstant.ofValue("value2"))); - createMapEntry.setOptionalEntry(true); + mapEntry.setId(2L); + mapEntry.setKey(CelMutableExpr.ofConstant(CelConstant.ofValue("key2"))); + mapEntry.setValue(CelMutableExpr.ofConstant(CelConstant.ofValue("value2"))); + mapEntry.setOptionalEntry(true); - assertThat(createMapEntry) + assertThat(mapEntry) .isEqualTo( CelMutableMap.Entry.create( 2L, @@ -568,7 +568,7 @@ public void mutableCreateMapEntry_setters() { @Test @SuppressWarnings("ReferenceEquality") // test only on iterating through elements - public void mutableCreateMap_deepCopy() { + public void mutableMap_deepCopy() { CelMutableExpr mutableExpr = CelMutableExpr.ofMap( 9L, @@ -836,9 +836,9 @@ private enum MutableExprKindTestCase { IDENT(CelMutableExpr.ofIdent("test")), SELECT(CelMutableExpr.ofSelect(CelMutableSelect.create(CelMutableExpr.ofNotSet(), "field"))), CALL(CelMutableExpr.ofCall(CelMutableCall.create("call"))), - CREATE_LIST(CelMutableExpr.ofList(CelMutableList.create())), - CREATE_STRUCT(CelMutableExpr.ofStruct(CelMutableStruct.create("message", ImmutableList.of()))), - CREATE_MAP(CelMutableExpr.ofMap(CelMutableMap.create(ImmutableList.of()))), + LIST(CelMutableExpr.ofList(CelMutableList.create())), + STRUCT(CelMutableExpr.ofStruct(CelMutableStruct.create("message", ImmutableList.of()))), + MAP(CelMutableExpr.ofMap(CelMutableMap.create(ImmutableList.of()))), COMPREHENSION( CelMutableExpr.ofComprehension( 10L, @@ -909,14 +909,14 @@ private enum HashCodeTestCase { "function", CelMutableExpr.ofConstant(CelConstant.ofValue("arg")))), -1735261193), - CREATE_LIST( + LIST( CelMutableExpr.ofList( 6L, CelMutableList.create( CelMutableExpr.ofConstant(CelConstant.ofValue("element1")), CelMutableExpr.ofConstant(CelConstant.ofValue("element2")))), 165341403), - CREATE_STRUCT( + STRUCT( CelMutableExpr.ofStruct( 7L, CelMutableStruct.create( @@ -928,7 +928,7 @@ private enum HashCodeTestCase { CelMutableExpr.ofConstant(CelConstant.ofValue("value")), /* optionalEntry= */ true)))), 2064611987), - CREATE_MAP( + MAP( CelMutableExpr.ofMap( 8L, CelMutableMap.create( diff --git a/common/src/test/java/dev/cel/common/navigation/CelNavigableExprVisitorTest.java b/common/src/test/java/dev/cel/common/navigation/CelNavigableExprVisitorTest.java index c22471c05..101fb9fdb 100644 --- a/common/src/test/java/dev/cel/common/navigation/CelNavigableExprVisitorTest.java +++ b/common/src/test/java/dev/cel/common/navigation/CelNavigableExprVisitorTest.java @@ -599,7 +599,7 @@ public void messageConstruction_allNodesReturned() throws Exception { } @Test - public void messageConstruction_filterCreateStruct_allNodesReturned() throws Exception { + public void messageConstruction_filterStruct_allNodesReturned() throws Exception { CelCompiler compiler = CelCompilerFactory.standardCelCompilerBuilder() .addMessageTypes(TestAllTypes.getDescriptor()) @@ -708,7 +708,7 @@ public void mapConstruction_allNodesReturned() throws Exception { } @Test - public void mapConstruction_filterCreateMap_allNodesReturned() throws Exception { + public void mapConstruction_filterMap_allNodesReturned() throws Exception { CelCompiler compiler = CelCompilerFactory.standardCelCompilerBuilder().build(); CelAbstractSyntaxTree ast = compiler.compile("{'key': 2}").getAst(); CelNavigableAst navigableAst = CelNavigableAst.fromAst(ast); @@ -1301,7 +1301,7 @@ public void callExpr_postOrder_maxIdsSet() throws Exception { } @Test - public void createList_children_heightSet(@TestParameter TraversalOrder traversalOrder) + public void list_children_heightSet(@TestParameter TraversalOrder traversalOrder) throws Exception { CelCompiler compiler = CelCompilerFactory.standardCelCompilerBuilder().addVar("a", SimpleType.INT).build(); @@ -1319,7 +1319,7 @@ public void createList_children_heightSet(@TestParameter TraversalOrder traversa } @Test - public void createList_children_maxIdsSet(@TestParameter TraversalOrder traversalOrder) + public void list_children_maxIdsSet(@TestParameter TraversalOrder traversalOrder) throws Exception { CelCompiler compiler = CelCompilerFactory.standardCelCompilerBuilder().addVar("a", SimpleType.INT).build(); diff --git a/optimizer/src/main/java/dev/cel/optimizer/MutableExprVisitor.java b/optimizer/src/main/java/dev/cel/optimizer/MutableExprVisitor.java index 6d37246fc..7a04a3c3a 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/MutableExprVisitor.java +++ b/optimizer/src/main/java/dev/cel/optimizer/MutableExprVisitor.java @@ -107,8 +107,8 @@ private CelMutableExpr visit(CelMutableExpr expr, CelMutableCall call) { } @CanIgnoreReturnValue - private CelMutableExpr visit(CelMutableExpr expr, CelMutableStruct createStruct) { - List entries = createStruct.entries(); + private CelMutableExpr visit(CelMutableExpr expr, CelMutableStruct struct) { + List entries = struct.entries(); for (CelMutableStruct.Entry entry : entries) { entry.setId(celExprIdGenerator.generate(entry.id())); entry.setValue(visit(entry.value())); @@ -118,8 +118,8 @@ private CelMutableExpr visit(CelMutableExpr expr, CelMutableStruct createStruct) } @CanIgnoreReturnValue - private CelMutableExpr visit(CelMutableExpr expr, CelMutableMap createMap) { - List entriesBuilders = createMap.entries(); + private CelMutableExpr visit(CelMutableExpr expr, CelMutableMap map) { + List entriesBuilders = map.entries(); for (CelMutableMap.Entry entry : entriesBuilders) { entry.setId(celExprIdGenerator.generate(entry.id())); entry.setKey(visit(entry.key())); @@ -130,11 +130,11 @@ private CelMutableExpr visit(CelMutableExpr expr, CelMutableMap createMap) { } @CanIgnoreReturnValue - private CelMutableExpr visit(CelMutableExpr expr, CelMutableList createList) { - List elementsBuilders = createList.elements(); + private CelMutableExpr visit(CelMutableExpr expr, CelMutableList list) { + List elementsBuilders = list.elements(); for (int i = 0; i < elementsBuilders.size(); i++) { CelMutableExpr elem = elementsBuilders.get(i); - createList.setElement(i, visit(elem)); + list.setElement(i, visit(elem)); } return expr; diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java b/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java index 485ded5e4..150f614df 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java @@ -438,18 +438,18 @@ private CelMutableAst pruneOptionalElements(CelMutableAst ast) { } private CelMutableAst pruneOptionalListElements(CelMutableAst mutableAst, CelMutableExpr expr) { - CelMutableList createList = expr.list(); - if (createList.optionalIndices().isEmpty()) { + CelMutableList list = expr.list(); + if (list.optionalIndices().isEmpty()) { return mutableAst; } - HashSet optionalIndices = new HashSet<>(createList.optionalIndices()); + HashSet optionalIndices = new HashSet<>(list.optionalIndices()); ImmutableList.Builder updatedElemBuilder = new ImmutableList.Builder<>(); ImmutableList.Builder updatedIndicesBuilder = new ImmutableList.Builder<>(); int newOptIndex = -1; - for (int i = 0; i < createList.elements().size(); i++) { + for (int i = 0; i < list.elements().size(); i++) { newOptIndex++; - CelMutableExpr element = createList.elements().get(i); + CelMutableExpr element = list.elements().get(i); if (!optionalIndices.contains(i)) { updatedElemBuilder.add(element); continue; @@ -483,10 +483,10 @@ private CelMutableAst pruneOptionalListElements(CelMutableAst mutableAst, CelMut } private CelMutableAst pruneOptionalMapElements(CelMutableAst ast, CelMutableExpr expr) { - CelMutableMap createMap = expr.map(); + CelMutableMap map = expr.map(); ImmutableList.Builder updatedEntryBuilder = new ImmutableList.Builder<>(); boolean modified = false; - for (CelMutableMap.Entry entry : createMap.entries()) { + for (CelMutableMap.Entry entry : map.entries()) { CelMutableExpr key = entry.key(); Kind keyKind = key.getKind(); CelMutableExpr value = entry.value(); @@ -526,11 +526,11 @@ private CelMutableAst pruneOptionalMapElements(CelMutableAst ast, CelMutableExpr } private CelMutableAst pruneOptionalStructElements(CelMutableAst ast, CelMutableExpr expr) { - CelMutableStruct createStruct = expr.struct(); + CelMutableStruct struct = expr.struct(); ImmutableList.Builder updatedEntryBuilder = new ImmutableList.Builder<>(); boolean modified = false; - for (CelMutableStruct.Entry entry : createStruct.entries()) { + for (CelMutableStruct.Entry entry : struct.entries()) { CelMutableExpr value = entry.value(); Kind valueKind = value.getKind(); if (!entry.optionalEntry() || !valueKind.equals(Kind.CALL)) { @@ -562,7 +562,7 @@ private CelMutableAst pruneOptionalStructElements(CelMutableAst ast, CelMutableE return astMutator.replaceSubtree( ast, CelMutableExpr.ofStruct( - CelMutableStruct.create(createStruct.messageName(), updatedEntryBuilder.build())), + CelMutableStruct.create(struct.messageName(), updatedEntryBuilder.build())), expr.id()); } diff --git a/parser/src/main/java/dev/cel/parser/CelUnparserVisitor.java b/parser/src/main/java/dev/cel/parser/CelUnparserVisitor.java index b43779ffa..5f2f05e4d 100644 --- a/parser/src/main/java/dev/cel/parser/CelUnparserVisitor.java +++ b/parser/src/main/java/dev/cel/parser/CelUnparserVisitor.java @@ -163,31 +163,31 @@ protected void visit(CelExpr expr, CelCall call) { } @Override - protected void visit(CelExpr expr, CelList createList) { + protected void visit(CelExpr expr, CelList list) { stringBuilder.append(LEFT_BRACKET); - HashSet optionalIndices = new HashSet<>(createList.optionalIndices()); - for (int i = 0; i < createList.elements().size(); i++) { + HashSet optionalIndices = new HashSet<>(list.optionalIndices()); + for (int i = 0; i < list.elements().size(); i++) { if (i > 0) { stringBuilder.append(COMMA).append(SPACE); } if (optionalIndices.contains(i)) { stringBuilder.append(QUESTION_MARK); } - visit(createList.elements().get(i)); + visit(list.elements().get(i)); } stringBuilder.append(RIGHT_BRACKET); } @Override - protected void visit(CelExpr expr, CelStruct createStruct) { - stringBuilder.append(createStruct.messageName()); + protected void visit(CelExpr expr, CelStruct struct) { + stringBuilder.append(struct.messageName()); stringBuilder.append(LEFT_BRACE); - for (int i = 0; i < createStruct.entries().size(); i++) { + for (int i = 0; i < struct.entries().size(); i++) { if (i > 0) { stringBuilder.append(COMMA).append(SPACE); } - CelStruct.Entry e = createStruct.entries().get(i); + CelStruct.Entry e = struct.entries().get(i); if (e.optionalEntry()) { stringBuilder.append(QUESTION_MARK); } @@ -199,14 +199,14 @@ protected void visit(CelExpr expr, CelStruct createStruct) { } @Override - protected void visit(CelExpr expr, CelMap createMap) { + protected void visit(CelExpr expr, CelMap map) { stringBuilder.append(LEFT_BRACE); - for (int i = 0; i < createMap.entries().size(); i++) { + for (int i = 0; i < map.entries().size(); i++) { if (i > 0) { stringBuilder.append(COMMA).append(SPACE); } - CelMap.Entry e = createMap.entries().get(i); + CelMap.Entry e = map.entries().get(i); if (e.optionalEntry()) { stringBuilder.append(QUESTION_MARK); } diff --git a/runtime/src/test/java/dev/cel/runtime/CelRuntimeTest.java b/runtime/src/test/java/dev/cel/runtime/CelRuntimeTest.java index 074405c20..fd4de8179 100644 --- a/runtime/src/test/java/dev/cel/runtime/CelRuntimeTest.java +++ b/runtime/src/test/java/dev/cel/runtime/CelRuntimeTest.java @@ -289,7 +289,7 @@ public void trace_select() throws Exception { } @Test - public void trace_createStruct() throws Exception { + public void trace_struct() throws Exception { CelEvaluationListener listener = (expr, res) -> { assertThat(res).isEqualTo(TestAllTypes.getDefaultInstance()); @@ -309,7 +309,7 @@ public void trace_createStruct() throws Exception { @Test @SuppressWarnings("unchecked") // Test only - public void trace_createList() throws Exception { + public void trace_list() throws Exception { CelEvaluationListener listener = (expr, res) -> { if (expr.exprKind().getKind().equals(Kind.LIST)) { @@ -327,7 +327,7 @@ public void trace_createList() throws Exception { @Test @SuppressWarnings("unchecked") // Test only - public void trace_createMap() throws Exception { + public void trace_map() throws Exception { CelEvaluationListener listener = (expr, res) -> { if (expr.exprKind().getKind().equals(Kind.MAP)) { From 62b0d22224e0016be5869686a8b1dbc415f07ec5 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Wed, 8 May 2024 10:32:02 -0700 Subject: [PATCH 118/486] Retain source description post AST optimization PiperOrigin-RevId: 631847830 --- .../java/dev/cel/common/CelMutableSource.java | 23 +++++++++++++++---- .../java/dev/cel/optimizer/AstMutator.java | 12 ++++++++-- .../dev/cel/optimizer/AstMutatorTest.java | 4 ++-- 3 files changed, 31 insertions(+), 8 deletions(-) diff --git a/common/src/main/java/dev/cel/common/CelMutableSource.java b/common/src/main/java/dev/cel/common/CelMutableSource.java index 250963b9a..459042c6d 100644 --- a/common/src/main/java/dev/cel/common/CelMutableSource.java +++ b/common/src/main/java/dev/cel/common/CelMutableSource.java @@ -35,8 +35,9 @@ */ public final class CelMutableSource { - final Map macroCalls; - final Set extensions; + private String description; + private final Map macroCalls; + private final Set extensions; @CanIgnoreReturnValue public CelMutableSource addMacroCalls(long exprId, CelMutableExpr expr) { @@ -57,6 +58,12 @@ public CelMutableSource addAllExtensions(Collection extensi return this; } + @CanIgnoreReturnValue + public CelMutableSource setDescription(String description) { + this.description = checkNotNull(description); + return this; + } + @CanIgnoreReturnValue public CelMutableSource clearMacroCall(long exprId) { this.macroCalls.remove(exprId); @@ -69,6 +76,10 @@ public CelMutableSource clearMacroCalls() { return this; } + public String getDescription() { + return description; + } + public Map getMacroCalls() { return macroCalls; } @@ -79,6 +90,7 @@ public Set getExtensions() { public CelSource toCelSource() { return CelSource.newBuilder() + .setDescription(description) .addAllExtensions(extensions) .addAllMacroCalls( macroCalls.entrySet().stream() @@ -89,11 +101,12 @@ public CelSource toCelSource() { } public static CelMutableSource newInstance() { - return new CelMutableSource(new HashMap<>(), new HashSet<>()); + return new CelMutableSource("", new HashMap<>(), new HashSet<>()); } public static CelMutableSource fromCelSource(CelSource source) { return new CelMutableSource( + source.getDescription(), source.getMacroCalls().entrySet().stream() .collect( Collectors.toMap( @@ -107,7 +120,9 @@ public static CelMutableSource fromCelSource(CelSource source) { source.getExtensions()); } - CelMutableSource(Map macroCalls, Set extensions) { + CelMutableSource( + String description, Map macroCalls, Set extensions) { + this.description = checkNotNull(description); this.macroCalls = checkNotNull(macroCalls); this.extensions = checkNotNull(extensions); } diff --git a/optimizer/src/main/java/dev/cel/optimizer/AstMutator.java b/optimizer/src/main/java/dev/cel/optimizer/AstMutator.java index 92f056e79..8d35efc2c 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/AstMutator.java +++ b/optimizer/src/main/java/dev/cel/optimizer/AstMutator.java @@ -20,6 +20,7 @@ import com.google.auto.value.AutoValue; import com.google.common.base.Preconditions; +import com.google.common.base.Strings; import com.google.common.collect.ImmutableMap; import com.google.errorprone.annotations.Immutable; import dev.cel.common.CelAbstractSyntaxTree; @@ -418,7 +419,8 @@ public CelMutableAst replaceSubtree( CelMutableExpr mutatedRoot = mutateExpr(stableIdGenerator::renumberId, ast.expr(), newAst.expr(), exprIdToReplace); - CelMutableSource newAstSource = CelMutableSource.newInstance(); + CelMutableSource newAstSource = + CelMutableSource.newInstance().setDescription(ast.source().getDescription()); if (!ast.source().getMacroCalls().isEmpty()) { newAstSource = combine(newAstSource, ast.source()); } @@ -570,6 +572,10 @@ private CelMutableExpr newBindMacroSourceExpr( private static CelMutableSource combine( CelMutableSource celSource1, CelMutableSource celSource2) { return CelMutableSource.newInstance() + .setDescription( + Strings.isNullOrEmpty(celSource1.getDescription()) + ? celSource2.getDescription() + : celSource1.getDescription()) .addAllExtensions(celSource1.getExtensions()) .addAllExtensions(celSource2.getExtensions()) .addAllMacroCalls(celSource1.getMacroCalls()) @@ -635,7 +641,9 @@ private CelMutableSource normalizeMacroSource( })); CelMutableSource newMacroSource = - CelMutableSource.newInstance().addAllExtensions(source.getExtensions()); + CelMutableSource.newInstance() + .setDescription(source.getDescription()) + .addAllExtensions(source.getExtensions()); // Update the macro call IDs and their call references for (Entry existingMacroCall : source.getMacroCalls().entrySet()) { long macroId = existingMacroCall.getKey(); diff --git a/optimizer/src/test/java/dev/cel/optimizer/AstMutatorTest.java b/optimizer/src/test/java/dev/cel/optimizer/AstMutatorTest.java index 3cc84ea95..8d56c2a3a 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/AstMutatorTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/AstMutatorTest.java @@ -109,11 +109,11 @@ public void astMutator_nonMacro_sourceCleared() throws Exception { .replaceSubtree(mutableAst, newBooleanConst, mutableAst.expr().id()) .toParsedAst(); - assertThat(mutatedAst.getSource().getDescription()).isEmpty(); assertThat(mutatedAst.getSource().getLineOffsets()).isEmpty(); assertThat(mutatedAst.getSource().getPositionsMap()).isEmpty(); assertThat(mutatedAst.getSource().getExtensions()).isEmpty(); assertThat(mutatedAst.getSource().getMacroCalls()).isEmpty(); + assertThat(mutatedAst.getSource().getDescription()).isEqualTo(ast.getSource().getDescription()); } @Test @@ -125,11 +125,11 @@ public void astMutator_macro_sourceMacroCallsPopulated() throws Exception { CelAbstractSyntaxTree mutatedAst = AST_MUTATOR.replaceSubtree(mutableAst, newBooleanConst, 1).toParsedAst(); // no_op - assertThat(mutatedAst.getSource().getDescription()).isEmpty(); assertThat(mutatedAst.getSource().getLineOffsets()).isEmpty(); assertThat(mutatedAst.getSource().getPositionsMap()).isEmpty(); assertThat(mutatedAst.getSource().getExtensions()).isEmpty(); assertThat(mutatedAst.getSource().getMacroCalls()).isNotEmpty(); + assertThat(mutatedAst.getSource().getDescription()).isEqualTo(ast.getSource().getDescription()); } @Test From 447776fcdaf84bbed7630f887c67c1436e7c5d98 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Wed, 8 May 2024 10:54:07 -0700 Subject: [PATCH 119/486] Fix extensions README.md formatting PiperOrigin-RevId: 631855511 --- .../main/java/dev/cel/extensions/README.md | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/extensions/src/main/java/dev/cel/extensions/README.md b/extensions/src/main/java/dev/cel/extensions/README.md index 473ba634b..1c78f0364 100644 --- a/extensions/src/main/java/dev/cel/extensions/README.md +++ b/extensions/src/main/java/dev/cel/extensions/README.md @@ -140,13 +140,13 @@ zero-based. Returns the character at the given position. If the position is negative, or greater than the length of the string, the function will produce an error. -.charAt() -> + .charAt() -> Examples: -'hello'.charAt(4) // return 'o' -'hello'.charAt(5) // return '' -'hello'.charAt(-1) // error + 'hello'.charAt(4) // return 'o' + 'hello'.charAt(5) // return '' + 'hello'.charAt(-1) // error ### IndexOf @@ -156,17 +156,17 @@ not found the function returns -1. The function also accepts an optional offset from which to begin the substring search. If the substring is the empty string, the index where the search starts is returned (zero or custom). -.indexOf() -> -.indexOf(, ) -> + .indexOf() -> + .indexOf(, ) -> Examples: -'hello mellow'.indexOf('') // returns 0 -'hello mellow'.indexOf('ello') // returns 1 -'hello mellow'.indexOf('jello') // returns -1 -'hello mellow'.indexOf('', 2) // returns 2 -'hello mellow'.indexOf('ello', 2) // returns 7 -'hello mellow'.indexOf('ello', 20) // error + 'hello mellow'.indexOf('') // returns 0 + 'hello mellow'.indexOf('ello') // returns 1 + 'hello mellow'.indexOf('jello') // returns -1 + 'hello mellow'.indexOf('', 2) // returns 2 + 'hello mellow'.indexOf('ello', 2) // returns 7 + 'hello mellow'.indexOf('ello', 20) // error ### Join @@ -174,15 +174,15 @@ Returns a new string where the elements of string list are concatenated. The function also accepts an optional separator which is placed between elements in the resulting string. ->.join() -> ->.join() -> + >.join() -> + >.join() -> Examples: -['hello', 'mellow'].join() // returns 'hellomellow' -['hello', 'mellow'].join(' ') // returns 'hello mellow' -[].join() // returns '' -[].join('/') // returns '' + ['hello', 'mellow'].join() // returns 'hellomellow' + ['hello', 'mellow'].join(' ') // returns 'hello mellow' + [].join() // returns '' + [].join('/') // returns '' ### LastIndexOf @@ -304,8 +304,8 @@ ASCII range. Examples: - 'TacoCat'.upperAscii() // returns 'TACOCAT' - 'TacoCÆt Xii'.upperAscii() // returns 'TACOCÆT XII' + 'TacoCat'.upperAscii() // returns 'TACOCAT' + 'TacoCÆt Xii'.upperAscii() // returns 'TACOCÆT XII' ## Encoders From 606a2b213debe66356d81c906fce094b17219f98 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Thu, 9 May 2024 10:41:02 -0700 Subject: [PATCH 120/486] Add code for Exercise 8 Codelabs PiperOrigin-RevId: 632199199 --- codelab/src/main/codelab/BUILD.bazel | 11 ++ codelab/src/main/codelab/Exercise8.java | 76 +++++++++ .../src/main/codelab/solutions/BUILD.bazel | 11 ++ .../src/main/codelab/solutions/Exercise8.java | 106 +++++++++++++ codelab/src/test/codelab/BUILD.bazel | 19 +++ codelab/src/test/codelab/Exercise8Test.java | 147 ++++++++++++++++++ .../src/test/codelab/solutions/BUILD.bazel | 18 +++ .../test/codelab/solutions/Exercise8Test.java | 147 ++++++++++++++++++ 8 files changed, 535 insertions(+) create mode 100644 codelab/src/main/codelab/Exercise8.java create mode 100644 codelab/src/main/codelab/solutions/Exercise8.java create mode 100644 codelab/src/test/codelab/Exercise8Test.java create mode 100644 codelab/src/test/codelab/solutions/Exercise8Test.java diff --git a/codelab/src/main/codelab/BUILD.bazel b/codelab/src/main/codelab/BUILD.bazel index c5ede3a1a..117d1ccd8 100644 --- a/codelab/src/main/codelab/BUILD.bazel +++ b/codelab/src/main/codelab/BUILD.bazel @@ -16,8 +16,19 @@ java_library( "//common/types:type_providers", # unuseddeps: keep "//compiler", # unuseddeps: keep "//compiler:compiler_builder", # unuseddeps: keep + "//optimizer", # unuseddeps: keep + "//optimizer:optimization_exception", # unuseddeps: keep + "//optimizer:optimizer_builder", # unuseddeps: keep + "//optimizer/optimizers:common_subexpression_elimination", # unuseddeps: keep + "//optimizer/optimizers:constant_folding", # unuseddeps: keep "//parser:macro", # unuseddeps: keep "//runtime", # unuseddeps: keep + "//validator", # unuseddeps: keep + "//validator:validator_builder", # unuseddeps: keep + "//validator/validators:duration", # unuseddeps: keep + "//validator/validators:homogeneous_literal", # unuseddeps: keep + "//validator/validators:regex", # unuseddeps: keep + "//validator/validators:timestamp", # unuseddeps: keep "@maven//:com_google_api_grpc_proto_google_common_protos", # unuseddeps: keep "@maven//:com_google_guava_guava", # unuseddeps: keep "@maven//:com_google_protobuf_protobuf_java", # unuseddeps: keep diff --git a/codelab/src/main/codelab/Exercise8.java b/codelab/src/main/codelab/Exercise8.java new file mode 100644 index 000000000..d38854687 --- /dev/null +++ b/codelab/src/main/codelab/Exercise8.java @@ -0,0 +1,76 @@ +// Copyright 2024 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 codelab; + +import com.google.rpc.context.AttributeContext; +import dev.cel.common.CelAbstractSyntaxTree; +import dev.cel.common.CelValidationException; +import dev.cel.common.CelValidationResult; +import dev.cel.common.types.SimpleType; +import dev.cel.common.types.StructTypeReference; +import dev.cel.compiler.CelCompiler; +import dev.cel.compiler.CelCompilerFactory; +import dev.cel.runtime.CelEvaluationException; +import dev.cel.runtime.CelRuntime; +import dev.cel.runtime.CelRuntimeFactory; +import java.util.Map; + +/** + * Exercise8 demonstrates how to leverage canonical CEL validators to perform advanced validations + * on an AST and CEL optimizers to improve evaluation efficiency. + */ +final class Exercise8 { + private static final CelCompiler CEL_COMPILER = + CelCompilerFactory.standardCelCompilerBuilder() + .addVar("x", SimpleType.INT) + .addVar( + "request", StructTypeReference.create("google.rpc.context.AttributeContext.Request")) + .addMessageTypes(AttributeContext.Request.getDescriptor()) + .build(); + private static final CelRuntime CEL_RUNTIME = + CelRuntimeFactory.standardCelRuntimeBuilder() + .addMessageTypes(AttributeContext.Request.getDescriptor()) + .build(); + + // Statically declare the validator and optimizer here. + + /** + * Compiles the input expression. + * + * @throws CelValidationException If the expression contains parsing or type-checking errors. + */ + CelAbstractSyntaxTree compile(String expression) throws CelValidationException { + return CEL_COMPILER.compile(expression).getAst(); + } + + /** Validates a type-checked AST. */ + @SuppressWarnings("DoNotCallSuggester") + CelValidationResult validate(CelAbstractSyntaxTree checkedAst) { + throw new UnsupportedOperationException("To be implemented"); + } + + /** Optimizes a type-checked AST. */ + @SuppressWarnings("DoNotCallSuggester") + CelAbstractSyntaxTree optimize(CelAbstractSyntaxTree checkedAst) { + throw new UnsupportedOperationException("To be implemented"); + } + + /** Evaluates the compiled AST with the user provided parameter values. */ + Object eval(CelAbstractSyntaxTree ast, Map parameterValues) + throws CelEvaluationException { + CelRuntime.Program program = CEL_RUNTIME.createProgram(ast); + return program.eval(parameterValues); + } +} diff --git a/codelab/src/main/codelab/solutions/BUILD.bazel b/codelab/src/main/codelab/solutions/BUILD.bazel index 40b18fca1..ec29a3e7a 100644 --- a/codelab/src/main/codelab/solutions/BUILD.bazel +++ b/codelab/src/main/codelab/solutions/BUILD.bazel @@ -16,8 +16,19 @@ java_library( "//common/types:type_providers", "//compiler", "//compiler:compiler_builder", + "//optimizer", + "//optimizer:optimization_exception", + "//optimizer:optimizer_builder", + "//optimizer/optimizers:common_subexpression_elimination", + "//optimizer/optimizers:constant_folding", "//parser:macro", "//runtime", + "//validator", + "//validator:validator_builder", + "//validator/validators:duration", + "//validator/validators:homogeneous_literal", + "//validator/validators:regex", + "//validator/validators:timestamp", "@maven//:com_google_api_grpc_proto_google_common_protos", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", diff --git a/codelab/src/main/codelab/solutions/Exercise8.java b/codelab/src/main/codelab/solutions/Exercise8.java new file mode 100644 index 000000000..161089354 --- /dev/null +++ b/codelab/src/main/codelab/solutions/Exercise8.java @@ -0,0 +1,106 @@ +// Copyright 2024 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 codelab.solutions; + +import com.google.rpc.context.AttributeContext; +import dev.cel.common.CelAbstractSyntaxTree; +import dev.cel.common.CelValidationException; +import dev.cel.common.CelValidationResult; +import dev.cel.common.types.SimpleType; +import dev.cel.common.types.StructTypeReference; +import dev.cel.compiler.CelCompiler; +import dev.cel.compiler.CelCompilerFactory; +import dev.cel.optimizer.CelOptimizationException; +import dev.cel.optimizer.CelOptimizer; +import dev.cel.optimizer.CelOptimizerFactory; +import dev.cel.optimizer.optimizers.ConstantFoldingOptimizer; +import dev.cel.optimizer.optimizers.SubexpressionOptimizer; +import dev.cel.optimizer.optimizers.SubexpressionOptimizer.SubexpressionOptimizerOptions; +import dev.cel.runtime.CelEvaluationException; +import dev.cel.runtime.CelRuntime; +import dev.cel.runtime.CelRuntimeFactory; +import dev.cel.validator.CelValidator; +import dev.cel.validator.CelValidatorFactory; +import dev.cel.validator.validators.DurationLiteralValidator; +import dev.cel.validator.validators.HomogeneousLiteralValidator; +import dev.cel.validator.validators.RegexLiteralValidator; +import dev.cel.validator.validators.TimestampLiteralValidator; +import java.util.Map; + +/** + * Exercise8 demonstrates how to leverage canonical CEL validators to perform advanced validations + * on an AST and CEL optimizers to improve evaluation efficiency. + */ +final class Exercise8 { + private static final CelCompiler CEL_COMPILER = + CelCompilerFactory.standardCelCompilerBuilder() + .addVar("x", SimpleType.INT) + .addVar( + "request", StructTypeReference.create("google.rpc.context.AttributeContext.Request")) + .addMessageTypes(AttributeContext.Request.getDescriptor()) + .build(); + private static final CelRuntime CEL_RUNTIME = + CelRuntimeFactory.standardCelRuntimeBuilder() + .addMessageTypes(AttributeContext.Request.getDescriptor()) + .build(); + + // Just like the compiler and runtime, the validator and optimizer can be statically + // initialized as their instances are immutable. + private static final CelValidator CEL_VALIDATOR = + CelValidatorFactory.standardCelValidatorBuilder(CEL_COMPILER, CEL_RUNTIME) + .addAstValidators( + TimestampLiteralValidator.INSTANCE, + DurationLiteralValidator.INSTANCE, + RegexLiteralValidator.INSTANCE, + HomogeneousLiteralValidator.newInstance()) + .build(); + private static final CelOptimizer CEL_OPTIMIZER = + CelOptimizerFactory.standardCelOptimizerBuilder(CEL_COMPILER, CEL_RUNTIME) + .addAstOptimizers( + ConstantFoldingOptimizer.getInstance(), + SubexpressionOptimizer.newInstance( + SubexpressionOptimizerOptions.newBuilder().enableCelBlock(true).build())) + .build(); + + /** + * Compiles the input expression. + * + * @throws CelValidationException If the expression contains parsing or type-checking errors. + */ + CelAbstractSyntaxTree compile(String expression) throws CelValidationException { + return CEL_COMPILER.compile(expression).getAst(); + } + + /** Validates a type-checked AST. */ + CelValidationResult validate(CelAbstractSyntaxTree checkedAst) { + return CEL_VALIDATOR.validate(checkedAst); + } + + /** + * Optimizes a type-checked AST. + * + * @throws CelOptimizationException If the optimization fails. + */ + CelAbstractSyntaxTree optimize(CelAbstractSyntaxTree checkedAst) throws CelOptimizationException { + return CEL_OPTIMIZER.optimize(checkedAst); + } + + /** Evaluates the compiled AST with the user provided parameter values. */ + Object eval(CelAbstractSyntaxTree ast, Map parameterValues) + throws CelEvaluationException { + CelRuntime.Program program = CEL_RUNTIME.createProgram(ast); + return program.eval(parameterValues); + } +} diff --git a/codelab/src/test/codelab/BUILD.bazel b/codelab/src/test/codelab/BUILD.bazel index 5a979c968..6bc725573 100644 --- a/codelab/src/test/codelab/BUILD.bazel +++ b/codelab/src/test/codelab/BUILD.bazel @@ -115,6 +115,25 @@ java_test( ], ) +java_test( + name = "Exercise8Test", + srcs = ["Exercise8Test.java"], + tags = ["notap"], + test_class = "codelab.Exercise8Test", + deps = [ + "//:java_truth", + "//codelab", + "//common", + "//common:compiler_common", + "//parser:unparser", + "//runtime", + "@maven//:com_google_api_grpc_proto_google_common_protos", + "@maven//:com_google_guava_guava", + "@maven//:com_google_testparameterinjector_test_parameter_injector", + "@maven//:junit_junit", + ], +) + test_suite( name = "exercise_test_suite", tags = ["notap"], diff --git a/codelab/src/test/codelab/Exercise8Test.java b/codelab/src/test/codelab/Exercise8Test.java new file mode 100644 index 000000000..cda194437 --- /dev/null +++ b/codelab/src/test/codelab/Exercise8Test.java @@ -0,0 +1,147 @@ +// Copyright 2024 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 codelab; + +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertThrows; + +import com.google.common.collect.ImmutableMap; +import com.google.rpc.context.AttributeContext; +import com.google.testing.junit.testparameterinjector.TestParameterInjector; +import dev.cel.common.CelAbstractSyntaxTree; +import dev.cel.common.CelValidationException; +import dev.cel.common.CelValidationResult; +import dev.cel.parser.CelUnparser; +import dev.cel.parser.CelUnparserFactory; +import dev.cel.runtime.CelEvaluationException; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(TestParameterInjector.class) +public final class Exercise8Test { + + private final Exercise8 exercise8 = new Exercise8(); + + @Test + public void validate_invalidTimestampLiteral_returnsError() throws Exception { + CelAbstractSyntaxTree ast = exercise8.compile("timestamp('bad')"); + + CelValidationResult validationResult = exercise8.validate(ast); + + assertThat(validationResult.hasError()).isTrue(); + assertThat(validationResult.getErrorString()) + .isEqualTo( + "ERROR: :1:11: timestamp validation failed. Reason: evaluation error: Failed to" + + " parse timestamp: invalid timestamp \"bad\"\n" + + " | timestamp('bad')\n" + + " | ..........^"); + } + + @Test + public void validate_invalidDurationLiteral_returnsError() throws Exception { + CelAbstractSyntaxTree ast = exercise8.compile("duration('bad')"); + + CelValidationResult validationResult = exercise8.validate(ast); + + assertThat(validationResult.hasError()).isTrue(); + assertThat(validationResult.getErrorString()) + .isEqualTo( + "ERROR: :1:10: duration validation failed. Reason: evaluation error: invalid" + + " duration format\n" + + " | duration('bad')\n" + + " | .........^"); + } + + @Test + public void validate_invalidRegexLiteral_returnsError() throws Exception { + CelAbstractSyntaxTree ast = exercise8.compile("'text'.matches('**')"); + + CelValidationResult validationResult = exercise8.validate(ast); + + assertThat(validationResult.hasError()).isTrue(); + assertThat(validationResult.getErrorString()) + .isEqualTo( + "ERROR: :1:16: Regex validation failed. Reason: Dangling meta character '*' near" + + " index 0\n" + + "**\n" + + "^\n" + + " | 'text'.matches('**')\n" + + " | ...............^"); + } + + @Test + public void validate_listHasMixedLiterals_throws() throws Exception { + CelAbstractSyntaxTree ast = exercise8.compile("3 in [1, 2, '3']"); + + // Note that `CelValidationResult` is the same result class used for the compilation path. This + // means you could alternatively invoke `.getAst()` and handle `CelValidationException` as + // usual. + CelValidationResult validationResult = exercise8.validate(ast); + + CelValidationException e = assertThrows(CelValidationException.class, validationResult::getAst); + assertThat(e) + .hasMessageThat() + .contains( + "ERROR: :1:13: expected type 'int' but found 'string'\n" + + " | 3 in [1, 2, '3']\n" + + " | ............^"); + } + + @Test + public void optimize_constantFold_success() throws Exception { + CelUnparser celUnparser = CelUnparserFactory.newUnparser(); + CelAbstractSyntaxTree ast = exercise8.compile("(1 + 2 + 3 == x) && (x in [1, 2, x])"); + + CelAbstractSyntaxTree optimizedAst = exercise8.optimize(ast); + + assertThat(celUnparser.unparse(optimizedAst)).isEqualTo("6 == x"); + } + + @Test + public void optimize_constantFold_evaluateError() throws Exception { + CelAbstractSyntaxTree ast = + exercise8.compile("request.headers.referer == 'https://' + 'cel.dev'"); + CelAbstractSyntaxTree optimizedAst = exercise8.optimize(ast); + ImmutableMap runtimeParameters = + ImmutableMap.of("request", AttributeContext.Request.getDefaultInstance()); + + CelEvaluationException e1 = + assertThrows(CelEvaluationException.class, () -> exercise8.eval(ast, runtimeParameters)); + CelEvaluationException e2 = + assertThrows( + CelEvaluationException.class, () -> exercise8.eval(optimizedAst, runtimeParameters)); + // Note that the errors below differ by their source position. + assertThat(e1) + .hasMessageThat() + .contains("evaluation error at :15: key 'referer' is not present in map."); + assertThat(e2) + .hasMessageThat() + .contains("evaluation error at :0: key 'referer' is not present in map."); + } + + @Test + public void optimize_commonSubexpressionElimination_success() throws Exception { + CelUnparser celUnparser = CelUnparserFactory.newUnparser(); + CelAbstractSyntaxTree ast = + exercise8.compile( + "request.auth.claims.group == 'admin' || request.auth.claims.group == 'user'"); + + CelAbstractSyntaxTree optimizedAst = exercise8.optimize(ast); + + assertThat(celUnparser.unparse(optimizedAst)) + .isEqualTo( + "cel.@block([request.auth.claims.group], @index0 == \"admin\" || @index0 == \"user\")"); + } +} diff --git a/codelab/src/test/codelab/solutions/BUILD.bazel b/codelab/src/test/codelab/solutions/BUILD.bazel index 5c139b613..3f434f83a 100644 --- a/codelab/src/test/codelab/solutions/BUILD.bazel +++ b/codelab/src/test/codelab/solutions/BUILD.bazel @@ -107,3 +107,21 @@ java_test( "@maven//:junit_junit", ], ) + +java_test( + name = "Exercise8Test", + srcs = ["Exercise8Test.java"], + test_class = "codelab.solutions.Exercise8Test", + deps = [ + "//:java_truth", + "//codelab:solutions", + "//common", + "//common:compiler_common", + "//parser:unparser", + "//runtime", + "@maven//:com_google_api_grpc_proto_google_common_protos", + "@maven//:com_google_guava_guava", + "@maven//:com_google_testparameterinjector_test_parameter_injector", + "@maven//:junit_junit", + ], +) diff --git a/codelab/src/test/codelab/solutions/Exercise8Test.java b/codelab/src/test/codelab/solutions/Exercise8Test.java new file mode 100644 index 000000000..a0d770a07 --- /dev/null +++ b/codelab/src/test/codelab/solutions/Exercise8Test.java @@ -0,0 +1,147 @@ +// Copyright 2024 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 codelab.solutions; + +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertThrows; + +import com.google.common.collect.ImmutableMap; +import com.google.rpc.context.AttributeContext; +import com.google.testing.junit.testparameterinjector.TestParameterInjector; +import dev.cel.common.CelAbstractSyntaxTree; +import dev.cel.common.CelValidationException; +import dev.cel.common.CelValidationResult; +import dev.cel.parser.CelUnparser; +import dev.cel.parser.CelUnparserFactory; +import dev.cel.runtime.CelEvaluationException; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(TestParameterInjector.class) +public final class Exercise8Test { + + private final Exercise8 exercise8 = new Exercise8(); + + @Test + public void validate_invalidTimestampLiteral_returnsError() throws Exception { + CelAbstractSyntaxTree ast = exercise8.compile("timestamp('bad')"); + + CelValidationResult validationResult = exercise8.validate(ast); + + assertThat(validationResult.hasError()).isTrue(); + assertThat(validationResult.getErrorString()) + .isEqualTo( + "ERROR: :1:11: timestamp validation failed. Reason: evaluation error: Failed to" + + " parse timestamp: invalid timestamp \"bad\"\n" + + " | timestamp('bad')\n" + + " | ..........^"); + } + + @Test + public void validate_invalidDurationLiteral_returnsError() throws Exception { + CelAbstractSyntaxTree ast = exercise8.compile("duration('bad')"); + + CelValidationResult validationResult = exercise8.validate(ast); + + assertThat(validationResult.hasError()).isTrue(); + assertThat(validationResult.getErrorString()) + .isEqualTo( + "ERROR: :1:10: duration validation failed. Reason: evaluation error: invalid" + + " duration format\n" + + " | duration('bad')\n" + + " | .........^"); + } + + @Test + public void validate_invalidRegexLiteral_returnsError() throws Exception { + CelAbstractSyntaxTree ast = exercise8.compile("'text'.matches('**')"); + + CelValidationResult validationResult = exercise8.validate(ast); + + assertThat(validationResult.hasError()).isTrue(); + assertThat(validationResult.getErrorString()) + .isEqualTo( + "ERROR: :1:16: Regex validation failed. Reason: Dangling meta character '*' near" + + " index 0\n" + + "**\n" + + "^\n" + + " | 'text'.matches('**')\n" + + " | ...............^"); + } + + @Test + public void validate_listHasMixedLiterals_throws() throws Exception { + CelAbstractSyntaxTree ast = exercise8.compile("3 in [1, 2, '3']"); + + // Note that `CelValidationResult` is the same result class used for the compilation path. This + // means you could alternatively invoke `.getAst()` and handle `CelValidationException` as + // usual. + CelValidationResult validationResult = exercise8.validate(ast); + + CelValidationException e = assertThrows(CelValidationException.class, validationResult::getAst); + assertThat(e) + .hasMessageThat() + .contains( + "ERROR: :1:13: expected type 'int' but found 'string'\n" + + " | 3 in [1, 2, '3']\n" + + " | ............^"); + } + + @Test + public void optimize_constantFold_success() throws Exception { + CelUnparser celUnparser = CelUnparserFactory.newUnparser(); + CelAbstractSyntaxTree ast = exercise8.compile("(1 + 2 + 3 == x) && (x in [1, 2, x])"); + + CelAbstractSyntaxTree optimizedAst = exercise8.optimize(ast); + + assertThat(celUnparser.unparse(optimizedAst)).isEqualTo("6 == x"); + } + + @Test + public void optimize_constantFold_evaluateError() throws Exception { + CelAbstractSyntaxTree ast = + exercise8.compile("request.headers.referer == 'https://' + 'cel.dev'"); + CelAbstractSyntaxTree optimizedAst = exercise8.optimize(ast); + ImmutableMap runtimeParameters = + ImmutableMap.of("request", AttributeContext.Request.getDefaultInstance()); + + CelEvaluationException e1 = + assertThrows(CelEvaluationException.class, () -> exercise8.eval(ast, runtimeParameters)); + CelEvaluationException e2 = + assertThrows( + CelEvaluationException.class, () -> exercise8.eval(optimizedAst, runtimeParameters)); + // Note that the errors below differ by their source position. + assertThat(e1) + .hasMessageThat() + .contains("evaluation error at :15: key 'referer' is not present in map."); + assertThat(e2) + .hasMessageThat() + .contains("evaluation error at :0: key 'referer' is not present in map."); + } + + @Test + public void optimize_commonSubexpressionElimination_success() throws Exception { + CelUnparser celUnparser = CelUnparserFactory.newUnparser(); + CelAbstractSyntaxTree ast = + exercise8.compile( + "request.auth.claims.group == 'admin' || request.auth.claims.group == 'user'"); + + CelAbstractSyntaxTree optimizedAst = exercise8.optimize(ast); + + assertThat(celUnparser.unparse(optimizedAst)) + .isEqualTo( + "cel.@block([request.auth.claims.group], @index0 == \"admin\" || @index0 == \"user\")"); + } +} From fbf7c27845e8926b07a105d280ffff63d9861579 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Thu, 9 May 2024 10:51:18 -0700 Subject: [PATCH 121/486] Add code for Exercise 9 Codelabs PiperOrigin-RevId: 632202746 --- codelab/src/main/codelab/BUILD.bazel | 4 + codelab/src/main/codelab/Exercise9.java | 99 ++++++++++ .../src/main/codelab/solutions/BUILD.bazel | 4 + .../src/main/codelab/solutions/Exercise9.java | 173 ++++++++++++++++++ codelab/src/test/codelab/BUILD.bazel | 16 ++ codelab/src/test/codelab/Exercise9Test.java | 95 ++++++++++ .../src/test/codelab/solutions/BUILD.bazel | 15 ++ .../test/codelab/solutions/Exercise9Test.java | 95 ++++++++++ 8 files changed, 501 insertions(+) create mode 100644 codelab/src/main/codelab/Exercise9.java create mode 100644 codelab/src/main/codelab/solutions/Exercise9.java create mode 100644 codelab/src/test/codelab/Exercise9Test.java create mode 100644 codelab/src/test/codelab/solutions/Exercise9Test.java diff --git a/codelab/src/main/codelab/BUILD.bazel b/codelab/src/main/codelab/BUILD.bazel index 117d1ccd8..6c9f90259 100644 --- a/codelab/src/main/codelab/BUILD.bazel +++ b/codelab/src/main/codelab/BUILD.bazel @@ -9,9 +9,12 @@ java_library( name = "codelab", srcs = glob(["*.java"]), deps = [ + "//bundle:cel", # unuseddeps: keep "//common", # unuseddeps: keep "//common:compiler_common", # unuseddeps: keep "//common:proto_json_adapter", # unuseddeps: keep + "//common/ast", # unuseddeps: keep + "//common/navigation", # unuseddeps: keep "//common/types", # unuseddeps: keep "//common/types:type_providers", # unuseddeps: keep "//compiler", # unuseddeps: keep @@ -24,6 +27,7 @@ java_library( "//parser:macro", # unuseddeps: keep "//runtime", # unuseddeps: keep "//validator", # unuseddeps: keep + "//validator:ast_validator", # unuseddeps: keep "//validator:validator_builder", # unuseddeps: keep "//validator/validators:duration", # unuseddeps: keep "//validator/validators:homogeneous_literal", # unuseddeps: keep diff --git a/codelab/src/main/codelab/Exercise9.java b/codelab/src/main/codelab/Exercise9.java new file mode 100644 index 000000000..85705390c --- /dev/null +++ b/codelab/src/main/codelab/Exercise9.java @@ -0,0 +1,99 @@ +// Copyright 2024 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 codelab; + +import com.google.rpc.context.AttributeContext; +import dev.cel.common.CelAbstractSyntaxTree; +import dev.cel.common.CelFunctionDecl; +import dev.cel.common.CelOverloadDecl; +import dev.cel.common.CelValidationException; +import dev.cel.common.CelValidationResult; +import dev.cel.common.types.SimpleType; +import dev.cel.compiler.CelCompiler; +import dev.cel.compiler.CelCompilerFactory; +import dev.cel.parser.CelStandardMacro; +import dev.cel.runtime.CelEvaluationException; +import dev.cel.runtime.CelRuntime; +import dev.cel.runtime.CelRuntimeFactory; +import dev.cel.validator.CelValidator; +import dev.cel.validator.CelValidatorFactory; + +/** + * Exercise9 demonstrates how to author a custom AST validator to perform domain specific + * validations. + * + *

Given a `google.rpc.context.AttributeContext.Request` message, validate that its fields follow + * the expected HTTP specification. + * + *

Given an expression containing an expensive function call, validate that it is not nested + * within a macro. + */ +final class Exercise9 { + private static final CelCompiler CEL_COMPILER = + CelCompilerFactory.standardCelCompilerBuilder() + .setStandardMacros(CelStandardMacro.ALL) + .addFunctionDeclarations( + CelFunctionDecl.newFunctionDeclaration( + "is_prime_number", + CelOverloadDecl.newGlobalOverload( + "is_prime_number_int", + "Invokes an expensive RPC call to check if the value is a prime number.", + SimpleType.BOOL, + SimpleType.INT))) + .addMessageTypes(AttributeContext.Request.getDescriptor()) + .build(); + private static final CelRuntime CEL_RUNTIME = + CelRuntimeFactory.standardCelRuntimeBuilder() + .addMessageTypes(AttributeContext.Request.getDescriptor()) + .build(); + private static final CelValidator CEL_VALIDATOR = + CelValidatorFactory.standardCelValidatorBuilder(CEL_COMPILER, CEL_RUNTIME) + // Add your custom AST validators here + .build(); + + /** + * Compiles the input expression. + * + * @throws CelValidationException If the expression contains parsing or type-checking errors. + */ + CelAbstractSyntaxTree compile(String expression) throws CelValidationException { + return CEL_COMPILER.compile(expression).getAst(); + } + + /** Validates a type-checked AST. */ + CelValidationResult validate(CelAbstractSyntaxTree checkedAst) { + return CEL_VALIDATOR.validate(checkedAst); + } + + /** Evaluates the compiled AST. */ + Object eval(CelAbstractSyntaxTree ast) throws CelEvaluationException { + return CEL_RUNTIME.createProgram(ast).eval(); + } + + /** + * Performs general validation on AttributeContext.Request message. The validator raises errors if + * the HTTP request is malformed and semantically invalid (e.g: contains disallowed HTTP methods). + * Warnings are presented if there's potential problems with the contents of the request (e.g: + * using "http" instead of "https" for scheme). + */ + static final class AttributeContextRequestValidator { + // Implement validate method here + } + + /** Prevents nesting an expensive function call within a macro. */ + static final class ComprehensionSafetyValidator { + // Implement validate method here + } +} diff --git a/codelab/src/main/codelab/solutions/BUILD.bazel b/codelab/src/main/codelab/solutions/BUILD.bazel index ec29a3e7a..44f9632ea 100644 --- a/codelab/src/main/codelab/solutions/BUILD.bazel +++ b/codelab/src/main/codelab/solutions/BUILD.bazel @@ -9,9 +9,12 @@ java_library( name = "solutions", srcs = glob(["*.java"]), deps = [ + "//bundle:cel", "//common", "//common:compiler_common", "//common:proto_json_adapter", + "//common/ast", + "//common/navigation", "//common/types", "//common/types:type_providers", "//compiler", @@ -24,6 +27,7 @@ java_library( "//parser:macro", "//runtime", "//validator", + "//validator:ast_validator", "//validator:validator_builder", "//validator/validators:duration", "//validator/validators:homogeneous_literal", diff --git a/codelab/src/main/codelab/solutions/Exercise9.java b/codelab/src/main/codelab/solutions/Exercise9.java new file mode 100644 index 000000000..2b45c3539 --- /dev/null +++ b/codelab/src/main/codelab/solutions/Exercise9.java @@ -0,0 +1,173 @@ +// Copyright 2024 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 codelab.solutions; + +import com.google.common.collect.ImmutableSet; +import com.google.rpc.context.AttributeContext; +import dev.cel.bundle.Cel; +import dev.cel.common.CelAbstractSyntaxTree; +import dev.cel.common.CelFunctionDecl; +import dev.cel.common.CelOverloadDecl; +import dev.cel.common.CelValidationException; +import dev.cel.common.CelValidationResult; +import dev.cel.common.ast.CelExpr; +import dev.cel.common.ast.CelExpr.CelStruct; +import dev.cel.common.ast.CelExpr.ExprKind.Kind; +import dev.cel.common.navigation.CelNavigableAst; +import dev.cel.common.types.SimpleType; +import dev.cel.compiler.CelCompiler; +import dev.cel.compiler.CelCompilerFactory; +import dev.cel.parser.CelStandardMacro; +import dev.cel.runtime.CelEvaluationException; +import dev.cel.runtime.CelRuntime; +import dev.cel.runtime.CelRuntimeFactory; +import dev.cel.validator.CelAstValidator; +import dev.cel.validator.CelValidator; +import dev.cel.validator.CelValidatorFactory; + +/** + * Exercise9 demonstrates how to author a custom AST validator to perform domain specific + * validations. + * + *

Given a `google.rpc.context.AttributeContext.Request` message, validate that its fields follow + * the expected HTTP specification. + * + *

Given an expression containing an expensive function call, validate that it is not nested + * within a macro. + */ +final class Exercise9 { + private static final CelCompiler CEL_COMPILER = + CelCompilerFactory.standardCelCompilerBuilder() + .setStandardMacros(CelStandardMacro.ALL) + .addFunctionDeclarations( + CelFunctionDecl.newFunctionDeclaration( + "is_prime_number", + CelOverloadDecl.newGlobalOverload( + "is_prime_number_int", + "Invokes an expensive RPC call to check if the value is a prime number.", + SimpleType.BOOL, + SimpleType.INT))) + .addMessageTypes(AttributeContext.Request.getDescriptor()) + .build(); + private static final CelRuntime CEL_RUNTIME = + CelRuntimeFactory.standardCelRuntimeBuilder() + .addMessageTypes(AttributeContext.Request.getDescriptor()) + .build(); + private static final CelValidator CEL_VALIDATOR = + CelValidatorFactory.standardCelValidatorBuilder(CEL_COMPILER, CEL_RUNTIME) + .addAstValidators( + new AttributeContextRequestValidator(), // + new ComprehensionSafetyValidator()) + .build(); + + /** + * Compiles the input expression. + * + * @throws CelValidationException If the expression contains parsing or type-checking errors. + */ + CelAbstractSyntaxTree compile(String expression) throws CelValidationException { + return CEL_COMPILER.compile(expression).getAst(); + } + + /** Validates a type-checked AST. */ + CelValidationResult validate(CelAbstractSyntaxTree checkedAst) { + return CEL_VALIDATOR.validate(checkedAst); + } + + /** Evaluates the compiled AST. */ + Object eval(CelAbstractSyntaxTree ast) throws CelEvaluationException { + return CEL_RUNTIME.createProgram(ast).eval(); + } + + /** + * Performs general validation on AttributeContext.Request message. The validator raises errors if + * the HTTP request is malformed and semantically invalid (e.g: contains disallowed HTTP methods). + * Warnings are presented if there's potential problems with the contents of the request (e.g: + * using "http" instead of "https" for scheme). + */ + static final class AttributeContextRequestValidator implements CelAstValidator { + private static final ImmutableSet ALLOWED_HTTP_METHODS = + ImmutableSet.of("GET", "POST", "PUT", "DELETE"); + + @Override + public void validate(CelNavigableAst navigableAst, Cel cel, IssuesFactory issuesFactory) { + navigableAst + .getRoot() + .allNodes() + .filter(node -> node.getKind().equals(Kind.STRUCT)) + .map(node -> node.expr().struct()) + .filter( + struct -> struct.messageName().equals("google.rpc.context.AttributeContext.Request")) + .forEach( + struct -> { + for (CelStruct.Entry entry : struct.entries()) { + String fieldKey = entry.fieldKey(); + if (fieldKey.equals("method")) { + String entryStringValue = getStringValue(entry.value()); + if (!ALLOWED_HTTP_METHODS.contains(entryStringValue)) { + issuesFactory.addError( + entry.value().id(), entryStringValue + " is not an allowed HTTP method."); + } + } else if (fieldKey.equals("scheme")) { + String entryStringValue = getStringValue(entry.value()); + if (!entryStringValue.equals("https")) { + issuesFactory.addWarning( + entry.value().id(), "Prefer using https for safety."); + } + } + } + }); + } + + /** + * Reads the underlying string value from the expression. + * + * @throws UnsupportedOperationException if the expression is not a constant string value. + */ + private static String getStringValue(CelExpr celExpr) { + return celExpr.constant().stringValue(); + } + } + + /** Prevents nesting an expensive function call within a macro. */ + static final class ComprehensionSafetyValidator implements CelAstValidator { + private static final String EXPENSIVE_FUNCTION_NAME = "is_prime_number"; + + @Override + public void validate(CelNavigableAst navigableAst, Cel cel, IssuesFactory issuesFactory) { + navigableAst + .getRoot() + .allNodes() + .filter(node -> node.getKind().equals(Kind.COMPREHENSION)) + .forEach( + comprehensionNode -> { + boolean isFunctionWithinMacro = + comprehensionNode + .descendants() + .anyMatch( + node -> + node.expr() + .callOrDefault() + .function() + .equals(EXPENSIVE_FUNCTION_NAME)); + if (isFunctionWithinMacro) { + issuesFactory.addError( + comprehensionNode.id(), + EXPENSIVE_FUNCTION_NAME + " function cannot be used within CEL macros."); + } + }); + } + } +} diff --git a/codelab/src/test/codelab/BUILD.bazel b/codelab/src/test/codelab/BUILD.bazel index 6bc725573..8772578c1 100644 --- a/codelab/src/test/codelab/BUILD.bazel +++ b/codelab/src/test/codelab/BUILD.bazel @@ -134,6 +134,22 @@ java_test( ], ) +java_test( + name = "Exercise9Test", + srcs = ["Exercise9Test.java"], + tags = ["notap"], + test_class = "codelab.Exercise9Test", + deps = [ + "//:java_truth", + "//codelab", + "//common", + "//common:compiler_common", + "@maven//:com_google_api_grpc_proto_google_common_protos", + "@maven//:com_google_testparameterinjector_test_parameter_injector", + "@maven//:junit_junit", + ], +) + test_suite( name = "exercise_test_suite", tags = ["notap"], diff --git a/codelab/src/test/codelab/Exercise9Test.java b/codelab/src/test/codelab/Exercise9Test.java new file mode 100644 index 000000000..7157d61c2 --- /dev/null +++ b/codelab/src/test/codelab/Exercise9Test.java @@ -0,0 +1,95 @@ +// Copyright 2024 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 codelab; + +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertThrows; + +import com.google.rpc.context.AttributeContext; +import com.google.testing.junit.testparameterinjector.TestParameterInjector; +import dev.cel.common.CelAbstractSyntaxTree; +import dev.cel.common.CelValidationException; +import dev.cel.common.CelValidationResult; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(TestParameterInjector.class) +public final class Exercise9Test { + private final Exercise9 exercise9 = new Exercise9(); + + @Test + public void validate_invalidHttpMethod_returnsError() throws Exception { + String expression = + "google.rpc.context.AttributeContext.Request { \n" + + "scheme: 'http', " + + "method: 'GETTT', " // method is misspelled. + + "host: 'cel.dev' \n" + + "}"; + CelAbstractSyntaxTree ast = exercise9.compile(expression); + + CelValidationResult validationResult = exercise9.validate(ast); + + assertThat(validationResult.hasError()).isTrue(); + assertThat(validationResult.getErrorString()) + .isEqualTo( + "ERROR: :2:25: GETTT is not an allowed HTTP method.\n" + + " | scheme: 'http', method: 'GETTT', host: 'cel.dev' \n" + + " | ........................^"); + assertThrows(CelValidationException.class, validationResult::getAst); + } + + @Test + public void validate_schemeIsHttp_returnsWarning() throws Exception { + String expression = + "google.rpc.context.AttributeContext.Request { \n" + + "scheme: 'http', " // https is preferred but not required. + + "method: 'GET', " + + "host: 'cel.dev' \n" + + "}"; + CelAbstractSyntaxTree ast = exercise9.compile(expression); + + CelValidationResult validationResult = exercise9.validate(ast); + + assertThat(validationResult.hasError()).isFalse(); + assertThat(validationResult.getIssueString()) + .isEqualTo( + "WARNING: :2:9: Prefer using https for safety.\n" + + " | scheme: 'http', method: 'GET', host: 'cel.dev' \n" + + " | ........^"); + // Because the validation result does not contain any errors, you can still evaluate it. + assertThat(exercise9.eval(validationResult.getAst())) + .isEqualTo( + AttributeContext.Request.newBuilder() + .setScheme("http") + .setMethod("GET") + .setHost("cel.dev") + .build()); + } + + @Test + public void validate_isPrimeNumberWithinMacro_returnsError() throws Exception { + String expression = "[2,3,5].all(x, is_prime_number(x))"; + CelAbstractSyntaxTree ast = exercise9.compile(expression); + + CelValidationResult validationResult = exercise9.validate(ast); + + assertThat(validationResult.hasError()).isTrue(); + assertThat(validationResult.getErrorString()) + .isEqualTo( + "ERROR: :1:12: is_prime_number function cannot be used within CEL macros.\n" + + " | [2,3,5].all(x, is_prime_number(x))\n" + + " | ...........^"); + } +} diff --git a/codelab/src/test/codelab/solutions/BUILD.bazel b/codelab/src/test/codelab/solutions/BUILD.bazel index 3f434f83a..0ac187a92 100644 --- a/codelab/src/test/codelab/solutions/BUILD.bazel +++ b/codelab/src/test/codelab/solutions/BUILD.bazel @@ -125,3 +125,18 @@ java_test( "@maven//:junit_junit", ], ) + +java_test( + name = "Exercise9Test", + srcs = ["Exercise9Test.java"], + test_class = "codelab.solutions.Exercise9Test", + deps = [ + "//:java_truth", + "//codelab:solutions", + "//common", + "//common:compiler_common", + "@maven//:com_google_api_grpc_proto_google_common_protos", + "@maven//:com_google_testparameterinjector_test_parameter_injector", + "@maven//:junit_junit", + ], +) diff --git a/codelab/src/test/codelab/solutions/Exercise9Test.java b/codelab/src/test/codelab/solutions/Exercise9Test.java new file mode 100644 index 000000000..622df45ce --- /dev/null +++ b/codelab/src/test/codelab/solutions/Exercise9Test.java @@ -0,0 +1,95 @@ +// Copyright 2024 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 codelab.solutions; + +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertThrows; + +import com.google.rpc.context.AttributeContext; +import com.google.testing.junit.testparameterinjector.TestParameterInjector; +import dev.cel.common.CelAbstractSyntaxTree; +import dev.cel.common.CelValidationException; +import dev.cel.common.CelValidationResult; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(TestParameterInjector.class) +public final class Exercise9Test { + private final Exercise9 exercise9 = new Exercise9(); + + @Test + public void validate_invalidHttpMethod_returnsError() throws Exception { + String expression = + "google.rpc.context.AttributeContext.Request { \n" + + "scheme: 'http', " + + "method: 'GETTT', " // method is misspelled. + + "host: 'cel.dev' \n" + + "}"; + CelAbstractSyntaxTree ast = exercise9.compile(expression); + + CelValidationResult validationResult = exercise9.validate(ast); + + assertThat(validationResult.hasError()).isTrue(); + assertThat(validationResult.getErrorString()) + .isEqualTo( + "ERROR: :2:25: GETTT is not an allowed HTTP method.\n" + + " | scheme: 'http', method: 'GETTT', host: 'cel.dev' \n" + + " | ........................^"); + assertThrows(CelValidationException.class, validationResult::getAst); + } + + @Test + public void validate_schemeIsHttp_returnsWarning() throws Exception { + String expression = + "google.rpc.context.AttributeContext.Request { \n" + + "scheme: 'http', " // https is preferred but not required. + + "method: 'GET', " + + "host: 'cel.dev' \n" + + "}"; + CelAbstractSyntaxTree ast = exercise9.compile(expression); + + CelValidationResult validationResult = exercise9.validate(ast); + + assertThat(validationResult.hasError()).isFalse(); + assertThat(validationResult.getIssueString()) + .isEqualTo( + "WARNING: :2:9: Prefer using https for safety.\n" + + " | scheme: 'http', method: 'GET', host: 'cel.dev' \n" + + " | ........^"); + // Because the validation result does not contain any errors, you can still evaluate it. + assertThat(exercise9.eval(validationResult.getAst())) + .isEqualTo( + AttributeContext.Request.newBuilder() + .setScheme("http") + .setMethod("GET") + .setHost("cel.dev") + .build()); + } + + @Test + public void validate_isPrimeNumberWithinMacro_returnsError() throws Exception { + String expression = "[2,3,5].all(x, is_prime_number(x))"; + CelAbstractSyntaxTree ast = exercise9.compile(expression); + + CelValidationResult validationResult = exercise9.validate(ast); + + assertThat(validationResult.hasError()).isTrue(); + assertThat(validationResult.getErrorString()) + .isEqualTo( + "ERROR: :1:12: is_prime_number function cannot be used within CEL macros.\n" + + " | [2,3,5].all(x, is_prime_number(x))\n" + + " | ...........^"); + } +} From 285436e791c8aa08808838fcdb30f2d3119becd7 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Thu, 9 May 2024 12:05:33 -0700 Subject: [PATCH 122/486] Clear the source position for only the dangling macro expr ID instead of all exprs PiperOrigin-RevId: 632228017 --- common/src/main/java/dev/cel/common/CelSource.java | 6 ------ parser/src/main/java/dev/cel/parser/Parser.java | 2 +- .../dev/cel/parser/CelParserParameterizedTest.java | 1 + parser/src/test/resources/parser_errors.baseline | 11 ++++++++++- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/common/src/main/java/dev/cel/common/CelSource.java b/common/src/main/java/dev/cel/common/CelSource.java index 595fbffca..aea607ccd 100644 --- a/common/src/main/java/dev/cel/common/CelSource.java +++ b/common/src/main/java/dev/cel/common/CelSource.java @@ -261,12 +261,6 @@ public Builder addPositions(long exprId, int position) { return this; } - @CanIgnoreReturnValue - public Builder clearPositions() { - this.positions.clear(); - return this; - } - @CanIgnoreReturnValue public Builder removePositions(long exprId) { this.positions.remove(exprId); diff --git a/parser/src/main/java/dev/cel/parser/Parser.java b/parser/src/main/java/dev/cel/parser/Parser.java index d61cf3c45..3ec9350ed 100644 --- a/parser/src/main/java/dev/cel/parser/Parser.java +++ b/parser/src/main/java/dev/cel/parser/Parser.java @@ -896,7 +896,7 @@ private CelExpr macroOrCall( ImmutableList arguments = visitExprListContext(args); Optional errorArg = arguments.stream().filter(ERROR::equals).findAny(); if (errorArg.isPresent()) { - sourceInfo.clearPositions(); + sourceInfo.removePositions(exprBuilder.id()); // Any arguments passed in to the macro may fail parsing. // Stop the macro expansion in this case as the result of the macro will be a parse failure. return ERROR; diff --git a/parser/src/test/java/dev/cel/parser/CelParserParameterizedTest.java b/parser/src/test/java/dev/cel/parser/CelParserParameterizedTest.java index a013c4ea3..a091cc60a 100644 --- a/parser/src/test/java/dev/cel/parser/CelParserParameterizedTest.java +++ b/parser/src/test/java/dev/cel/parser/CelParserParameterizedTest.java @@ -239,6 +239,7 @@ public void parser_errors() { runTest(PARSER, "TestAllTypes(){single_int32: 1, single_int64: 2}"); runTest(PARSER, "{"); runTest(PARSER, "t{>C}"); + runTest(PARSER, "has([(has(("); CelParser parserWithoutOptionalSupport = CelParserImpl.newBuilder() diff --git a/parser/src/test/resources/parser_errors.baseline b/parser/src/test/resources/parser_errors.baseline index 9ae4565ce..8547ebed9 100644 --- a/parser/src/test/resources/parser_errors.baseline +++ b/parser/src/test/resources/parser_errors.baseline @@ -262,6 +262,15 @@ ERROR: :1:5: mismatched input '}' expecting ':' | t{>C} | ....^ +I: has([(has(( +=====> +E: ERROR: :1:4: invalid argument to has() macro + | has([(has(( + | ...^ +ERROR: :1:12: mismatched input '' expecting {'[', '{', '(', '.', '-', '!', 'true', 'false', 'null', NUM_FLOAT, NUM_INT, NUM_UINT, STRING, BYTES, IDENTIFIER} + | has([(has(( + | ...........^ + I: a.?b && a[?b] =====> E: ERROR: :1:2: unsupported syntax '.?' @@ -287,4 +296,4 @@ E: ERROR: :1:2: unsupported syntax '?' | .^ ERROR: :1:6: unsupported syntax '?' | [?a, ?b] - | .....^ + | .....^ \ No newline at end of file From e29ccc823697016bb33b7407d406adc0f9ba0146 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Thu, 16 May 2024 11:28:10 -0700 Subject: [PATCH 123/486] Mark CelDescriptorUtil as internal. Remove unused method PiperOrigin-RevId: 634473979 --- .../dev/cel/common/CelDescriptorUtil.java | 23 ++++++------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/common/src/main/java/dev/cel/common/CelDescriptorUtil.java b/common/src/main/java/dev/cel/common/CelDescriptorUtil.java index 28aff8291..db1f22120 100644 --- a/common/src/main/java/dev/cel/common/CelDescriptorUtil.java +++ b/common/src/main/java/dev/cel/common/CelDescriptorUtil.java @@ -14,37 +14,28 @@ package dev.cel.common; -import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.protobuf.DescriptorProtos.FileDescriptorSet; import com.google.protobuf.Descriptors.Descriptor; import com.google.protobuf.Descriptors.FieldDescriptor; import com.google.protobuf.Descriptors.FileDescriptor; -import com.google.protobuf.Descriptors.GenericDescriptor; +import dev.cel.common.annotations.Internal; import dev.cel.common.internal.FileDescriptorSetConverter; import dev.cel.common.types.CelTypes; import java.util.Arrays; -import java.util.Collection; import java.util.HashSet; import java.util.Set; -/** Utility class for working with protobuf descriptors. */ +/** + * Utility class for working with protobuf descriptors. + * + *

CEL Library Internals. Do Not Use. + */ +@Internal public final class CelDescriptorUtil { private CelDescriptorUtil() {} - /** - * Converts descriptor collection to an ImmutableMap. - * - *

Key: Descriptor's full name, Value: Descriptor object - */ - public static ImmutableMap descriptorCollectionToMap( - Collection descriptors) { - ImmutableMap.Builder descriptorMapBuilder = new ImmutableMap.Builder<>(); - descriptors.forEach(d -> descriptorMapBuilder.put(d.getFullName(), d)); - return descriptorMapBuilder.buildOrThrow(); - } - /** * Get the full {@code FileDescriptor} set needed to accurately instantiate the {@code * descriptors}. From 28de30650bd218afa4f75f9abb2df62267ef7006 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Thu, 23 May 2024 13:08:12 -0700 Subject: [PATCH 124/486] Add documentation for codelab exercises 5 through 9 PiperOrigin-RevId: 636650857 --- codelab/README.md | 1048 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 1046 insertions(+), 2 deletions(-) diff --git a/codelab/README.md b/codelab/README.md index 825783620..7c9e41cb0 100644 --- a/codelab/README.md +++ b/codelab/README.md @@ -16,7 +16,11 @@ Some key areas covered are: * [Creating variables](#creating-variables) * [Commutatibe logical AND/OR](#logical-andor) * [Adding custom functions](#custom-functions) +* [Building JSON](#building-json) * [Building Protos](#building-protos) +* [Macros](#macros) +* [Static AST Validators and Optimizers](#static-ast-validators-and-optimizers) +* [Custom AST Validation](#custom-ast-validation) ### Prerequisites This codelab builds upon a basic understanding of Protocol Buffers and Java. @@ -534,8 +538,9 @@ You should see the following error: To fix the error, the contains function will need to be added to the list of declarations which currently declares the request variable. Declaring a function is not much different than declaring a variable. A function must indicate its common name and enumerate a set of overloads with unique signatures. +The following snippet shows how to declare a parameterized type. This is the most complicated any function overload ever be for CEL: + ```java -The following snippet shows how to declare a parameterized type. This is the most complicated any function overload will ever be for CEL: /** * Compiles the input expression. * @@ -636,6 +641,1045 @@ private static boolean mapContainsKeyValue(Object[] args) { > [!TIP] > Best practice: Declare overload ids according to their types and function names. e.g. targetType_func_argType_argType. In the case where argType is a type param, use a descriptive name instead of the simple type name. +## Building JSON + +CEL can also produce non-boolean outputs, such as JSON. + +Have a look at the test case in `Exercise5Test.java` first: + +```java +@Test +public void evaluate_jwtWithTimeVariable_producesJsonString() throws Exception { + // Note the quoted keys in the CEL map literal. For proto messages the field names are unquoted + // as they represent well-defined identifiers. + String jwt = + "{'sub': 'serviceAccount:delegate@acme.co'," + + "'aud': 'my-project'," + + "'iss': 'auth.acme.com:12350'," + + "'iat': time," + + "'nbf': time," + + "'exp': time + duration('300s')," + + "'extra_claims': {" + + "'group': 'admin'" + + "}}"; + CelAbstractSyntaxTree ast = exercise5.compile(jwt); + + // The output of the program is a map type. + @SuppressWarnings("unchecked") + Map evaluatedResult = + (Map) + exercise5.eval(ast, ImmutableMap.of("time", Timestamps.fromSeconds(1698361778))); + String jsonOutput = exercise5.toJson(evaluatedResult); + + assertThat(jsonOutput) + .isEqualTo( + "{\"sub\":\"serviceAccount:delegate@acme.co\"," + + "\"aud\":\"my-project\"," + + "\"iss\":\"auth.acme.com:12350\"," + + "\"iat\":\"2023-10-26T23:09:38Z\"," + + "\"nbf\":\"2023-10-26T23:09:38Z\"," + + "\"exp\":\"2023-10-26T23:14:38Z\"," + + "\"extra_claims\":{\"group\":\"admin\"}}"); +} +``` + +Run the test: + +```sh +bazel test --test_output=errors //codelab/src/test/codelab:Exercise5Test +``` + +You should see the following error: + +``` +There was 1 failure: +1) evaluate_jwtWithTimeVariable_producesJsonString(codelab.Exercise5Test) +java.lang.IllegalArgumentException: Failed to compile expression. + at codelab.Exercise5.compile(Exercise5.java:49) + at codelab.Exercise5Test.evaluate_jwtWithTimeVariable_producesJsonString(Exercise5Test.java:46) + ... 26 trimmed +Caused by: dev.cel.common.CelValidationException: ERROR: :1:99: undeclared reference to 'time' (in container '') + | {'sub': 'serviceAccount:delegate@acme.co','aud': 'my-project','iss': 'auth.acme.com:12350','iat': time,'nbf': time,'exp': time + duration('300s'),'extra_claims': {'group': 'admin'}} + | ..................................................................................................^ + ... and more ... +``` + +In `Exercise5.java`, add a declaration for the `time` variable of type `SimpleType.TIMESTAMP`: + +```java +CelAbstractSyntaxTree compile(String expression) { + CelCompiler celCompiler = + CelCompilerFactory.standardCelCompilerBuilder() + .addVar("time", SimpleType.TIMESTAMP) + .build(); +} +``` + +> [!NOTE] +> Timestamps and durations are well-known types and have special convenience +types within CEL. The `google.protobuf.Timestamp` and `google.protobuf.Duration` +message types are equivalent to the convenience types; however, the fields of +all well-known types are not directly accessible, but are instead mediated by +member functions. + +The expression will successfully compile then evaluate, but you will run into a different error: + +``` +There was 1 failure: +1) evaluate_jwtWithTimeVariable_producesJsonString(codelab.Exercise5Test) +java.lang.UnsupportedOperationException: To be implemented + at codelab.Exercise5.toJson(Exercise5.java:73) + at codelab.Exercise5Test.evaluate_jwtWithTimeVariable_producesJsonString(Exercise5Test.java:52) +``` + +The evaluated result is a native Java map type, and this needs to be explicitly +converted to JSON by leveraging `google.protobuf.Struct`. The internal CEL +representation is JSON convertible as it only refers to types that JSON can +support or for which there is a well-known [Proto to JSON mapping](https://protobuf.dev/programming-guides/proto3/#json). + +Copy and paste the following into `toJson` method: + +```java +/** Converts the evaluated result into a JSON string using protobuf's google.protobuf.Struct. */ +String toJson(Map map) throws InvalidProtocolBufferException { + // Convert the map into google.protobuf.Struct using the CEL provided helper function + Struct jsonStruct = CelProtoJsonAdapter.adaptToJsonStructValue(map); + // Then use Protobuf's JsonFormat to produce a JSON string output. + return JsonFormat.printer().omittingInsignificantWhitespace().print(jsonStruct); +} +``` +Re-running the test will show that it successfully passes. + ## Building Protos -CEL can also build protobuf messages for any message type compiled into the application. \ No newline at end of file +CEL can also build protobuf messages for any message type compiled into the application. + +Have a look at the test case in `Exercise6Test.java` first: + +```java +@Test +public void evaluate_constructAttributeContext() { + // Given JSON web token and the current time as input variables, + // Setup an expression to construct an AttributeContext protobuf object. + // + // Note: the field names within the proto message types are not quoted as they + // are well-defined names composed of valid identifier characters. Also, note + // that when building nested proto objects, the message name needs to prefix + // the object construction. + String expression = + "Request{\n" + + "auth: Auth{" + + " principal: jwt.iss + '/' + jwt.sub," + + " audiences: [jwt.aud]," + + " presenter: 'azp' in jwt ? jwt.azp : ''," + + " claims: jwt" + + "}," + + "time: now" + + "}"; + // Values for `now` and `jwt` variables to be passed into the runtime + Timestamp now = Timestamps.now(); + ImmutableMap jwt = + ImmutableMap.of( + "sub", "serviceAccount:delegate@acme.co", + "aud", "my-project", + "iss", "auth.acme.com:12350", + "extra_claims", ImmutableMap.of("group", "admin")); + AttributeContext.Request expectedMessage = + AttributeContext.Request.newBuilder() + .setTime(now) + .setAuth( + AttributeContext.Auth.newBuilder() + .setPrincipal("auth.acme.com:12350/serviceAccount:delegate@acme.co") + .addAudiences("my-project") + .setClaims( + Struct.newBuilder() + .putAllFields( + ImmutableMap.of( + "sub", newStringValue("serviceAccount:delegate@acme.co"), + "aud", newStringValue("my-project"), + "iss", newStringValue("auth.acme.com:12350"))) + .putFields( + "extra_claims", + Value.newBuilder() + .setStructValue( + Struct.newBuilder() + .putFields("group", newStringValue("admin")) + .build()) + .build()))) + .build(); + + // Compile the `Request` message construction expression and validate that + // the resulting expression type matches the fully qualified message name. + CelAbstractSyntaxTree ast = exercise6.compile(expression); + AttributeContext.Request evaluatedResult = + (AttributeContext.Request) + exercise6.eval( + ast, + ImmutableMap.of( + "now", now, + "jwt", jwt)); + + assertThat(evaluatedResult).isEqualTo(expectedMessage); +} +``` + +Run the test: + +```sh +bazel test --test_output=errors //codelab/src/test/codelab:Exercise6Test +``` + +You should see the following error: + +``` +There was 1 failure: +1) evaluate_constructAttributeContext(codelab.Exercise6Test) +java.lang.IllegalArgumentException: Failed to compile expression. + at codelab.Exercise6.compile(Exercise6.java:42) + at codelab.Exercise6Test.evaluate_constructAttributeContext(Exercise6Test.java:72) + ... 26 trimmed +Caused by: dev.cel.common.CelValidationException: ERROR: :1:8: undeclared reference to 'Request' (in container '') + | Request{ + | .......^ +... and many more ... +``` + +The container is basically the equivalent of a namespace or package, but can +even be as granular as a protobuf message name. CEL containers use the same +namespace resolution rules as [Protobuf and C++][27] for determining where a +given variable, function, or type name is declared. + +Given the container `google.rpc.context.AttributeContext` the type-checker and +the evaluator will try the following identifier names for all variables, types, +and functions: + +* `google.rpc.context.AttributeContext.` +* `google.rpc.context.` +* `google.rpc.` +* `google.` +* `` + +For absolute names, prefix the variable, type, or function reference with a +leading dot `.`. In the example, the expression `.` will only search for the +top-level `` identifier without first checking within the container. + +Try specifying the `.setContainer("google.rpc.context.AttributeContext")` option +to the compiler environment then run the test again: + +```java +CelAbstractSyntaxTree compile(String expression) { + CelCompiler celCompiler = + CelCompilerFactory.standardCelCompilerBuilder() + .setContainer("google.rpc.context.AttributeContext") + // Declare variables for "jwt" and "now" here + .addMessageTypes(Request.getDescriptor()) + .setResultType(StructTypeReference.create(Request.getDescriptor().getFullName())) + .build(); + ... +} +``` + +``` +There was 1 failure: +1) evaluate_constructAttributeContext(codelab.Exercise6Test) +... +Caused by: dev.cel.common.CelValidationException: ERROR: :2:25: undeclared reference to 'jwt' (in container 'google.rpc.context.AttributeContext') + | auth: Auth{ principal: jwt.iss + '/' + jwt.sub, audiences: [jwt.aud], presenter: 'azp' in jwt ? jwt.azp : '', claims: jwt},time: now} + | ........................^ +... and many more ... +``` + +We're making progress. Declare the `jwt` and `now` variables: + +```java +CelAbstractSyntaxTree compile(String expression) { + CelCompiler celCompiler = + CelCompilerFactory.standardCelCompilerBuilder() + .setContainer("google.rpc.context.AttributeContext") + .addVar("jwt", SimpleType.DYN) + .addVar("now", SimpleType.TIMESTAMP) + .addMessageTypes(Request.getDescriptor()) + .setResultType(StructTypeReference.create(Request.getDescriptor().getFullName())) + .build(); + ... +} +``` + +The test should pass now. + +> [!NOTE] +> Additional considerations for using CEL to build protos: +> +> 1. There is no native support for the conditional assignment for `oneof` +> fields. +> 2. There are issues round-tripping to / from a `google.protobuf.Any`. +> +> When a `oneof` needs to be set, test whether the desired value is present before +> constructing the message, or extend CEL to include a custom object building +> function such as a [`wither`](https://crates.io/crates/withers_derive#the-wither-pattern) +> method, or perhaps something more abstract. +> +> When an `Any` contains a wrapper type such as `google.protobuf.IntValue`, CEL +> automatically unpacks the `Any` to `int` or `null_type` depending on the +> contents. In the case where the wrapper type is unset, the `null` could not be +> assigned to an `Any` field and have its same original meaning. So far, this is +> the only roundtripping issue we have discovered, but it's worth noting. + +## Macros + +Macros can be used to manipulate the CEL program at parse time. Macros match a +call signature and manipulate the input call and its arguments in order to +produce a new subexpression AST. + +Macros can be used to implement complex logic in the AST that can't be written +directly in CEL. For example, the `has` macro enables field presence testing. +The comprehension macros such as `exists` and `all` replace a function call with +bounded iteration over an input list or map. Neither concept is possible at a +syntactic level, but they are possible through macro expansions. + +Have a look at the test case in `Exercise7Test.java` first: + +```java +@Test +public void evaluate_checkJwtClaimsWithMacro_evaluatesToTrue() { + String expression = + "jwt.extra_claims.exists(c, c.startsWith('group'))" + + " && jwt.extra_claims" + + ".filter(c, c.startsWith('group'))" + + ".all(c, jwt.extra_claims[c]" + + ".all(g, g.endsWith('@acme.co')))"; + ImmutableMap jwt = + ImmutableMap.of( + "sub", + "serviceAccount:delegate@acme.co", + "aud", + "my-project", + "iss", + "auth.acme.com:12350", + "extra_claims", + ImmutableMap.of("group1", ImmutableList.of("admin@acme.co", "analyst@acme.co")), + "labels", + ImmutableList.of("metadata", "prod", "pii"), + "groupN", + ImmutableList.of("forever@acme.co")); + CelAbstractSyntaxTree ast = exercise7.compile(expression); + + // Evaluate a complex-ish JWT with two groups that satisfy the criteria. + // Output: true. + boolean evaluatedResult = (boolean) exercise7.eval(ast, ImmutableMap.of("jwt", jwt)); + + assertThat(evaluatedResult).isTrue(); +} +``` + +Run the test: + +```sh +bazel test --test_output=errors //codelab/src/test/codelab:Exercise7Test +``` + +You should see the following error: + +``` +There was 1 failure: +1) evaluate_checkJwtClaimsWithMacro_evaluatesToTrue(codelab.Exercise7Test) +java.lang.IllegalArgumentException: Failed to compile expression. + at codelab.Exercise7.compile(Exercise7.java:40) + at codelab.Exercise7Test.evaluate_checkJwtClaimsWithMacro_evaluatesToTrue(Exercise7Test.java:52) + ... 26 trimmed +Caused by: dev.cel.common.CelValidationException: ERROR: :1:24: undeclared reference to 'exists' (in container '') + | jwt.extra_claims.exists(c, c.startsWith('group')) && jwt.extra_claims.filter(c, c.startsWith('group')).all(c, jwt.extra_claims[c].all(g, g.endsWith('@acme.co'))) + | .......................^ +... and many more ... +``` + +Specify the option `setStandardMacros` with `CelStandardMacro.ALL`, +`CelStandardMacro.FILTER`, and `CelStandardMacro.EXISTS` as arguments: + +```java +CelAbstractSyntaxTree compile(String expression) { + CelCompiler celCompiler = + CelCompilerFactory.standardCelCompilerBuilder() + .addVar("jwt", SimpleType.DYN) + .setStandardMacros( + CelStandardMacro.ALL, CelStandardMacro.FILTER, CelStandardMacro.EXISTS) + .setResultType(SimpleType.BOOL) + .build(); + ... +} +``` + +Run the test again to confirm that it passes. + +These are the currently supported macros: + +| Macro | Signature | Description | +| ------------ | ------------------------- | --------------------------------- | +| `all` | `r.all(var, cond)` | Test if `cond` evaluates `true` for *all* `var` in range `r`. +| `exists` | `r.exists(var, cond)` | Test if `cond` evaluates `true` for *any* `var` in range `r`. +| `exists_one` | `r.exists_one(var, cond)` | Test if `cond` evaluates `true` for *only one* `var` in range `r`. +| `filter` | `r.filter(var, cond)` | For lists, create a new list where each element `var` in range `r` satisfies the condition `cond`. For maps, create a new list where each key `var` in range `r` satisfies the condition `cond`. +| `map` | `r.map(var, expr)` | Create a new list where each each `var` in range `r` is transformed by `expr`. +| | `r.map(var, cond, expr)` | Same as two-arg `map` but with a conditional `cond` filter before the value is transformed. +| `has` | `has(a.b)` | Presence test for `b` on value `a` \: For maps, json tests definition. For protos, tests non-default primitive value or a or a set message field. + +When the range `r` argument is a `map` type, the `var` will be the map key, and +for `list` type values the `var` will be the list element value. The `all`, +`exists`, `exists_one`, `filter`, and `map` macros perform an AST rewrite that +does for-each iteration which is bounded by the size of the input. + +The bounded comprehensions ensure that CEL programs won't be Turing-complete, +but they evaluate in super-linear time with respect to the input. Use these +macros sparingly or not at all. Heavy use of comprehensions usually a good +indicator that a custom function would provide a better user experience and +better performance. + +> [!TIP] +> Best practice: `CelStandardMacro.STANDARD_MACROS` enables all listed macros, but +it's safer to explicitly enable only the required ones for your use case. + +## Static AST Validators and Optimizers + +CEL can perform complex validations on a compiled AST beyond what the +type-checker is capable of. CEL can also enhance evaluation efficiency through +AST optimizations such as constant folding and common subexpression elimination. +We will explore the use of canonical CEL validators and optimizers available. + +> [!NOTE] +> Note: Both validation and optimization require a type-checked AST. + +> [!CAUTION] +> AST validation and optimization should not be done in latency critical +code paths, similar to parsing and type-checking. + +### Validators + +Inspect the first three test cases in `Exercise8Test.java`: + +```java +@Test +public void validate_invalidTimestampLiteral_returnsError() throws Exception { + CelAbstractSyntaxTree ast = exercise8.compile("timestamp('bad')"); + + CelValidationResult validationResult = exercise8.validate(ast); + + assertThat(validationResult.hasError()).isTrue(); + assertThat(validationResult.getErrorString()) + .isEqualTo( + "ERROR: :1:11: timestamp validation failed. Reason: evaluation error: Failed to" + + " parse timestamp: invalid timestamp \"bad\"\n" + + " | timestamp('bad')\n" + + " | ..........^"); +} + +@Test +public void validate_invalidDurationLiteral_returnsError() throws Exception { + CelAbstractSyntaxTree ast = exercise8.compile("duration('bad')"); + + CelValidationResult validationResult = exercise8.validate(ast); + + assertThat(validationResult.hasError()).isTrue(); + assertThat(validationResult.getErrorString()) + .isEqualTo( + "ERROR: :1:10: duration validation failed. Reason: evaluation error: invalid" + + " duration format\n" + + " | duration('bad')\n" + + " | .........^"); +} + +@Test +public void validate_invalidRegexLiteral_returnsError() throws Exception { + CelAbstractSyntaxTree ast = exercise8.compile("'text'.matches('**')"); + + CelValidationResult validationResult = exercise8.validate(ast); + + assertThat(validationResult.hasError()).isTrue(); + assertThat(validationResult.getErrorString()) + .isEqualTo( + "ERROR: :1:16: Regex validation failed. Reason: Dangling meta character '*' near" + + " index 0\n" + + "**\n" + + "^\n" + + " | 'text'.matches('**')\n" + + " | ...............^"); +} +``` + +Note that all three test cases contain an expression with invalid literals +that would fail if evaluated. + +Run the validator tests (note the `--test_filter` flag): + +```sh +bazel test --test_output=errors --test_filter=validate //codelab/src/test/codelab:Exercise8Test +``` + + +You should see 4 tests failing: + +``` +There were 4 failures: +1) validate_invalidTimestampLiteral_returnsError(codelab.Exercise8Test) +... and more +FAILURES!!! +Tests run: 4, Failures: 4 +``` + +Setting up a validator requires an instance of a compiler and a runtime. These +have been provided for you out of convenience in `Exercise8.java`: + +```java +private static final CelCompiler CEL_COMPILER = + CelCompilerFactory.standardCelCompilerBuilder() + .addVar("x", SimpleType.INT) + .addVar( + "request", StructTypeReference.create("google.rpc.context.AttributeContext.Request")) + .addMessageTypes(AttributeContext.Request.getDescriptor()) + .build(); +private static final CelRuntime CEL_RUNTIME = + CelRuntimeFactory.standardCelRuntimeBuilder() + .addMessageTypes(AttributeContext.Request.getDescriptor()) + .build(); +``` + +Copy and paste the following, below where the runtime is declared: + +```java +// Just like the compiler and runtime, the validator and optimizer can be statically +// initialized as their instances are immutable. +private static final CelValidator CEL_VALIDATOR = + CelValidatorFactory.standardCelValidatorBuilder(CEL_COMPILER, CEL_RUNTIME) + .build(); +``` + +Next, replace the implementation of `validate` method with the following code: + +```java +/** Validates a type-checked AST. */ +CelValidationResult validate(CelAbstractSyntaxTree checkedAst) { + return CEL_VALIDATOR.validate(checkedAst); +} +``` + +Re-run the tests. The tests no longer throws an exception, but they still fail +because we aren't actually validating anything at the moment: + +``` +1) validate_invalidTimestampLiteral_returnsError(codelab.Exercise8Test) +value of: hasError() +expected to be true + at codelab.Exercise8Test.validate_invalidTimestampLiteral_returnsError(Exercise8Test.java:28) +... and more +``` + +We now need to register the individual AST validators. Add the literal +validators for timestamp, duration and regular expressions through +`.addAstValidators` builder method: + +```java +private static final CelValidator CEL_VALIDATOR = + CelValidatorFactory.standardCelValidatorBuilder(CEL_COMPILER, CEL_RUNTIME) + .addAstValidators( + TimestampLiteralValidator.INSTANCE, + DurationLiteralValidator.INSTANCE, + RegexLiteralValidator.INSTANCE) + .build(); +``` + +Re-run the test. You should observe that the first three literal validation +tests pass. + +There is one more test remaining to be fixed: + +```java +@Test +public void validate_listHasMixedLiterals_throws() throws Exception { + CelAbstractSyntaxTree ast = exercise8.compile("3 in [1, 2, '3']"); + + // Note that `CelValidationResult` is the same result class used for the compilation path. This + // means you could alternatively invoke `.getAst()` and handle `CelValidationException` as + // usual. + CelValidationResult validationResult = exercise8.validate(ast); + + CelValidationException e = assertThrows(CelValidationException.class, validationResult::getAst); + assertThat(e) + .hasMessageThat() + .contains( + "ERROR: :1:13: expected type 'int' but found 'string'\n" + + " | 3 in [1, 2, '3']\n" + + " | ............^"); +} +``` + +CEL offers a validator to catch literals with mixed types in lists or maps. +For example, `3 in [1, 2, "3"]` is a perfectly valid expression in CEL but +likely unintended as this would evaluate to false. + +Add `HomogeneousLiteralValidator.newInstance()` then rerun the tests to confirm +that all tests pass: + +```java +// Just like the compiler and runtime, the validator and optimizer can be statically +// initialized as their instances are immutable. +private static final CelValidator CEL_VALIDATOR = + CelValidatorFactory.standardCelValidatorBuilder(CEL_COMPILER, CEL_RUNTIME) + .addAstValidators( + TimestampLiteralValidator.INSTANCE, + DurationLiteralValidator.INSTANCE, + RegexLiteralValidator.INSTANCE, + HomogeneousLiteralValidator.newInstance()) + .build(); +``` + +### Optimizers + +Human authored expressions often contain redundancies that may cause suboptimal +evaluation. In such cases, optimization is highly beneficial if the ASTs will be +repeatedly evaluated. Conversely, there is little point in optimizing an AST if +it will be evaluated once. + +We first look at a classic compiler optimization known as constant folding. Have +a look at the relevant test: + +```java +@Test +public void optimize_constantFold_success() throws Exception { + CelUnparser celUnparser = CelUnparserFactory.newUnparser(); + CelAbstractSyntaxTree ast = exercise8.compile("(1 + 2 + 3 == x) && (x in [1, 2, x])"); + + CelAbstractSyntaxTree optimizedAst = exercise8.optimize(ast); + + assertThat(celUnparser.unparse(optimizedAst)).isEqualTo("6 == x"); +} +``` + +> [!NOTE] +> Note: Unparser can be used to convert an AST into its textual representation. +In this exercise, it's used to verify the result of an AST optimization. + +Constant folding will take all arithmetic expression containing only constant +values, computes the expression then replaces with the result. It will also +prune any branches of the expression that can be removed without affecting the +correctness (akin to dead-code elimination). + +Run the optimizer tests (note the `--test_filter` flag): + +```sh +bazel test --test_output=errors --test_filter=optimize //codelab/src/test/codelab:Exercise8Test +``` + +You should see 3 tests failing: + +``` +There were 3 failures: +1) optimize_commonSubexpressionElimination_success(codelab.Exercise8Test) +... and more +FAILURES!!! +Tests run: 3, Failures: 3 +``` + +Similar to how the validator was setup, the optimizer requires both the compiler +and runtime instances. Copy and paste the following into `Exercise8.java`: + +```java +private static final CelOptimizer CEL_OPTIMIZER = + CelOptimizerFactory.standardCelOptimizerBuilder(CEL_COMPILER, CEL_RUNTIME) + .build(); +``` + +Then change the code in `optimize` method as: + +```java +/** + * Optimizes a type-checked AST. + * + * @throws CelOptimizationException If the optimization fails. + */ +CelAbstractSyntaxTree optimize(CelAbstractSyntaxTree checkedAst) throws CelOptimizationException { + return CEL_OPTIMIZER.optimize(checkedAst); +} +``` + +Next, register `ConstantFoldingOptimizer` via `.addAstOptimizers`: + +```java +private static final CelOptimizer CEL_OPTIMIZER = + CelOptimizerFactory.standardCelOptimizerBuilder(CEL_COMPILER, CEL_RUNTIME) + .addAstOptimizers(ConstantFoldingOptimizer.getInstance()) + .build(); +``` + +Re-run the test. You should see 2 out of 3 tests passing now. + +Please note that optimization removes parsing metadata from the AST, as +modifications may cause it to deviate from the original expression. +Practically, this means the error message will no longer indicate the source +location as shown in the test below: + +```java +@Test +public void optimize_constantFold_evaluateError() throws Exception { + CelAbstractSyntaxTree ast = + exercise8.compile("request.headers.referer == 'https://' + 'cel.dev'"); + CelAbstractSyntaxTree optimizedAst = exercise8.optimize(ast); + ImmutableMap runtimeParameters = + ImmutableMap.of("request", AttributeContext.Request.getDefaultInstance()); + + CelEvaluationException e1 = + assertThrows(CelEvaluationException.class, () -> exercise8.eval(ast, runtimeParameters)); + CelEvaluationException e2 = + assertThrows( + CelEvaluationException.class, () -> exercise8.eval(optimizedAst, runtimeParameters)); + // Note that the errors below differ by their source position. + assertThat(e1) + .hasMessageThat() + .contains("evaluation error at :15: key 'referer' is not present in map."); + assertThat(e2) + .hasMessageThat() + .contains("evaluation error at :0: key 'referer' is not present in map."); +} +``` + +The second optimization technique to cover is Common Subexpression Elimination +(CSE). It will replace instances of identical expressions to a single variable +holding the computed value. + +Have a look at the following test and note the expression containing duplicate field +selections `request.auth.claims.group`: + +```java +@Test +public void optimize_commonSubexpressionElimination_success() throws Exception { + CelUnparser celUnparser = CelUnparserFactory.newUnparser(); + CelAbstractSyntaxTree ast = + exercise8.compile( + "request.auth.claims.group == 'admin' || request.auth.claims.group == 'user'"); + + CelAbstractSyntaxTree optimizedAst = exercise8.optimize(ast); + + assertThat(celUnparser.unparse(optimizedAst)) + .isEqualTo( + "cel.@block([request.auth.claims.group], @index0 == \"admin\" || @index0 == \"user\")"); +} +``` + +CSE will rewrite this expression using a specialized internal function +`cel.@block`. The first argument contain a list duplicate subexpressions +and the second argument is the rewritten result expression that is semantically +the same as the original expression. The subexpressions are lazily evaluated and +memoized when accessed by index (e.g: `@index0`). + +Make the following changes in `Exercise8.java`: + +```java +private static final CelOptimizer CEL_OPTIMIZER = + CelOptimizerFactory.standardCelOptimizerBuilder(CEL_COMPILER, CEL_RUNTIME) + .addAstOptimizers( + ConstantFoldingOptimizer.getInstance(), + SubexpressionOptimizer.newInstance( + SubexpressionOptimizerOptions.newBuilder().enableCelBlock(true).build())) + .build(); +``` + +As seen here, the usage of `cel.block` must explicitly be enabled as it is +only supported in CEL-Java as of now. Disabling `cel.block` will instead rewrite +the AST using cascaded `cel.bind` macros. Prefer using the block format if +possible as it is a more efficient format for evaluation. + +> [!CAUTION] +> You MUST disable `cel.block` if you are targeting `cel-go` or `cel-cpp` for the runtime until its support has been added in those stacks. + +Re-run the tests to confirm that they pass. + +## Custom AST Validation + +As seen in the earlier exercise, CEL offers many built-in validators. There +are however situations where authoring a custom AST validator is beneficial to +improve user experience by providing context-specific feedback. + +We'll be writing a validator to ensure that `AttributeContext.Request` message +is well formatted. Have a look at the test case: + +```java +@Test +public void validate_invalidHttpMethod_returnsError() throws Exception { + String expression = + "google.rpc.context.AttributeContext.Request { \n" + + "scheme: 'http', " + + "method: 'GETTT', " // method is misspelled. + + "host: 'cel.dev' \n" + + "}"; + CelAbstractSyntaxTree ast = exercise9.compile(expression); + + CelValidationResult validationResult = exercise9.validate(ast); + + assertThat(validationResult.hasError()).isTrue(); + assertThat(validationResult.getErrorString()) + .isEqualTo( + "ERROR: :2:25: GETTT is not an allowed HTTP method.\n" + + " | scheme: 'http', method: 'GETTT', host: 'cel.dev' \n" + + " | ........................^"); + assertThrows(CelValidationException.class, validationResult::getAst); +} +``` + +Run the test: + +```sh +bazel test --test_output=errors //codelab/src/test/codelab:Exercise9Test +``` + +You should see all three tests failing: + +``` +There were 3 failures: +1) validate_invalidHttpMethod_returnsError(codelab.Exercise9Test) +... and more +FAILURES!!! +Tests run: 3, Failures: 3 +``` + +The first step in writing a custom AST validator is to have a class implement +the `CelAstValidator` interface. In `Exercise9.java`, make the +following changes: + +```java +static final class AttributeContextRequestValidator implements CelAstValidator { + @Override + public void validate(CelNavigableAst navigableAst, Cel cel, IssuesFactory issuesFactory) { + // Implement validate method here + } +} +``` + +We need a way to fetch then inspect the expression nodes of interest. For this, +CEL provides fluent APIs to navigate a compiled AST via navigable expressions. +A `CelNavigableExpr` allows you to traverse through its descendants or parent +with ease. + +Let's write some logic to filter for expressions containing +`google.rpc.context.AttributeContext.Request` message name. Copy and paste the +following: + +```java +@Override +public void validate(CelNavigableAst navigableAst, Cel cel, IssuesFactory issuesFactory) { + navigableAst + .getRoot() + .allNodes() + .filter(node -> node.getKind().equals(Kind.STRUCT)) + .map(node -> node.expr().struct()) + .filter( + struct -> struct.messageName().equals("google.rpc.context.AttributeContext.Request")) +} +``` + +> [!TIP] +> Call `.toString()` on a `CelExpr` object to obtain a human-readable format +of the AST. + +Next, we'll iterate through the fields of the message to confirm that it has +the correct HTTP method. Otherwise, we'll add it as an error through +`IssuesFactory`. Copy and paste the rest of the code: + +```java +static final class AttributeContextRequestValidator implements CelAstValidator { + private static final ImmutableSet ALLOWED_HTTP_METHODS = + ImmutableSet.of("GET", "POST", "PUT", "DELETE"); + + @Override + public void validate(CelNavigableAst navigableAst, Cel cel, IssuesFactory issuesFactory) { + navigableAst + .getRoot() + .allNodes() + .filter(node -> node.getKind().equals(Kind.STRUCT)) + .map(node -> node.expr().struct()) + .filter( + struct -> struct.messageName().equals("google.rpc.context.AttributeContext.Request")) + .forEach( + struct -> { + for (CelStruct.Entry entry : struct.entries()) { + String fieldKey = entry.fieldKey(); + if (fieldKey.equals("method")) { + String entryStringValue = getStringValue(entry.value()); + if (!ALLOWED_HTTP_METHODS.contains(entryStringValue)) { + issuesFactory.addError( + entry.value().id(), entryStringValue + " is not an allowed HTTP method."); + } + } + } + }); + } + + /** + * Reads the underlying string value from the expression. + * + * @throws UnsupportedOperationException if the expression is not a constant string value. + */ + private static String getStringValue(CelExpr celExpr) { + return celExpr.constant().stringValue(); + } +} +``` + +Register the custom validator via `.addAstValidators`: + +```java +private static final CelValidator CEL_VALIDATOR = + CelValidatorFactory.standardCelValidatorBuilder(CEL_COMPILER, CEL_RUNTIME) + .addAstValidators(new AttributeContextRequestValidator()) + .build(); +``` + +Run the test again and confirm that the first test case passes. + +Let's look at the next test: + +```java +@Test +public void validate_schemeIsHttp_returnsWarning() throws Exception { + String expression = + "google.rpc.context.AttributeContext.Request { \n" + + "scheme: 'http', " // https is preferred but not required. + + "method: 'GET', " + + "host: 'cel.dev' \n" + + "}"; + CelAbstractSyntaxTree ast = exercise9.compile(expression); + + CelValidationResult validationResult = exercise9.validate(ast); + + assertThat(validationResult.hasError()).isFalse(); + assertThat(validationResult.getIssueString()) + .isEqualTo( + "WARNING: :2:9: Prefer using https for safety.\n" + + " | scheme: 'http', method: 'GET', host: 'cel.dev' \n" + + " | ........^"); + // Because the validation result does not contain any errors, you can still evaluate it. + assertThat(exercise9.eval(validationResult.getAst())) + .isEqualTo( + AttributeContext.Request.newBuilder() + .setScheme("http") + .setMethod("GET") + .setHost("cel.dev") + .build()); +} +``` + +A validator does not necessarily have to produce a pass/fail outcome. It can +instead provide informational feedbacks or warnings. This is useful when an +expression has no correctness issue, but can be improved based on the +application context. Linting is a good example of this. + +Make the following changes to produce a warning when `https` is not used as the +scheme: + +```java +@Override +public void validate(CelNavigableAst navigableAst, Cel cel, IssuesFactory issuesFactory) { + navigableAst + .getRoot() + .allNodes() + .filter(node -> node.getKind().equals(Kind.STRUCT)) + .map(node -> node.expr().struct()) + .filter( + struct -> struct.messageName().equals("google.rpc.context.AttributeContext.Request")) + .forEach( + struct -> { + for (CelStruct.Entry entry : struct.entries()) { + String fieldKey = entry.fieldKey(); + if (fieldKey.equals("method")) { + String entryStringValue = getStringValue(entry.value()); + if (!ALLOWED_HTTP_METHODS.contains(entryStringValue)) { + issuesFactory.addError( + entry.value().id(), entryStringValue + " is not an allowed HTTP method."); + } + } else if (fieldKey.equals("scheme")) { + String entryStringValue = getStringValue(entry.value()); + if (!entryStringValue.equals("https")) { + issuesFactory.addWarning( + entry.value().id(), "Prefer using https for safety."); + } + } + } + }); +} +``` + +Re-run to confirm that the first two tests pass. + +Another common need is to restrict the use of an expensive function call in an +unsafe manner. Suppose we have a function that issues an RPC. We'll write a +validator to ensure that it can't be used within a macro to prevent repeated +invocations within an expression. + +Inspect the test case: + +```java +@Test +public void validate_isPrimeNumberWithinMacro_returnsError() throws Exception { + String expression = "[2,3,5].all(x, is_prime_number(x))"; + CelAbstractSyntaxTree ast = exercise9.compile(expression); + + CelValidationResult validationResult = exercise9.validate(ast); + + assertThat(validationResult.hasError()).isTrue(); + assertThat(validationResult.getErrorString()) + .isEqualTo( + "ERROR: :1:12: is_prime_number function cannot be used within CEL macros.\n" + + " | [2,3,5].all(x, is_prime_number(x))\n" + + " | ...........^"); +} +``` + +Then copy and paste the following into `ComprehensionSafetyValidator` in `Exercise9.java`: + +```java +/** Prevents nesting an expensive function call within a macro. */ +static final class ComprehensionSafetyValidator implements CelAstValidator { + private static final String EXPENSIVE_FUNCTION_NAME = "is_prime_number"; + + @Override + public void validate(CelNavigableAst navigableAst, Cel cel, IssuesFactory issuesFactory) { + navigableAst + .getRoot() + .allNodes() + .filter(node -> node.getKind().equals(Kind.COMPREHENSION)) + .forEach( + comprehensionNode -> { + boolean isFunctionWithinMacro = + comprehensionNode + .descendants() + .anyMatch( + node -> + node.expr() + .callOrDefault() + .function() + .equals(EXPENSIVE_FUNCTION_NAME)); + if (isFunctionWithinMacro) { + issuesFactory.addError( + comprehensionNode.id(), + EXPENSIVE_FUNCTION_NAME + " function cannot be used within CEL macros."); + } + }); + } +} +``` + +> [!NOTE] +> This doesn't stop the expression author from simply chaining the calls together outside the macro (e.g: `is_prime_number(2) && is_prime_number(3) ...)`. One could easily introduce a validator to catch these cases too if desired. + +> [!TIP] +> Use `(kind)OrDefault` to consolidate checking for the expression kind and the retrieval of the underlying expression for brevity. `callOrDefault` here is an example. + +Finally, register the custom validator: + +```java +private static final CelValidator CEL_VALIDATOR = + CelValidatorFactory.standardCelValidatorBuilder(CEL_COMPILER, CEL_RUNTIME) + .addAstValidators( + new AttributeContextRequestValidator(), + new ComprehensionSafetyValidator()) + .build(); +``` + +Re-run the test to confirm that all tests pass. From 62aae63503eba585f27883c1f6f38ed1b6421705 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Tue, 28 May 2024 09:44:02 -0700 Subject: [PATCH 125/486] Support evaluation of dynamic messages constructed via dynamic descriptors Closes https://github.com/google/cel-java/issues/350 PiperOrigin-RevId: 637930690 --- common/resources/testdata/proto3/BUILD.bazel | 5 + .../dev/cel/common/internal/ProtoAdapter.java | 28 +- .../common/values/ProtoCelValueConverter.java | 24 +- .../resources/testdata/proto3/BUILD.bazel | 5 + .../testdata/proto3/test_all_types.fds | 871 ++++++++++++++++++ ...seline => dynamicMessage_adapted.baseline} | 0 .../dynamicMessage_dynamicDescriptor.baseline | 222 +++++ .../src/main/java/dev/cel/testing/BUILD.bazel | 6 +- .../dev/cel/testing/BaseInterpreterTest.java | 152 ++- 9 files changed, 1302 insertions(+), 11 deletions(-) create mode 100644 common/src/main/resources/testdata/proto3/test_all_types.fds rename runtime/src/test/resources/{dynamicMessage.baseline => dynamicMessage_adapted.baseline} (100%) create mode 100644 runtime/src/test/resources/dynamicMessage_dynamicDescriptor.baseline diff --git a/common/resources/testdata/proto3/BUILD.bazel b/common/resources/testdata/proto3/BUILD.bazel index f094fbdb6..38b92096c 100644 --- a/common/resources/testdata/proto3/BUILD.bazel +++ b/common/resources/testdata/proto3/BUILD.bazel @@ -4,6 +4,11 @@ package( default_visibility = ["//visibility:public"], ) +alias( + name = "test_all_types_file_descriptor_set", + actual = "//common/src/main/resources/testdata/proto3:test_all_types_file_descriptor_set", +) + alias( name = "test_all_types_java_proto", actual = "//common/src/main/resources/testdata/proto3:test_all_types_java_proto", diff --git a/common/src/main/java/dev/cel/common/internal/ProtoAdapter.java b/common/src/main/java/dev/cel/common/internal/ProtoAdapter.java index e4b12f841..b63825dc4 100644 --- a/common/src/main/java/dev/cel/common/internal/ProtoAdapter.java +++ b/common/src/main/java/dev/cel/common/internal/ProtoAdapter.java @@ -210,14 +210,32 @@ public Optional adaptFieldToValue(FieldDescriptor fieldDescriptor, Objec } if (fieldDescriptor.isMapField()) { Descriptor entryDescriptor = fieldDescriptor.getMessageType(); - BidiConverter keyConverter = fieldToValueConverter(entryDescriptor.findFieldByNumber(1)); - BidiConverter valueConverter = fieldToValueConverter(entryDescriptor.findFieldByNumber(2)); + FieldDescriptor keyFieldDescriptor = entryDescriptor.findFieldByNumber(1); + FieldDescriptor valueFieldDescriptor = entryDescriptor.findFieldByNumber(2); + BidiConverter keyConverter = fieldToValueConverter(keyFieldDescriptor); + BidiConverter valueConverter = fieldToValueConverter(valueFieldDescriptor); + Map map = new HashMap<>(); - for (MapEntry entry : ((List) fieldValue)) { + Object mapKey; + Object mapValue; + for (Object entry : ((List) fieldValue)) { + if (entry instanceof MapEntry) { + MapEntry mapEntry = (MapEntry) entry; + mapKey = mapEntry.getKey(); + mapValue = mapEntry.getValue(); + } else if (entry instanceof DynamicMessage) { + DynamicMessage dynamicMessage = (DynamicMessage) entry; + mapKey = dynamicMessage.getField(keyFieldDescriptor); + mapValue = dynamicMessage.getField(valueFieldDescriptor); + } else { + throw new IllegalStateException("Unexpected map field type: " + entry); + } + map.put( - keyConverter.forwardConverter().convert(entry.getKey()), - valueConverter.forwardConverter().convert(entry.getValue())); + keyConverter.forwardConverter().convert(mapKey), + valueConverter.forwardConverter().convert(mapValue)); } + return Optional.of(map); } if (fieldDescriptor.isRepeated()) { diff --git a/common/src/main/java/dev/cel/common/values/ProtoCelValueConverter.java b/common/src/main/java/dev/cel/common/values/ProtoCelValueConverter.java index cafa399f8..152adbffb 100644 --- a/common/src/main/java/dev/cel/common/values/ProtoCelValueConverter.java +++ b/common/src/main/java/dev/cel/common/values/ProtoCelValueConverter.java @@ -186,7 +186,7 @@ public CelValue fromJavaObjectToCelValue(Object value) { } /** Adapts the protobuf message field into {@link CelValue}. */ - @SuppressWarnings("unchecked") + @SuppressWarnings({"unchecked", "rawtypes"}) public CelValue fromProtoMessageFieldToCelValue( Message message, FieldDescriptor fieldDescriptor) { Preconditions.checkNotNull(message); @@ -202,8 +202,26 @@ public CelValue fromProtoMessageFieldToCelValue( return NullValue.NULL_VALUE; } else if (fieldDescriptor.isMapField()) { Map map = new HashMap<>(); - for (MapEntry entry : ((List>) result)) { - map.put(entry.getKey(), entry.getValue()); + Object mapKey; + Object mapValue; + for (Object entry : ((List) result)) { + if (entry instanceof MapEntry) { + MapEntry mapEntry = (MapEntry) entry; + mapKey = mapEntry.getKey(); + mapValue = mapEntry.getValue(); + } else if (entry instanceof DynamicMessage) { + DynamicMessage dynamicMessage = (DynamicMessage) entry; + FieldDescriptor keyFieldDescriptor = + fieldDescriptor.getMessageType().findFieldByNumber(1); + FieldDescriptor valueFieldDescriptor = + fieldDescriptor.getMessageType().findFieldByNumber(2); + mapKey = dynamicMessage.getField(keyFieldDescriptor); + mapValue = dynamicMessage.getField(valueFieldDescriptor); + } else { + throw new IllegalStateException("Unexpected map field type: " + entry); + } + + map.put(mapKey, mapValue); } return fromJavaObjectToCelValue(map); } diff --git a/common/src/main/resources/testdata/proto3/BUILD.bazel b/common/src/main/resources/testdata/proto3/BUILD.bazel index d76c8ae59..2230ee37a 100644 --- a/common/src/main/resources/testdata/proto3/BUILD.bazel +++ b/common/src/main/resources/testdata/proto3/BUILD.bazel @@ -8,6 +8,11 @@ package( ], ) +filegroup( + name = "test_all_types_file_descriptor_set", + srcs = ["test_all_types.fds"], +) + proto_library( name = "test_all_types_proto", srcs = [ diff --git a/common/src/main/resources/testdata/proto3/test_all_types.fds b/common/src/main/resources/testdata/proto3/test_all_types.fds new file mode 100644 index 000000000..5a2b9778c --- /dev/null +++ b/common/src/main/resources/testdata/proto3/test_all_types.fds @@ -0,0 +1,871 @@ +file { + name: "common/src/main/resources/testdata/proto3/test_all_types_serialized.proto" + package: "dev.cel.testing.testdata.serialized.proto3" + dependency: "google/protobuf/any.proto" + dependency: "google/protobuf/duration.proto" + dependency: "google/protobuf/struct.proto" + dependency: "google/protobuf/timestamp.proto" + dependency: "google/protobuf/wrappers.proto" + message_type { + name: "TestAllTypes" + field { + name: "single_int32" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_INT32 + } + field { + name: "single_int64" + number: 2 + label: LABEL_OPTIONAL + type: TYPE_INT64 + } + field { + name: "single_uint32" + number: 3 + label: LABEL_OPTIONAL + type: TYPE_UINT32 + } + field { + name: "single_uint64" + number: 4 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + } + field { + name: "single_sint32" + number: 5 + label: LABEL_OPTIONAL + type: TYPE_SINT32 + } + field { + name: "single_sint64" + number: 6 + label: LABEL_OPTIONAL + type: TYPE_SINT64 + } + field { + name: "single_fixed32" + number: 7 + label: LABEL_OPTIONAL + type: TYPE_FIXED32 + } + field { + name: "single_fixed64" + number: 8 + label: LABEL_OPTIONAL + type: TYPE_FIXED64 + } + field { + name: "single_sfixed32" + number: 9 + label: LABEL_OPTIONAL + type: TYPE_SFIXED32 + } + field { + name: "single_sfixed64" + number: 10 + label: LABEL_OPTIONAL + type: TYPE_SFIXED64 + } + field { + name: "single_float" + number: 11 + label: LABEL_OPTIONAL + type: TYPE_FLOAT + } + field { + name: "single_double" + number: 12 + label: LABEL_OPTIONAL + type: TYPE_DOUBLE + } + field { + name: "single_bool" + number: 13 + label: LABEL_OPTIONAL + type: TYPE_BOOL + } + field { + name: "single_string" + number: 14 + label: LABEL_OPTIONAL + type: TYPE_STRING + } + field { + name: "single_bytes" + number: 15 + label: LABEL_OPTIONAL + type: TYPE_BYTES + } + field { + name: "optional_bool" + number: 16 + label: LABEL_OPTIONAL + type: TYPE_BOOL + oneof_index: 2 + proto3_optional: true + } + field { + name: "optional_string" + number: 17 + label: LABEL_OPTIONAL + type: TYPE_BOOL + oneof_index: 3 + proto3_optional: true + } + field { + name: "single_any" + number: 100 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".google.protobuf.Any" + } + field { + name: "single_duration" + number: 101 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".google.protobuf.Duration" + } + field { + name: "single_timestamp" + number: 102 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".google.protobuf.Timestamp" + } + field { + name: "single_struct" + number: 103 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".google.protobuf.Struct" + } + field { + name: "single_value" + number: 104 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".google.protobuf.Value" + } + field { + name: "single_int64_wrapper" + number: 105 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".google.protobuf.Int64Value" + } + field { + name: "single_int32_wrapper" + number: 106 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".google.protobuf.Int32Value" + } + field { + name: "single_double_wrapper" + number: 107 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".google.protobuf.DoubleValue" + } + field { + name: "single_float_wrapper" + number: 108 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".google.protobuf.FloatValue" + } + field { + name: "single_uint64_wrapper" + number: 109 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".google.protobuf.UInt64Value" + } + field { + name: "single_uint32_wrapper" + number: 110 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".google.protobuf.UInt32Value" + } + field { + name: "single_string_wrapper" + number: 111 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".google.protobuf.StringValue" + } + field { + name: "single_bool_wrapper" + number: 112 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".google.protobuf.BoolValue" + } + field { + name: "single_bytes_wrapper" + number: 113 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".google.protobuf.BytesValue" + } + field { + name: "single_list_value" + number: 114 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".google.protobuf.ListValue" + } + field { + name: "single_nested_message" + number: 21 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".dev.cel.testing.testdata.serialized.proto3.TestAllTypes.NestedMessage" + oneof_index: 0 + } + field { + name: "single_nested_enum" + number: 22 + label: LABEL_OPTIONAL + type: TYPE_ENUM + type_name: ".dev.cel.testing.testdata.serialized.proto3.TestAllTypes.NestedEnum" + oneof_index: 0 + } + field { + name: "standalone_message" + number: 23 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".dev.cel.testing.testdata.serialized.proto3.TestAllTypes.NestedMessage" + } + field { + name: "standalone_enum" + number: 24 + label: LABEL_OPTIONAL + type: TYPE_ENUM + type_name: ".dev.cel.testing.testdata.serialized.proto3.TestAllTypes.NestedEnum" + } + field { + name: "repeated_int32" + number: 31 + label: LABEL_REPEATED + type: TYPE_INT32 + } + field { + name: "repeated_int64" + number: 32 + label: LABEL_REPEATED + type: TYPE_INT64 + } + field { + name: "repeated_uint32" + number: 33 + label: LABEL_REPEATED + type: TYPE_UINT32 + } + field { + name: "repeated_uint64" + number: 34 + label: LABEL_REPEATED + type: TYPE_UINT64 + } + field { + name: "repeated_sint32" + number: 35 + label: LABEL_REPEATED + type: TYPE_SINT32 + } + field { + name: "repeated_sint64" + number: 36 + label: LABEL_REPEATED + type: TYPE_SINT64 + } + field { + name: "repeated_fixed32" + number: 37 + label: LABEL_REPEATED + type: TYPE_FIXED32 + } + field { + name: "repeated_fixed64" + number: 38 + label: LABEL_REPEATED + type: TYPE_FIXED64 + } + field { + name: "repeated_sfixed32" + number: 39 + label: LABEL_REPEATED + type: TYPE_SFIXED32 + } + field { + name: "repeated_sfixed64" + number: 40 + label: LABEL_REPEATED + type: TYPE_SFIXED64 + } + field { + name: "repeated_float" + number: 41 + label: LABEL_REPEATED + type: TYPE_FLOAT + } + field { + name: "repeated_double" + number: 42 + label: LABEL_REPEATED + type: TYPE_DOUBLE + } + field { + name: "repeated_bool" + number: 43 + label: LABEL_REPEATED + type: TYPE_BOOL + } + field { + name: "repeated_string" + number: 44 + label: LABEL_REPEATED + type: TYPE_STRING + } + field { + name: "repeated_bytes" + number: 45 + label: LABEL_REPEATED + type: TYPE_BYTES + } + field { + name: "repeated_nested_message" + number: 51 + label: LABEL_REPEATED + type: TYPE_MESSAGE + type_name: ".dev.cel.testing.testdata.serialized.proto3.TestAllTypes.NestedMessage" + } + field { + name: "repeated_nested_enum" + number: 52 + label: LABEL_REPEATED + type: TYPE_ENUM + type_name: ".dev.cel.testing.testdata.serialized.proto3.TestAllTypes.NestedEnum" + } + field { + name: "repeated_string_piece" + number: 53 + label: LABEL_REPEATED + type: TYPE_STRING + options { + ctype: STRING_PIECE + } + } + field { + name: "repeated_cord" + number: 54 + label: LABEL_REPEATED + type: TYPE_STRING + options { + ctype: CORD + } + } + field { + name: "repeated_lazy_message" + number: 55 + label: LABEL_REPEATED + type: TYPE_MESSAGE + type_name: ".dev.cel.testing.testdata.serialized.proto3.TestAllTypes.NestedMessage" + } + field { + name: "map_int32_int64" + number: 56 + label: LABEL_REPEATED + type: TYPE_MESSAGE + type_name: ".dev.cel.testing.testdata.serialized.proto3.TestAllTypes.MapInt32Int64Entry" + } + field { + name: "map_string_string" + number: 61 + label: LABEL_REPEATED + type: TYPE_MESSAGE + type_name: ".dev.cel.testing.testdata.serialized.proto3.TestAllTypes.MapStringStringEntry" + } + field { + name: "map_int64_nested_type" + number: 62 + label: LABEL_REPEATED + type: TYPE_MESSAGE + type_name: ".dev.cel.testing.testdata.serialized.proto3.TestAllTypes.MapInt64NestedTypeEntry" + } + field { + name: "oneof_type" + number: 63 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".dev.cel.testing.testdata.serialized.proto3.NestedTestAllTypes" + oneof_index: 1 + } + field { + name: "oneof_msg" + number: 64 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".dev.cel.testing.testdata.serialized.proto3.TestAllTypes.NestedMessage" + oneof_index: 1 + } + field { + name: "oneof_bool" + number: 65 + label: LABEL_OPTIONAL + type: TYPE_BOOL + oneof_index: 1 + } + nested_type { + name: "NestedMessage" + field { + name: "bb" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_INT32 + } + } + nested_type { + name: "MapInt32Int64Entry" + field { + name: "key" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_INT32 + } + field { + name: "value" + number: 2 + label: LABEL_OPTIONAL + type: TYPE_INT64 + } + options { + map_entry: true + } + } + nested_type { + name: "MapStringStringEntry" + field { + name: "key" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_STRING + } + field { + name: "value" + number: 2 + label: LABEL_OPTIONAL + type: TYPE_STRING + } + options { + map_entry: true + } + } + nested_type { + name: "MapInt64NestedTypeEntry" + field { + name: "key" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_INT64 + } + field { + name: "value" + number: 2 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".dev.cel.testing.testdata.serialized.proto3.NestedTestAllTypes" + } + options { + map_entry: true + } + } + enum_type { + name: "NestedEnum" + value { + name: "FOO" + number: 0 + } + value { + name: "BAR" + number: 1 + } + value { + name: "BAZ" + number: 2 + } + } + oneof_decl { + name: "nested_type" + } + oneof_decl { + name: "kind" + } + oneof_decl { + name: "_optional_bool" + } + oneof_decl { + name: "_optional_string" + } + } + message_type { + name: "NestedTestAllTypes" + field { + name: "child" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".dev.cel.testing.testdata.serialized.proto3.NestedTestAllTypes" + } + field { + name: "payload" + number: 2 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".dev.cel.testing.testdata.serialized.proto3.TestAllTypes" + } + } + enum_type { + name: "GlobalEnum" + value { + name: "GOO" + number: 0 + } + value { + name: "GAR" + number: 1 + } + value { + name: "GAZ" + number: 2 + } + } + options { + java_package: "dev.cel.testing.testdata.serialized.proto3" + java_outer_classname: "TestAllTypesProto" + } + syntax: "proto3" +} +file { + name: "google/protobuf/any.proto" + package: "google.protobuf" + message_type { + name: "Any" + field { + name: "type_url" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "typeUrl" + } + field { + name: "value" + number: 2 + label: LABEL_OPTIONAL + type: TYPE_BYTES + json_name: "value" + } + } + options { + java_package: "com.google.protobuf" + java_outer_classname: "AnyProto" + java_multiple_files: true + go_package: "google.golang.org/protobuf/types/known/anypb" + objc_class_prefix: "GPB" + csharp_namespace: "Google.Protobuf.WellKnownTypes" + } + syntax: "proto3" +} +file { + name: "google/protobuf/duration.proto" + package: "google.protobuf" + message_type { + name: "Duration" + field { + name: "seconds" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_INT64 + json_name: "seconds" + } + field { + name: "nanos" + number: 2 + label: LABEL_OPTIONAL + type: TYPE_INT32 + json_name: "nanos" + } + } + options { + java_package: "com.google.protobuf" + java_outer_classname: "DurationProto" + java_multiple_files: true + go_package: "google.golang.org/protobuf/types/known/durationpb" + cc_enable_arenas: true + objc_class_prefix: "GPB" + csharp_namespace: "Google.Protobuf.WellKnownTypes" + } + syntax: "proto3" +} +file { + name: "google/protobuf/struct.proto" + package: "google.protobuf" + message_type { + name: "Struct" + field { + name: "fields" + number: 1 + label: LABEL_REPEATED + type: TYPE_MESSAGE + type_name: ".google.protobuf.Struct.FieldsEntry" + json_name: "fields" + } + nested_type { + name: "FieldsEntry" + field { + name: "key" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "key" + } + field { + name: "value" + number: 2 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".google.protobuf.Value" + json_name: "value" + } + options { + map_entry: true + } + } + } + message_type { + name: "Value" + field { + name: "null_value" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_ENUM + type_name: ".google.protobuf.NullValue" + oneof_index: 0 + json_name: "nullValue" + } + field { + name: "number_value" + number: 2 + label: LABEL_OPTIONAL + type: TYPE_DOUBLE + oneof_index: 0 + json_name: "numberValue" + } + field { + name: "string_value" + number: 3 + label: LABEL_OPTIONAL + type: TYPE_STRING + oneof_index: 0 + json_name: "stringValue" + } + field { + name: "bool_value" + number: 4 + label: LABEL_OPTIONAL + type: TYPE_BOOL + oneof_index: 0 + json_name: "boolValue" + } + field { + name: "struct_value" + number: 5 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".google.protobuf.Struct" + oneof_index: 0 + json_name: "structValue" + } + field { + name: "list_value" + number: 6 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".google.protobuf.ListValue" + oneof_index: 0 + json_name: "listValue" + } + oneof_decl { + name: "kind" + } + } + message_type { + name: "ListValue" + field { + name: "values" + number: 1 + label: LABEL_REPEATED + type: TYPE_MESSAGE + type_name: ".google.protobuf.Value" + json_name: "values" + } + } + enum_type { + name: "NullValue" + value { + name: "NULL_VALUE" + number: 0 + } + } + options { + java_package: "com.google.protobuf" + java_outer_classname: "StructProto" + java_multiple_files: true + go_package: "google.golang.org/protobuf/types/known/structpb" + cc_enable_arenas: true + objc_class_prefix: "GPB" + csharp_namespace: "Google.Protobuf.WellKnownTypes" + } + syntax: "proto3" +} +file { + name: "google/protobuf/timestamp.proto" + package: "google.protobuf" + message_type { + name: "Timestamp" + field { + name: "seconds" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_INT64 + json_name: "seconds" + } + field { + name: "nanos" + number: 2 + label: LABEL_OPTIONAL + type: TYPE_INT32 + json_name: "nanos" + } + } + options { + java_package: "com.google.protobuf" + java_outer_classname: "TimestampProto" + java_multiple_files: true + go_package: "google.golang.org/protobuf/types/known/timestamppb" + cc_enable_arenas: true + objc_class_prefix: "GPB" + csharp_namespace: "Google.Protobuf.WellKnownTypes" + } + syntax: "proto3" +} +file { + name: "google/protobuf/wrappers.proto" + package: "google.protobuf" + message_type { + name: "DoubleValue" + field { + name: "value" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_DOUBLE + json_name: "value" + } + } + message_type { + name: "FloatValue" + field { + name: "value" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_FLOAT + json_name: "value" + } + } + message_type { + name: "Int64Value" + field { + name: "value" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_INT64 + json_name: "value" + } + } + message_type { + name: "UInt64Value" + field { + name: "value" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "value" + } + } + message_type { + name: "Int32Value" + field { + name: "value" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_INT32 + json_name: "value" + } + } + message_type { + name: "UInt32Value" + field { + name: "value" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_UINT32 + json_name: "value" + } + } + message_type { + name: "BoolValue" + field { + name: "value" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_BOOL + json_name: "value" + } + } + message_type { + name: "StringValue" + field { + name: "value" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "value" + } + } + message_type { + name: "BytesValue" + field { + name: "value" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_BYTES + json_name: "value" + } + } + options { + java_package: "com.google.protobuf" + java_outer_classname: "WrappersProto" + java_multiple_files: true + go_package: "google.golang.org/protobuf/types/known/wrapperspb" + cc_enable_arenas: true + objc_class_prefix: "GPB" + csharp_namespace: "Google.Protobuf.WellKnownTypes" + } + syntax: "proto3" +} diff --git a/runtime/src/test/resources/dynamicMessage.baseline b/runtime/src/test/resources/dynamicMessage_adapted.baseline similarity index 100% rename from runtime/src/test/resources/dynamicMessage.baseline rename to runtime/src/test/resources/dynamicMessage_adapted.baseline diff --git a/runtime/src/test/resources/dynamicMessage_dynamicDescriptor.baseline b/runtime/src/test/resources/dynamicMessage_dynamicDescriptor.baseline new file mode 100644 index 000000000..6de5a507d --- /dev/null +++ b/runtime/src/test/resources/dynamicMessage_dynamicDescriptor.baseline @@ -0,0 +1,222 @@ +Source: TestAllTypes {} +=====> +bindings: {} +result: + +Source: TestAllTypes { single_int32: 1, single_int64: 2, single_string: 'hello'} +=====> +bindings: {} +result: single_int32: 1 +single_int64: 2 +single_string: "hello" + + +Source: TestAllTypes { single_int32: 1, single_int64: 2, single_string: 'hello'}.single_string +=====> +bindings: {} +result: hello + +Source: TestAllTypes { single_int32_wrapper: 3 }.single_int32_wrapper +=====> +bindings: {} +result: 3 + +Source: TestAllTypes { single_int64_wrapper: 3 }.single_int64_wrapper +=====> +bindings: {} +result: 3 + +Source: TestAllTypes { single_bool_wrapper: true }.single_bool_wrapper +=====> +bindings: {} +result: true + +Source: TestAllTypes { single_bytes_wrapper: b'abc' }.single_bytes_wrapper +=====> +bindings: {} +result: abc + +Source: TestAllTypes { single_float_wrapper: 1.1 }.single_float_wrapper +=====> +bindings: {} +result: 1.100000023841858 + +Source: TestAllTypes { single_double_wrapper: 1.1 }.single_double_wrapper +=====> +bindings: {} +result: 1.1 + +Source: TestAllTypes { single_uint32_wrapper: 2u}.single_uint32_wrapper +=====> +bindings: {} +result: 2 + +Source: TestAllTypes { single_uint64_wrapper: 2u}.single_uint64_wrapper +=====> +bindings: {} +result: 2 + +Source: TestAllTypes { single_list_value: ['a', 1.5, true] }.single_list_value +=====> +bindings: {} +result: [a, 1.5, true] + +Source: TestAllTypes { standalone_message: TestAllTypes.NestedMessage { } }.standalone_message +=====> +bindings: {} +result: + +Source: TestAllTypes { standalone_message: TestAllTypes.NestedMessage { bb: 5} }.standalone_message.bb +=====> +bindings: {} +result: 5 + +Source: TestAllTypes { standalone_enum: TestAllTypes.NestedEnum.BAR }.standalone_enum +=====> +bindings: {} +result: 1 + +Source: TestAllTypes { map_string_string: {'key': 'value'}} +=====> +bindings: {} +result: map_string_string { + key: "key" + value: "value" +} + + +Source: TestAllTypes { map_string_string: {'key': 'value'}}.map_string_string +=====> +bindings: {} +result: {key=value} + +Source: TestAllTypes { map_string_string: {'key': 'value'}}.map_string_string['key'] +=====> +bindings: {} +result: value + +Source: TestAllTypes { single_any: dur }.single_any +declare dur { + value google.protobuf.Timestamp +} +=====> +bindings: {dur=type_url: "type.googleapis.com/google.protobuf.Duration" +value: "\bd" +} +result: seconds: 100 + + +Source: TestAllTypes { single_any: any_packed_test_msg }.single_any +declare any_packed_test_msg { + value dev.cel.testing.testdata.proto3.TestAllTypes +} +=====> +bindings: {any_packed_test_msg=type_url: "type.googleapis.com/dev.cel.testing.testdata.proto3.TestAllTypes" +value: "r\005hello" +} +result: single_string: "hello" + + +Source: dynamic_msg +declare any_packed_test_msg { + value dev.cel.testing.testdata.proto3.TestAllTypes +} +declare test_msg { + value dev.cel.testing.testdata.proto3.TestAllTypes +} +declare dynamic_msg { + value dev.cel.testing.testdata.serialized.proto3.TestAllTypes +} +=====> +bindings: {dynamic_msg=map_string_string { + key: "foo" + value: "bar" +} +} +result: map_string_string { + key: "foo" + value: "bar" +} + + +Source: dynamic_msg.map_string_string +declare any_packed_test_msg { + value dev.cel.testing.testdata.proto3.TestAllTypes +} +declare test_msg { + value dev.cel.testing.testdata.proto3.TestAllTypes +} +declare dynamic_msg { + value dev.cel.testing.testdata.serialized.proto3.TestAllTypes +} +=====> +bindings: {dynamic_msg=map_string_string { + key: "foo" + value: "bar" +} +} +result: {foo=bar} + +Source: dynamic_msg.map_string_string['foo'] +declare any_packed_test_msg { + value dev.cel.testing.testdata.proto3.TestAllTypes +} +declare test_msg { + value dev.cel.testing.testdata.proto3.TestAllTypes +} +declare dynamic_msg { + value dev.cel.testing.testdata.serialized.proto3.TestAllTypes +} +=====> +bindings: {dynamic_msg=map_string_string { + key: "foo" + value: "bar" +} +} +result: bar + +Source: f_msg(dynamic_msg) +declare any_packed_test_msg { + value dev.cel.testing.testdata.proto3.TestAllTypes +} +declare test_msg { + value dev.cel.testing.testdata.proto3.TestAllTypes +} +declare dynamic_msg { + value dev.cel.testing.testdata.serialized.proto3.TestAllTypes +} +declare f_msg { + function f_msg_generated (dev.cel.testing.testdata.proto3.TestAllTypes) -> bool + function f_msg_dynamic (dev.cel.testing.testdata.serialized.proto3.TestAllTypes) -> bool +} +=====> +bindings: {dynamic_msg=map_string_string { + key: "foo" + value: "bar" +} +, test_msg=single_int64: 10 +} +result: true + +Source: f_msg(test_msg) +declare any_packed_test_msg { + value dev.cel.testing.testdata.proto3.TestAllTypes +} +declare test_msg { + value dev.cel.testing.testdata.proto3.TestAllTypes +} +declare dynamic_msg { + value dev.cel.testing.testdata.serialized.proto3.TestAllTypes +} +declare f_msg { + function f_msg_generated (dev.cel.testing.testdata.proto3.TestAllTypes) -> bool + function f_msg_dynamic (dev.cel.testing.testdata.serialized.proto3.TestAllTypes) -> bool +} +=====> +bindings: {dynamic_msg=map_string_string { + key: "foo" + value: "bar" +} +, test_msg=single_int64: 10 +} +result: true diff --git a/testing/src/main/java/dev/cel/testing/BUILD.bazel b/testing/src/main/java/dev/cel/testing/BUILD.bazel index f641dd56f..7e4c69fb9 100644 --- a/testing/src/main/java/dev/cel/testing/BUILD.bazel +++ b/testing/src/main/java/dev/cel/testing/BUILD.bazel @@ -141,13 +141,17 @@ java_library( srcs = [ "BaseInterpreterTest.java", ], - resources = ["//runtime/testdata"], + resources = [ + "//common/resources/testdata/proto3:test_all_types_file_descriptor_set", + "//runtime/testdata", + ], deps = [ ":cel_baseline_test_case", ":eval", "//:java_truth", "//common", "//common/internal:cel_descriptor_pools", + "//common/internal:file_descriptor_converter", "//common/resources/testdata/proto3:standalone_global_enum_java_proto", "//common/resources/testdata/proto3:test_all_types_java_proto", "//common/types:cel_types", diff --git a/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java b/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java index 17e6bc26c..43fadd81c 100644 --- a/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java +++ b/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java @@ -16,20 +16,26 @@ import static com.google.common.collect.ImmutableList.toImmutableList; import static com.google.common.truth.Truth.assertThat; +import static java.nio.charset.StandardCharsets.UTF_8; import dev.cel.expr.CheckedExpr; import dev.cel.expr.ExprValue; import dev.cel.expr.Type; import dev.cel.expr.Type.AbstractType; import dev.cel.expr.UnknownSet; +import com.google.common.base.Ascii; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.common.io.Resources; import com.google.common.primitives.UnsignedLong; import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.protobuf.Any; import com.google.protobuf.BoolValue; import com.google.protobuf.ByteString; import com.google.protobuf.BytesValue; +import com.google.protobuf.DescriptorProtos.FileDescriptorSet; +import com.google.protobuf.Descriptors.Descriptor; import com.google.protobuf.Descriptors.FileDescriptor; import com.google.protobuf.DoubleValue; import com.google.protobuf.Duration; @@ -42,15 +48,18 @@ import com.google.protobuf.NullValue; import com.google.protobuf.StringValue; import com.google.protobuf.Struct; +import com.google.protobuf.TextFormat; import com.google.protobuf.Timestamp; import com.google.protobuf.UInt32Value; import com.google.protobuf.UInt64Value; import com.google.protobuf.Value; import com.google.protobuf.util.Durations; +import com.google.protobuf.util.JsonFormat; import com.google.protobuf.util.Timestamps; import dev.cel.common.CelAbstractSyntaxTree; import dev.cel.common.CelProtoAbstractSyntaxTree; import dev.cel.common.internal.DefaultDescriptorPool; +import dev.cel.common.internal.FileDescriptorSetConverter; import dev.cel.common.types.CelTypes; import dev.cel.runtime.Activation; import dev.cel.runtime.InterpreterException; @@ -59,6 +68,7 @@ import dev.cel.testing.testdata.proto3.TestAllTypesProto.TestAllTypes; import dev.cel.testing.testdata.proto3.TestAllTypesProto.TestAllTypes.NestedEnum; import dev.cel.testing.testdata.proto3.TestAllTypesProto.TestAllTypes.NestedMessage; +import java.io.IOException; import java.util.Arrays; import java.util.List; import java.util.Map; @@ -69,12 +79,38 @@ /** Base class for evaluation outputs that can be stored and used as a baseline test. */ public abstract class BaseInterpreterTest extends CelBaselineTestCase { + protected static final Descriptor TEST_ALL_TYPE_DYNAMIC_DESCRIPTOR = + getDeserializedTestAllTypeDescriptor(); + protected static final ImmutableList TEST_FILE_DESCRIPTORS = ImmutableList.of( - TestAllTypes.getDescriptor().getFile(), StandaloneGlobalEnum.getDescriptor().getFile()); + TestAllTypes.getDescriptor().getFile(), + StandaloneGlobalEnum.getDescriptor().getFile(), + TEST_ALL_TYPE_DYNAMIC_DESCRIPTOR.getFile()); private final Eval eval; + private static Descriptor getDeserializedTestAllTypeDescriptor() { + try { + String fdsContent = readResourceContent("testdata/proto3/test_all_types.fds"); + FileDescriptorSet fds = TextFormat.parse(fdsContent, FileDescriptorSet.class); + ImmutableSet fileDescriptors = FileDescriptorSetConverter.convert(fds); + + return fileDescriptors.stream() + .flatMap(f -> f.getMessageTypes().stream()) + .filter( + x -> + x.getFullName().equals("dev.cel.testing.testdata.serialized.proto3.TestAllTypes")) + .findAny() + .orElseThrow( + () -> + new IllegalStateException( + "Could not find deserialized TestAllTypes descriptor.")); + } catch (IOException e) { + throw new RuntimeException("Error loading TestAllTypes descriptor", e); + } + } + public BaseInterpreterTest(boolean declareWithCelType, Eval eval) { super(declareWithCelType); this.eval = eval; @@ -1926,7 +1962,7 @@ public void maxComprehension() throws Exception { } @Test - public void dynamicMessage() throws Exception { + public void dynamicMessage_adapted() throws Exception { TestAllTypes wrapperBindings = TestAllTypes.newBuilder() .setSingleAny(Any.pack(NestedMessage.newBuilder().setBb(42).build())) @@ -2005,4 +2041,116 @@ public void dynamicMessage() throws Exception { source = "msg.single_list_value"; assertThat(runTest(activation)).isInstanceOf(List.class); } + + @Test + public void dynamicMessage_dynamicDescriptor() throws Exception { + container = "dev.cel.testing.testdata.serialized.proto3"; + + source = "TestAllTypes {}"; + assertThat(runTest(Activation.EMPTY)).isInstanceOf(DynamicMessage.class); + source = "TestAllTypes { single_int32: 1, single_int64: 2, single_string: 'hello'}"; + assertThat(runTest(Activation.EMPTY)).isInstanceOf(DynamicMessage.class); + source = + "TestAllTypes { single_int32: 1, single_int64: 2, single_string: 'hello'}.single_string"; + assertThat(runTest(Activation.EMPTY)).isInstanceOf(String.class); + + // Test wrappers + source = "TestAllTypes { single_int32_wrapper: 3 }.single_int32_wrapper"; + assertThat(runTest(Activation.EMPTY)).isInstanceOf(Long.class); + source = "TestAllTypes { single_int64_wrapper: 3 }.single_int64_wrapper"; + assertThat(runTest(Activation.EMPTY)).isInstanceOf(Long.class); + source = "TestAllTypes { single_bool_wrapper: true }.single_bool_wrapper"; + assertThat(runTest(Activation.EMPTY)).isInstanceOf(Boolean.class); + source = "TestAllTypes { single_bytes_wrapper: b'abc' }.single_bytes_wrapper"; + assertThat(runTest(Activation.EMPTY)).isInstanceOf(String.class); + source = "TestAllTypes { single_float_wrapper: 1.1 }.single_float_wrapper"; + assertThat(runTest(Activation.EMPTY)).isInstanceOf(Double.class); + source = "TestAllTypes { single_double_wrapper: 1.1 }.single_double_wrapper"; + assertThat(runTest(Activation.EMPTY)).isInstanceOf(Double.class); + source = "TestAllTypes { single_uint32_wrapper: 2u}.single_uint32_wrapper"; + assertThat(runTest(Activation.EMPTY)) + .isInstanceOf(eval.celOptions().enableUnsignedLongs() ? UnsignedLong.class : Long.class); + source = "TestAllTypes { single_uint64_wrapper: 2u}.single_uint64_wrapper"; + assertThat(runTest(Activation.EMPTY)) + .isInstanceOf(eval.celOptions().enableUnsignedLongs() ? UnsignedLong.class : Long.class); + source = "TestAllTypes { single_list_value: ['a', 1.5, true] }.single_list_value"; + assertThat(runTest(Activation.EMPTY)).isInstanceOf(List.class); + + // Test nested messages + source = + "TestAllTypes { standalone_message: TestAllTypes.NestedMessage { } }.standalone_message"; + assertThat(runTest(Activation.EMPTY)).isInstanceOf(DynamicMessage.class); + source = + "TestAllTypes { standalone_message: TestAllTypes.NestedMessage { bb: 5}" + + " }.standalone_message.bb"; + assertThat(runTest(Activation.EMPTY)).isInstanceOf(Long.class); + source = "TestAllTypes { standalone_enum: TestAllTypes.NestedEnum.BAR }.standalone_enum"; + assertThat(runTest(Activation.EMPTY)).isInstanceOf(Long.class); + source = "TestAllTypes { map_string_string: {'key': 'value'}}"; + assertThat(runTest(Activation.EMPTY)).isInstanceOf(DynamicMessage.class); + source = "TestAllTypes { map_string_string: {'key': 'value'}}.map_string_string"; + assertThat(runTest(Activation.EMPTY)).isInstanceOf(Map.class); + source = "TestAllTypes { map_string_string: {'key': 'value'}}.map_string_string['key']"; + assertThat(runTest(Activation.EMPTY)).isInstanceOf(String.class); + + // Test any unpacking + // With well-known type + Any anyDuration = Any.pack(Durations.fromSeconds(100)); + declareVariable("dur", CelTypes.TIMESTAMP); + source = "TestAllTypes { single_any: dur }.single_any"; + assertThat(runTest(Activation.of("dur", anyDuration))).isInstanceOf(Duration.class); + // with custom message + clearAllDeclarations(); + Any anyTestMsg = Any.pack(TestAllTypes.newBuilder().setSingleString("hello").build()); + declareVariable( + "any_packed_test_msg", CelTypes.createMessage(TestAllTypes.getDescriptor().getFullName())); + source = "TestAllTypes { single_any: any_packed_test_msg }.single_any"; + assertThat(runTest(Activation.of("any_packed_test_msg", anyTestMsg))) + .isInstanceOf(TestAllTypes.class); + + // Test JSON map behavior + declareVariable("test_msg", CelTypes.createMessage(TestAllTypes.getDescriptor().getFullName())); + declareVariable( + "dynamic_msg", CelTypes.createMessage(TEST_ALL_TYPE_DYNAMIC_DESCRIPTOR.getFullName())); + DynamicMessage.Builder dynamicMessageBuilder = + DynamicMessage.newBuilder(TEST_ALL_TYPE_DYNAMIC_DESCRIPTOR); + JsonFormat.parser().merge("{ 'map_string_string' : { 'foo' : 'bar' } }", dynamicMessageBuilder); + Activation activation = Activation.of("dynamic_msg", dynamicMessageBuilder.build()); + + source = "dynamic_msg"; + assertThat(runTest(activation)).isInstanceOf(DynamicMessage.class); + source = "dynamic_msg.map_string_string"; + assertThat(runTest(activation)).isInstanceOf(Map.class); + source = "dynamic_msg.map_string_string['foo']"; + assertThat(runTest(activation)).isInstanceOf(String.class); + + // Test function dispatch + declareFunction( + "f_msg", + globalOverload( + "f_msg_generated", + ImmutableList.of(CelTypes.createMessage(TestAllTypes.getDescriptor().getFullName())), + CelTypes.BOOL), + globalOverload( + "f_msg_dynamic", + ImmutableList.of( + CelTypes.createMessage(TEST_ALL_TYPE_DYNAMIC_DESCRIPTOR.getFullName())), + CelTypes.BOOL)); + eval.registrar().add("f_msg_generated", TestAllTypes.class, x -> true); + eval.registrar().add("f_msg_dynamic", DynamicMessage.class, x -> true); + activation = + Activation.copyOf( + ImmutableMap.of( + "dynamic_msg", dynamicMessageBuilder.build(), + "test_msg", TestAllTypes.newBuilder().setSingleInt64(10L).build())); + + source = "f_msg(dynamic_msg)"; + assertThat(runTest(activation)).isInstanceOf(Boolean.class); + source = "f_msg(test_msg)"; + assertThat(runTest(activation)).isInstanceOf(Boolean.class); + } + + private static String readResourceContent(String path) throws IOException { + return Resources.toString(Resources.getResource(Ascii.toLowerCase(path)), UTF_8); + } } From fdc6c7a7488d750e2d021a0305bb2698e873c200 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Tue, 28 May 2024 11:22:00 -0700 Subject: [PATCH 126/486] Release 0.5.2 PiperOrigin-RevId: 637964925 --- README.md | 4 ++-- publish/cel_version.bzl | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 738d0e866..b9cc5f3a9 100644 --- a/README.md +++ b/README.md @@ -55,14 +55,14 @@ CEL-Java is available in Maven Central Repository. [Download the JARs here][8] o dev.cel cel - 0.5.1 + 0.5.2 ``` **Gradle** ```gradle -implementation 'dev.cel:cel:0.5.1' +implementation 'dev.cel:cel:0.5.2' ``` Then run this example: diff --git a/publish/cel_version.bzl b/publish/cel_version.bzl index 9f043258b..866840e0c 100644 --- a/publish/cel_version.bzl +++ b/publish/cel_version.bzl @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. """Maven artifact version for CEL.""" -CEL_VERSION = "0.5.1" +CEL_VERSION = "0.5.2" From d2355a18b0e73850385f044d806a450b76c1bc38 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Mon, 3 Jun 2024 12:38:34 -0700 Subject: [PATCH 127/486] Copy the suppress warning annotations to autovalue gened celexpr PiperOrigin-RevId: 639877597 --- common/src/main/java/dev/cel/common/ast/CelExpr.java | 1 + 1 file changed, 1 insertion(+) diff --git a/common/src/main/java/dev/cel/common/ast/CelExpr.java b/common/src/main/java/dev/cel/common/ast/CelExpr.java index 6af628551..4c08a6d05 100644 --- a/common/src/main/java/dev/cel/common/ast/CelExpr.java +++ b/common/src/main/java/dev/cel/common/ast/CelExpr.java @@ -34,6 +34,7 @@ *

This is the native type equivalent of Expr message in syntax.proto. */ @AutoValue +@AutoValue.CopyAnnotations @Immutable @SuppressWarnings("unchecked") // Class ensures only the super type is used public abstract class CelExpr implements Expression { From 293fb2b9150b231f2958b3734b86d9e81b578f17 Mon Sep 17 00:00:00 2001 From: CEL Dev Team Date: Tue, 18 Jun 2024 15:00:58 -0700 Subject: [PATCH 128/486] Implement CEL Set Extension Implement `.contains`, `intersects` and `.equivalent` for Sets. PiperOrigin-RevId: 644521835 --- extensions/BUILD.bazel | 5 + .../main/java/dev/cel/extensions/BUILD.bazel | 18 + .../dev/cel/extensions/CelExtensions.java | 38 +- .../dev/cel/extensions/CelSetsExtensions.java | 240 +++++++++++++ .../main/java/dev/cel/extensions/README.md | 68 ++++ .../test/java/dev/cel/extensions/BUILD.bazel | 1 + .../cel/extensions/CelSetsExtensionsTest.java | 328 ++++++++++++++++++ 7 files changed, 697 insertions(+), 1 deletion(-) create mode 100644 extensions/src/main/java/dev/cel/extensions/CelSetsExtensions.java create mode 100644 extensions/src/test/java/dev/cel/extensions/CelSetsExtensionsTest.java diff --git a/extensions/BUILD.bazel b/extensions/BUILD.bazel index ef0e9c9fd..70956e336 100644 --- a/extensions/BUILD.bazel +++ b/extensions/BUILD.bazel @@ -22,3 +22,8 @@ java_library( name = "optional_library", exports = ["//extensions/src/main/java/dev/cel/extensions:optional_library"], ) + +java_library( + name = "sets", + exports = ["//extensions/src/main/java/dev/cel/extensions:sets"], +) diff --git a/extensions/src/main/java/dev/cel/extensions/BUILD.bazel b/extensions/src/main/java/dev/cel/extensions/BUILD.bazel index bf42c2ae8..da8aba9a0 100644 --- a/extensions/src/main/java/dev/cel/extensions/BUILD.bazel +++ b/extensions/src/main/java/dev/cel/extensions/BUILD.bazel @@ -18,6 +18,7 @@ java_library( ":encoders", ":math", ":protos", + ":sets", ":strings", "//common:options", "@maven//:com_google_guava_guava", @@ -126,3 +127,20 @@ java_library( "@maven//:com_google_protobuf_protobuf_java", ], ) + +java_library( + name = "sets", + srcs = ["CelSetsExtensions.java"], + tags = [ + ], + deps = [ + "//checker:checker_builder", + "//common:compiler_common", + "//common/internal:comparison_functions", + "//common/types", + "//compiler:compiler_builder", + "//runtime", + "@maven//:com_google_errorprone_error_prone_annotations", + "@maven//:com_google_guava_guava", + ], +) diff --git a/extensions/src/main/java/dev/cel/extensions/CelExtensions.java b/extensions/src/main/java/dev/cel/extensions/CelExtensions.java index c3d9fdbbf..5515d6a89 100644 --- a/extensions/src/main/java/dev/cel/extensions/CelExtensions.java +++ b/extensions/src/main/java/dev/cel/extensions/CelExtensions.java @@ -1,4 +1,4 @@ -// Copyright 2022 Google LLC +// Copyright 2024 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -30,6 +30,7 @@ public final class CelExtensions { private static final CelProtoExtensions PROTO_EXTENSIONS = new CelProtoExtensions(); private static final CelBindingsExtensions BINDINGS_EXTENSIONS = new CelBindingsExtensions(); private static final CelEncoderExtensions ENCODER_EXTENSIONS = new CelEncoderExtensions(); + private static final CelSetsExtensions SET_EXTENSIONS = new CelSetsExtensions(); /** * Extended functions for string manipulation. @@ -170,5 +171,40 @@ public static CelEncoderExtensions encoders() { return ENCODER_EXTENSIONS; } + /** + * Extended functions for Set manipulation. + * + *

Refer to README.md for available functions. + * + *

This will include all functions denoted in {@link CelSetExtensions.Function}, including any + * future additions. To expose only a subset of functions, use {@link + * #sets(CelSetExtensions.Function...)} instead. + */ + public static CelSetsExtensions sets() { + return SET_EXTENSIONS; + } + + /** + * Extended functions for Set manipulation. + * + *

Refer to README.md for available functions. + * + *

This will include only the specific functions denoted by {@link CelSetsExtensions.Function}. + */ + public static CelSetsExtensions sets(CelSetsExtensions.Function... functions) { + return sets(ImmutableSet.copyOf(functions)); + } + + /** + * Extended functions for Set manipulation. + * + *

Refer to README.md for available functions. + * + *

This will include only the specific functions denoted by {@link CelSetsExtensions.Function}. + */ + public static CelSetsExtensions sets(Set functions) { + return new CelSetsExtensions(functions); + } + private CelExtensions() {} } diff --git a/extensions/src/main/java/dev/cel/extensions/CelSetsExtensions.java b/extensions/src/main/java/dev/cel/extensions/CelSetsExtensions.java new file mode 100644 index 000000000..10fcbdd0c --- /dev/null +++ b/extensions/src/main/java/dev/cel/extensions/CelSetsExtensions.java @@ -0,0 +1,240 @@ +// Copyright 2024 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.extensions; + +import com.google.common.collect.ImmutableSet; +import com.google.errorprone.annotations.Immutable; +import dev.cel.checker.CelCheckerBuilder; +import dev.cel.common.CelFunctionDecl; +import dev.cel.common.CelOverloadDecl; +import dev.cel.common.internal.ComparisonFunctions; +import dev.cel.common.types.ListType; +import dev.cel.common.types.SimpleType; +import dev.cel.common.types.TypeParamType; +import dev.cel.compiler.CelCompilerLibrary; +import dev.cel.runtime.CelRuntime; +import dev.cel.runtime.CelRuntimeBuilder; +import dev.cel.runtime.CelRuntimeLibrary; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +/** + * Internal implementation of CEL Set extensions. + * + *

TODO: https://github.com/google/cel-go/blob/master/ext/sets.go#L127 + * + *

Invoking in operator will result in O(n) complexity. We need to wire in the CEL optimizers to + * rewrite the AST into a map to achieve a O(1) lookup. + */ +@Immutable +@SuppressWarnings({"unchecked"}) // Unchecked: Type-checker guarantees casting safety. +public final class CelSetsExtensions implements CelCompilerLibrary, CelRuntimeLibrary { + + private static final String SET_CONTAINS_FUNCTION = "sets.contains"; + private static final String SET_CONTAINS_OVERLOAD_DOC = + "Returns whether the first list argument contains all elements in the second list" + + " argument. The list may contain elements of any type and standard CEL" + + " equality is used to determine whether a value exists in both lists. If the" + + " second list is empty, the result will always return true."; + private static final String SET_EQUIVALENT_FUNCTION = "sets.equivalent"; + private static final String SET_EQUIVALENT_OVERLOAD_DOC = + "Returns whether the first and second list are set equivalent. Lists are set equivalent if" + + " for every item in the first list, there is an element in the second which is equal." + + " The lists may not be of the same size as they do not guarantee the elements within" + + " them are unique, so size does not factor intothe computation."; + private static final String SET_INTERSECTS_FUNCTION = "sets.intersects"; + private static final String SET_INTERSECTS_OVERLOAD_DOC = + "Returns whether the first and second list intersect. Lists intersect if there is at least" + + " one element in the first list which is equal to an element in the second list. The" + + " lists may not be of the same size as they do not guarantee the elements within them" + + " are unique, so size does not factor into the computation. If either list is empty," + + " the result will be false."; + + /** Denotes the set extension function. */ + public enum Function { + CONTAINS( + CelFunctionDecl.newFunctionDeclaration( + SET_CONTAINS_FUNCTION, + CelOverloadDecl.newGlobalOverload( + "list_sets_contains_list", + SET_CONTAINS_OVERLOAD_DOC, + SimpleType.BOOL, + ListType.create(TypeParamType.create("T")), + ListType.create(TypeParamType.create("T")))), + CelRuntime.CelFunctionBinding.from( + "list_sets_contains_list", + Collection.class, + Collection.class, + CelSetsExtensions::containsAll)), + EQUIVALENT( + CelFunctionDecl.newFunctionDeclaration( + SET_EQUIVALENT_FUNCTION, + CelOverloadDecl.newGlobalOverload( + "list_sets_equivalent_list", + SET_EQUIVALENT_OVERLOAD_DOC, + SimpleType.BOOL, + ListType.create(TypeParamType.create("T")), + ListType.create(TypeParamType.create("T")))), + CelRuntime.CelFunctionBinding.from( + "list_sets_equivalent_list", + Collection.class, + Collection.class, + (listA, listB) -> containsAll(listA, listB) && containsAll(listB, listA))), + INTERSECTS( + CelFunctionDecl.newFunctionDeclaration( + SET_INTERSECTS_FUNCTION, + CelOverloadDecl.newGlobalOverload( + "list_sets_intersects_list", + SET_INTERSECTS_OVERLOAD_DOC, + SimpleType.BOOL, + ListType.create(TypeParamType.create("T")), + ListType.create(TypeParamType.create("T")))), + CelRuntime.CelFunctionBinding.from( + "list_sets_intersects_list", + Collection.class, + Collection.class, + CelSetsExtensions::setIntersects)); + + private final CelFunctionDecl functionDecl; + private final ImmutableSet functionBindings; + + Function(CelFunctionDecl functionDecl, CelRuntime.CelFunctionBinding... functionBindings) { + this.functionDecl = functionDecl; + this.functionBindings = ImmutableSet.copyOf(functionBindings); + } + } + + private final ImmutableSet functions; + + CelSetsExtensions() { + this(ImmutableSet.copyOf(Function.values())); + } + + CelSetsExtensions(Set functions) { + this.functions = ImmutableSet.copyOf(functions); + } + + @Override + public void setCheckerOptions(CelCheckerBuilder checkerBuilder) { + functions.forEach(function -> checkerBuilder.addFunctionDeclarations(function.functionDecl)); + } + + @Override + public void setRuntimeOptions(CelRuntimeBuilder runtimeBuilder) { + functions.forEach(function -> runtimeBuilder.addFunctionBindings(function.functionBindings)); + } + + /** + * This implementation iterates over the specified collection, checking each element returned by + * the iterator in turn to see if it's contained in this collection. If all elements are so + * contained true is returned, otherwise false. + * + *

This is picked verbatim as implemented in the Java standard library + * Collections.containsAll() method. + * + * @see #contains(Object) + */ + private static boolean containsAll(Collection list, Collection subList) { + for (T e : subList) { + if (!contains(e, list)) { + return false; + } + } + return true; + } + + /** + * This implementation iterates over the elements in the collection, checking each element in turn + * for equality with the specified element. + * + *

This is picked verbatim as implemented in the Java standard library Collections.contains() + * method. + * + *

Source: + * https://hg.openjdk.org/jdk8u/jdk8u-dev/jdk/file/c5d02f908fb2/src/share/classes/java/util/AbstractCollection.java#l98 + */ + private static boolean contains(Object o, Collection list) { + Iterator it = list.iterator(); + if (o == null) { + while (it.hasNext()) { + if (it.next() == null) { + return true; + } + } + } else { + while (it.hasNext()) { + Object item = it.next(); + if (objectsEquals(item, o)) { // TODO: Support Maps. + return true; + } + } + } + return false; + } + + private static boolean objectsEquals(Object o1, Object o2) { + if (o1 == o2) { + return true; + } + if (o1 == null || o2 == null) { + return false; + } + if (isNumeric(o1) && isNumeric(o2)) { + if (o1.getClass().equals(o2.getClass())) { + return o1.equals(o2); + } + return ComparisonFunctions.numericEquals((Number) o1, (Number) o2); + } + if (isList(o1) && isList(o2)) { + Collection list1 = (Collection) o1; + Collection list2 = (Collection) o2; + if (list1.size() != list2.size()) { + return false; + } + Iterator iterator1 = list1.iterator(); + Iterator iterator2 = list2.iterator(); + boolean result = true; + while (iterator1.hasNext() && iterator2.hasNext()) { + Object p1 = iterator1.next(); + Object p2 = iterator2.next(); + result = result && objectsEquals(p1, p2); + } + return result; + } + return o1.equals(o2); + } + + private static boolean isNumeric(Object o) { + return o instanceof Number; + } + + private static boolean isList(Object o) { + return o instanceof List; + } + + private static boolean setIntersects(Collection listA, Collection listB) { + if (listA.isEmpty() || listB.isEmpty()) { + return false; + } + for (T element : listB) { + if (contains(element, listA)) { + return true; + } + } + return false; + } +} diff --git a/extensions/src/main/java/dev/cel/extensions/README.md b/extensions/src/main/java/dev/cel/extensions/README.md index 1c78f0364..1163f334c 100644 --- a/extensions/src/main/java/dev/cel/extensions/README.md +++ b/extensions/src/main/java/dev/cel/extensions/README.md @@ -338,3 +338,71 @@ Example: base64.encode(b'hello') // return 'aGVsbG8=' +## Sets + +Sets provides set relationship tests. + +There is no set type within CEL, and while one may be introduced in the future, +there are cases where a `list` type is known to behave like a set. For such +cases, this library provides some basic functionality for determining set +containment, equivalence, and intersection. + +### Sets.Contains + +Returns whether the first list argument contains all elements in the second list +argument. The list may contain elements of any type and standard CEL equality is +used to determine whether a value exists in both lists. If the second list is +empty, the result will always return true. + +``` +sets.contains(list(T), list(T)) -> bool +``` + +Examples: + +``` +sets.contains([], []) // true +sets.contains([], [1]) // false +sets.contains([1, 2, 3, 4], [2, 3]) // true +sets.contains([1, 2.0, 3u], [1.0, 2u, 3]) // true +``` + +### Sets.Equivalent + +Returns whether the first and second list are set equivalent. Lists are set +equivalent if for every item in the first list, there is an element in the +second which is equal. The lists may not be of the same size as they do not +guarantee the elements within them are unique, so size does not factor into the +computation. + +``` +sets.equivalent(list(T), list(T)) -> bool +``` + +Examples: + +``` +sets.equivalent([], []) // true +sets.equivalent([1], [1, 1]) // true +sets.equivalent([1], [1u, 1.0]) // true +sets.equivalent([1, 2, 3], [3u, 2.0, 1]) // true +``` + +### Sets.Intersects + +Returns whether the first list has at least one element whose value is equal to +an element in the second list. If either list is empty, the result will be +false. + +``` +sets.intersects(list(T), list(T)) -> bool +``` + +Examples: + +``` +sets.intersects([1], []) // false +sets.intersects([1], [1, 2]) // true +sets.intersects([[1], [2, 3]], [[1, 2], [2, 3.0]]) // true +``` + diff --git a/extensions/src/test/java/dev/cel/extensions/BUILD.bazel b/extensions/src/test/java/dev/cel/extensions/BUILD.bazel index c2a362a81..1edea7cb0 100644 --- a/extensions/src/test/java/dev/cel/extensions/BUILD.bazel +++ b/extensions/src/test/java/dev/cel/extensions/BUILD.bazel @@ -23,6 +23,7 @@ java_library( "//extensions", "//extensions:math", "//extensions:optional_library", + "//extensions:sets", "//extensions:strings", "//parser:macro", "//runtime", diff --git a/extensions/src/test/java/dev/cel/extensions/CelSetsExtensionsTest.java b/extensions/src/test/java/dev/cel/extensions/CelSetsExtensionsTest.java new file mode 100644 index 000000000..70396ee45 --- /dev/null +++ b/extensions/src/test/java/dev/cel/extensions/CelSetsExtensionsTest.java @@ -0,0 +1,328 @@ +// Copyright 2024 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.extensions; + +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertThrows; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.testing.junit.testparameterinjector.TestParameterInjector; +import com.google.testing.junit.testparameterinjector.TestParameters; +import dev.cel.common.CelAbstractSyntaxTree; +import dev.cel.common.CelValidationException; +import dev.cel.common.CelValidationResult; +import dev.cel.common.types.ListType; +import dev.cel.common.types.SimpleType; +import dev.cel.compiler.CelCompiler; +import dev.cel.compiler.CelCompilerFactory; +import dev.cel.extensions.CelSetsExtensions.Function; +import dev.cel.runtime.CelEvaluationException; +import dev.cel.runtime.CelRuntime; +import dev.cel.runtime.CelRuntimeFactory; +import java.util.List; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(TestParameterInjector.class) +public final class CelSetsExtensionsTest { + private static final CelCompiler COMPILER = + CelCompilerFactory.standardCelCompilerBuilder() + .addLibraries(CelExtensions.sets()) + .addVar("list", ListType.create(SimpleType.INT)) + .addVar("subList", ListType.create(SimpleType.INT)) + .build(); + + private static final CelRuntime RUNTIME = + CelRuntimeFactory.standardCelRuntimeBuilder().addLibraries(CelExtensions.sets()).build(); + + @Test + public void contains_integerListWithSameValue_succeeds() throws Exception { + ImmutableList list = ImmutableList.of(1, 2, 3, 4); + ImmutableList subList = ImmutableList.of(1, 2, 3, 4); + CelAbstractSyntaxTree ast = COMPILER.compile("sets.contains(list, subList)").getAst(); + CelRuntime.Program program = RUNTIME.createProgram(ast); + + Object result = program.eval(ImmutableMap.of("list", list, "subList", subList)); + + assertThat(result).isEqualTo(true); + } + + @Test + public void contains_integerListAsExpression_succeeds() throws Exception { + CelAbstractSyntaxTree ast = COMPILER.compile("sets.contains([1, 1], [1])").getAst(); + CelRuntime.Program program = RUNTIME.createProgram(ast); + + Object result = program.eval(); + + assertThat(result).isEqualTo(true); + } + + @Test + @TestParameters("{list: [1, 2, 3, 4], subList: [1, 2, 3, 4], expected: true}") + @TestParameters("{list: [5, 4, 3, 2, 1], subList: [1, 2, 3], expected: true}") + @TestParameters("{list: [5, 4, 3, 2, 1], subList: [1, 1, 1, 1, 1], expected: true}") + @TestParameters("{list: [], subList: [], expected: true}") + @TestParameters("{list: [1], subList: [], expected: true}") + @TestParameters("{list: [], subList: [1], expected: false}") + @TestParameters("{list: [1], subList: [1], expected: true}") + @TestParameters("{list: [1], subList: [1, 1], expected: true}") + @TestParameters("{list: [1, 1], subList: [1, 1], expected: true}") + @TestParameters("{list: [2, 1], subList: [1], expected: true}") + @TestParameters("{list: [1, 2, 3, 4], subList: [2, 3], expected: true}") + @TestParameters("{list: [1], subList: [2], expected: false}") + @TestParameters("{list: [1], subList: [1, 2], expected: false}") + public void contains_withIntTypes_succeeds( + List list, List subList, boolean expected) throws Exception { + CelAbstractSyntaxTree ast = COMPILER.compile("sets.contains(list, subList)").getAst(); + CelRuntime.Program program = RUNTIME.createProgram(ast); + + Object result = program.eval(ImmutableMap.of("list", list, "subList", subList)); + + assertThat(result).isEqualTo(expected); + } + + @Test + @TestParameters("{list: [1.0], subList: [1.0, 1.0], expected: true}") + @TestParameters("{list: [1.0, 1.00], subList: [1], expected: true}") + @TestParameters("{list: [1.0], subList: [1.00], expected: true}") + @TestParameters("{list: [1.414], subList: [], expected: true}") + @TestParameters("{list: [], subList: [1.414], expected: false}") + @TestParameters("{list: [3.14, 2.71], subList: [2.71], expected: true}") + @TestParameters("{list: [3.9], subList: [3.1], expected: false}") + @TestParameters("{list: [3.2], subList: [3.1], expected: false}") + @TestParameters("{list: [2, 3.0], subList: [2, 3], expected: true}") + public void contains_withDoubleTypes_succeeds( + List list, List subList, boolean expected) throws Exception { + CelAbstractSyntaxTree ast = COMPILER.compile("sets.contains(list, subList)").getAst(); + CelRuntime.Program program = RUNTIME.createProgram(ast); + + Object result = program.eval(ImmutableMap.of("list", list, "subList", subList)); + + assertThat(result).isEqualTo(expected); + } + + @Test + @TestParameters("{expression: 'sets.contains([[1], [2, 3]], [[2, 3]])', expected: true}") + @TestParameters("{expression: 'sets.contains([[1], [2], [3]], [[2, 3]])', expected: false}") + @TestParameters( + "{expression: 'sets.contains([[1, 2], [2, 3]], [[1], [2, 3.0]])', expected: false}") + @TestParameters("{expression: 'sets.contains([[1], [2, 3.0]], [[2, 3]])', expected: true}") + public void contains_withNestedLists_succeeds(String expression, boolean expected) + throws Exception { + CelAbstractSyntaxTree ast = COMPILER.compile(expression).getAst(); + CelRuntime.Program program = RUNTIME.createProgram(ast); + + Object result = program.eval(); + + assertThat(result).isEqualTo(expected); + } + + @Test + @TestParameters("{expression: 'sets.contains([1, \"1\"], [1])', expected: true}") + @TestParameters("{expression: 'sets.contains([1], [1, \"1\"])', expected: false}") + public void contains_withMixingIntAndString_succeeds(String expression, boolean expected) + throws Exception { + CelAbstractSyntaxTree ast = COMPILER.compile(expression).getAst(); + CelRuntime.Program program = RUNTIME.createProgram(ast); + + Object result = program.eval(); + + assertThat(result).isEqualTo(expected); + } + + @Test + @TestParameters("{expression: 'sets.contains([1], [\"1\"])'}") + @TestParameters("{expression: 'sets.contains([\"1\"], [1])'}") + public void contains_withMixingIntAndString_throwsException(String expression) throws Exception { + CelValidationResult invalidData = COMPILER.compile(expression); + + assertThat(invalidData.getErrors()).hasSize(1); + assertThat(invalidData.getErrors().get(0).getMessage()) + .contains("found no matching overload for 'sets.contains'"); + } + + @Test + public void contains_withMixedValues_succeeds() throws Exception { + CelAbstractSyntaxTree ast = COMPILER.compile("sets.contains([1, 2], [2u, 2.0])").getAst(); + CelRuntime.Program program = RUNTIME.createProgram(ast); + + Object result = program.eval(); + + assertThat(result).isEqualTo(true); + } + + @Test + @TestParameters("{expression: 'sets.contains([[1], [2, 3.0]], [[2, 3]])', expected: true}") + @TestParameters( + "{expression: 'sets.contains([[1], [2, 3.0], [[[[[5]]]]]], [[[[[[5]]]]]])', expected: true}") + @TestParameters( + "{expression: 'sets.contains([[1], [2, 3.0], [[[[[5]]]]]], [[[[[[5, 1]]]]]])', expected:" + + " false}") + @TestParameters( + "{expression: 'sets.contains([[1], [2, 3.0], [[[[[5, 1]]]]]], [[[[[[5]]]]]])', expected:" + + " false}") + @TestParameters( + "{expression: 'sets.contains([[[[[[5]]]]]], [[1], [2, 3.0], [[[[[5]]]]]])', expected: false}") + public void contains_withMultiLevelNestedList_succeeds(String expression, boolean expected) + throws Exception { + CelAbstractSyntaxTree ast = COMPILER.compile(expression).getAst(); + CelRuntime.Program program = RUNTIME.createProgram(ast); + + Object result = program.eval(); + + assertThat(result).isEqualTo(expected); + } + + @Test + @TestParameters("{expression: 'sets.equivalent([], [])', expected: true}") + @TestParameters("{expression: 'sets.equivalent([1], [1])', expected: true}") + @TestParameters("{expression: 'sets.equivalent([1], [1, 1])', expected: true}") + @TestParameters("{expression: 'sets.equivalent([1, 1], [1])', expected: true}") + @TestParameters("{expression: 'sets.equivalent([[1], [2, 3]], [[1], [2, 3]])', expected: true}") + @TestParameters("{expression: 'sets.equivalent([2, 1], [1])', expected: false}") + @TestParameters("{expression: 'sets.equivalent([1], [1, 2])', expected: false}") + @TestParameters("{expression: 'sets.equivalent([1, 2], [1, 2, 3])', expected: false}") + @TestParameters("{expression: 'sets.equivalent([1, 2], [2, 2, 2])', expected: false}") + public void equivalent_withIntTypes_succeeds(String expression, boolean expected) + throws Exception { + CelAbstractSyntaxTree ast = COMPILER.compile(expression).getAst(); + CelRuntime.Program program = RUNTIME.createProgram(ast); + + Object result = program.eval(); + + assertThat(result).isEqualTo(expected); + } + + @Test + @TestParameters("{expression: 'sets.equivalent([1, 2, 3], [3u, 2.0, 1])', expected: true}") + @TestParameters("{expression: 'sets.equivalent([1], [1u, 1.0])', expected: true}") + @TestParameters("{expression: 'sets.equivalent([1], [1u, 1.0])', expected: true}") + @TestParameters( + "{expression: 'sets.equivalent([[1.0], [2, 3]], [[1], [2, 3.0]])', expected: true}") + @TestParameters("{expression: 'sets.equivalent([1, 2], [2u, 2, 2.0])', expected: false}") + @TestParameters("{expression: 'sets.equivalent([1, 2], [1u, 2, 2.3])', expected: false}") + public void equivalent_withMixedTypes_succeeds(String expression, boolean expected) + throws Exception { + CelAbstractSyntaxTree ast = COMPILER.compile(expression).getAst(); + CelRuntime.Program program = RUNTIME.createProgram(ast); + + Object result = program.eval(); + + assertThat(result).isEqualTo(expected); + } + + @Test + @TestParameters("{expression: 'sets.intersects([], [])', expected: false}") + @TestParameters("{expression: 'sets.intersects([1], [])', expected: false}") + @TestParameters("{expression: 'sets.intersects([], [1])', expected: false}") + @TestParameters("{expression: 'sets.intersects([1], [1])', expected: true}") + @TestParameters("{expression: 'sets.intersects([1], [2])', expected: false}") + @TestParameters("{expression: 'sets.intersects([1], [1, 1])', expected: true}") + @TestParameters("{expression: 'sets.intersects([1, 1], [1])', expected: true}") + @TestParameters("{expression: 'sets.intersects([2, 1], [1])', expected: true}") + @TestParameters("{expression: 'sets.intersects([1], [1, 2])', expected: true}") + @TestParameters("{expression: 'sets.intersects([1], [1.0, 2])', expected: true}") + @TestParameters("{expression: 'sets.intersects([1, 2], [2u, 2, 2.0])', expected: true}") + @TestParameters("{expression: 'sets.intersects([1, 2], [1, 2, 2.3])', expected: true}") + @TestParameters("{expression: 'sets.intersects([0, 1, 2], [1, 2, 2.3])', expected: true}") + @TestParameters("{expression: 'sets.intersects([1, 2], [1u, 2, 2.3])', expected: true}") + @TestParameters( + "{expression: 'sets.intersects([[1], [2, 3]], [[1, 2], [2, 3.0]])', expected: true}") + @TestParameters("{expression: 'sets.intersects([1], [\"1\", 2])', expected: false}") + @TestParameters("{expression: 'sets.intersects([1], [1.1, 2])', expected: false}") + @TestParameters("{expression: 'sets.intersects([1], [1.1, 2u])', expected: false}") + public void intersects_withMixedTypes_succeeds(String expression, boolean expected) + throws Exception { + CelAbstractSyntaxTree ast = COMPILER.compile(expression).getAst(); + CelRuntime.Program program = RUNTIME.createProgram(ast); + + Object result = program.eval(); + + assertThat(result).isEqualTo(expected); + } + + @Test + public void setsExtension_containsFunctionSubset_succeeds() throws Exception { + CelSetsExtensions setsExtensions = CelExtensions.sets(Function.CONTAINS); + CelCompiler celCompiler = + CelCompilerFactory.standardCelCompilerBuilder().addLibraries(setsExtensions).build(); + CelRuntime celRuntime = + CelRuntimeFactory.standardCelRuntimeBuilder().addLibraries(setsExtensions).build(); + + Object evaluatedResult = + celRuntime.createProgram(celCompiler.compile("sets.contains([1, 2], [2])").getAst()).eval(); + + assertThat(evaluatedResult).isEqualTo(true); + } + + @Test + public void setsExtension_equivalentFunctionSubset_succeeds() throws Exception { + CelSetsExtensions setsExtensions = CelExtensions.sets(Function.EQUIVALENT); + CelCompiler celCompiler = + CelCompilerFactory.standardCelCompilerBuilder().addLibraries(setsExtensions).build(); + CelRuntime celRuntime = + CelRuntimeFactory.standardCelRuntimeBuilder().addLibraries(setsExtensions).build(); + + Object evaluatedResult = + celRuntime + .createProgram(celCompiler.compile("sets.equivalent([1, 1], [1])").getAst()) + .eval(); + + assertThat(evaluatedResult).isEqualTo(true); + } + + @Test + public void setsExtension_intersectsFunctionSubset_succeeds() throws Exception { + CelSetsExtensions setsExtensions = CelExtensions.sets(Function.INTERSECTS); + CelCompiler celCompiler = + CelCompilerFactory.standardCelCompilerBuilder().addLibraries(setsExtensions).build(); + CelRuntime celRuntime = + CelRuntimeFactory.standardCelRuntimeBuilder().addLibraries(setsExtensions).build(); + + Object evaluatedResult = + celRuntime + .createProgram(celCompiler.compile("sets.intersects([1, 1], [1])").getAst()) + .eval(); + + assertThat(evaluatedResult).isEqualTo(true); + } + + @Test + public void setsExtension_compileUnallowedFunction_throws() { + CelSetsExtensions setsExtensions = CelExtensions.sets(Function.EQUIVALENT); + CelCompiler celCompiler = + CelCompilerFactory.standardCelCompilerBuilder().addLibraries(setsExtensions).build(); + + assertThrows( + CelValidationException.class, + () -> celCompiler.compile("sets.contains([1, 2], [2])").getAst()); + } + + @Test + public void setsExtension_evaluateUnallowedFunction_throws() throws Exception { + CelSetsExtensions setsExtensions = CelExtensions.sets(Function.CONTAINS, Function.EQUIVALENT); + CelCompiler celCompiler = + CelCompilerFactory.standardCelCompilerBuilder().addLibraries(setsExtensions).build(); + CelRuntime celRuntime = + CelRuntimeFactory.standardCelRuntimeBuilder() + .addLibraries(CelExtensions.sets(Function.EQUIVALENT)) + .build(); + + CelAbstractSyntaxTree ast = celCompiler.compile("sets.contains([1, 2], [2])").getAst(); + + assertThrows(CelEvaluationException.class, () -> celRuntime.createProgram(ast).eval()); + } +} From b28987191fe19af33b92b216a8906287d48a3e74 Mon Sep 17 00:00:00 2001 From: Kurt Alfred Kluever Date: Thu, 20 Jun 2024 10:49:35 -0700 Subject: [PATCH 129/486] No public description PiperOrigin-RevId: 645086818 --- WORKSPACE | 2 +- bundle/src/test/java/dev/cel/bundle/CelImplTest.java | 2 +- .../src/main/java/dev/cel/checker/DescriptorTypeProvider.java | 2 +- checker/src/main/java/dev/cel/checker/Env.java | 2 +- checker/src/main/java/dev/cel/checker/ExprChecker.java | 2 +- checker/src/main/java/dev/cel/checker/TypeFormatter.java | 2 +- checker/src/main/java/dev/cel/checker/TypeProvider.java | 2 +- .../src/main/java/dev/cel/checker/TypeProviderLegacyImpl.java | 2 +- checker/src/main/java/dev/cel/checker/Types.java | 2 +- common/src/main/java/dev/cel/common/CelValidationResult.java | 2 +- common/src/main/java/dev/cel/common/internal/AdaptingTypes.java | 2 +- common/src/main/java/dev/cel/common/internal/Errors.java | 2 +- common/src/main/java/dev/cel/common/internal/ProtoAdapter.java | 2 +- common/src/main/java/dev/cel/common/values/ListValue.java | 2 +- common/src/main/java/dev/cel/common/values/MapValue.java | 2 +- common/src/main/java/dev/cel/common/values/OptionalValue.java | 2 +- runtime/src/main/java/dev/cel/runtime/Activation.java | 2 +- runtime/src/main/java/dev/cel/runtime/CelRuntimeLegacyImpl.java | 2 +- .../main/java/dev/cel/runtime/DescriptorMessageProvider.java | 2 +- .../src/main/java/dev/cel/runtime/DynamicMessageFactory.java | 2 +- runtime/src/main/java/dev/cel/runtime/GlobalResolver.java | 2 +- runtime/src/main/java/dev/cel/runtime/InterpreterException.java | 2 +- runtime/src/main/java/dev/cel/runtime/InterpreterUtil.java | 2 +- runtime/src/main/java/dev/cel/runtime/MessageFactory.java | 2 +- .../java/dev/cel/runtime/RuntimeTypeProviderLegacyImpl.java | 2 +- runtime/src/main/java/dev/cel/runtime/StandardTypeResolver.java | 2 +- runtime/src/main/java/dev/cel/runtime/TypeResolver.java | 2 +- runtime/src/test/java/dev/cel/runtime/RuntimeEqualityTest.java | 2 +- 28 files changed, 28 insertions(+), 28 deletions(-) diff --git a/WORKSPACE b/WORKSPACE index e965fca90..cd72fce2c 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -73,7 +73,7 @@ maven_install( "com.google.truth.extensions:truth-proto-extension:1.4.2", "com.google.truth:truth:1.4.2", "org.antlr:antlr4-runtime:" + ANTLR4_VERSION, - "org.jspecify:jspecify:0.2.0", + "org.jspecify:jspecify:0.3.0", "org.threeten:threeten-extra:1.8.0", ], repositories = [ diff --git a/bundle/src/test/java/dev/cel/bundle/CelImplTest.java b/bundle/src/test/java/dev/cel/bundle/CelImplTest.java index f1b1dfb00..ef751df18 100644 --- a/bundle/src/test/java/dev/cel/bundle/CelImplTest.java +++ b/bundle/src/test/java/dev/cel/bundle/CelImplTest.java @@ -107,7 +107,7 @@ import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.ThreadPoolExecutor; -import org.jspecify.nullness.Nullable; +import org.jspecify.annotations.Nullable; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/checker/src/main/java/dev/cel/checker/DescriptorTypeProvider.java b/checker/src/main/java/dev/cel/checker/DescriptorTypeProvider.java index e2fe17351..b5f849d50 100644 --- a/checker/src/main/java/dev/cel/checker/DescriptorTypeProvider.java +++ b/checker/src/main/java/dev/cel/checker/DescriptorTypeProvider.java @@ -41,7 +41,7 @@ import java.util.List; import java.util.Map; import java.util.Set; -import org.jspecify.nullness.Nullable; +import org.jspecify.annotations.Nullable; /** * The {@code DescriptorTypeProvider} provides type information for one or more {@link Descriptor} diff --git a/checker/src/main/java/dev/cel/checker/Env.java b/checker/src/main/java/dev/cel/checker/Env.java index e1846f1b8..8cc354fb2 100644 --- a/checker/src/main/java/dev/cel/checker/Env.java +++ b/checker/src/main/java/dev/cel/checker/Env.java @@ -48,7 +48,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; -import org.jspecify.nullness.Nullable; +import org.jspecify.annotations.Nullable; /** * Environment used during checking of expressions. Provides name resolution and error reporting. diff --git a/checker/src/main/java/dev/cel/checker/ExprChecker.java b/checker/src/main/java/dev/cel/checker/ExprChecker.java index 658c7db06..f4f485e08 100644 --- a/checker/src/main/java/dev/cel/checker/ExprChecker.java +++ b/checker/src/main/java/dev/cel/checker/ExprChecker.java @@ -47,7 +47,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; -import org.jspecify.nullness.Nullable; +import org.jspecify.annotations.Nullable; /** * The expression type checker. diff --git a/checker/src/main/java/dev/cel/checker/TypeFormatter.java b/checker/src/main/java/dev/cel/checker/TypeFormatter.java index 450518068..3cdd1a511 100644 --- a/checker/src/main/java/dev/cel/checker/TypeFormatter.java +++ b/checker/src/main/java/dev/cel/checker/TypeFormatter.java @@ -18,7 +18,7 @@ import dev.cel.common.annotations.Internal; import dev.cel.common.types.CelType; import dev.cel.common.types.CelTypes; -import org.jspecify.nullness.Nullable; +import org.jspecify.annotations.Nullable; /** * Class to format {@link Type} objects into {@code String} values. diff --git a/checker/src/main/java/dev/cel/checker/TypeProvider.java b/checker/src/main/java/dev/cel/checker/TypeProvider.java index 745789498..10ce2a7d6 100644 --- a/checker/src/main/java/dev/cel/checker/TypeProvider.java +++ b/checker/src/main/java/dev/cel/checker/TypeProvider.java @@ -22,7 +22,7 @@ import dev.cel.common.types.CelTypes; import java.util.Optional; import java.util.function.Function; -import org.jspecify.nullness.Nullable; +import org.jspecify.annotations.Nullable; /** * The {@code TypeProvider} defines methods to lookup types and enums, and resolve field types. diff --git a/checker/src/main/java/dev/cel/checker/TypeProviderLegacyImpl.java b/checker/src/main/java/dev/cel/checker/TypeProviderLegacyImpl.java index 497d15698..4d1e0ea32 100644 --- a/checker/src/main/java/dev/cel/checker/TypeProviderLegacyImpl.java +++ b/checker/src/main/java/dev/cel/checker/TypeProviderLegacyImpl.java @@ -26,7 +26,7 @@ import dev.cel.common.types.StructType; import dev.cel.common.types.TypeType; import java.util.Optional; -import org.jspecify.nullness.Nullable; +import org.jspecify.annotations.Nullable; /** * The {@code TypeProviderLegacyImpl} acts as a bridge between the old and new type provider APIs diff --git a/checker/src/main/java/dev/cel/checker/Types.java b/checker/src/main/java/dev/cel/checker/Types.java index 5e54dfd6d..7f249fc92 100644 --- a/checker/src/main/java/dev/cel/checker/Types.java +++ b/checker/src/main/java/dev/cel/checker/Types.java @@ -39,7 +39,7 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; -import org.jspecify.nullness.Nullable; +import org.jspecify.annotations.Nullable; /** * Utilities for dealing with the {@link Type} proto. diff --git a/common/src/main/java/dev/cel/common/CelValidationResult.java b/common/src/main/java/dev/cel/common/CelValidationResult.java index a7e6eceb8..3e52bc8e1 100644 --- a/common/src/main/java/dev/cel/common/CelValidationResult.java +++ b/common/src/main/java/dev/cel/common/CelValidationResult.java @@ -24,7 +24,7 @@ import com.google.errorprone.annotations.Immutable; import com.google.errorprone.annotations.InlineMe; import dev.cel.common.annotations.Internal; -import org.jspecify.nullness.Nullable; +import org.jspecify.annotations.Nullable; /** * CelValidationResult encapsulates the {@code CelAbstractSyntaxTree} and {@code CelIssue} set which diff --git a/common/src/main/java/dev/cel/common/internal/AdaptingTypes.java b/common/src/main/java/dev/cel/common/internal/AdaptingTypes.java index 53fe59503..48158bd91 100644 --- a/common/src/main/java/dev/cel/common/internal/AdaptingTypes.java +++ b/common/src/main/java/dev/cel/common/internal/AdaptingTypes.java @@ -23,7 +23,7 @@ import java.util.ListIterator; import java.util.Map; import java.util.Set; -import org.jspecify.nullness.Nullable; +import org.jspecify.annotations.Nullable; /** * Collection of types which support bidirectional adaptation between CEL and Java native value diff --git a/common/src/main/java/dev/cel/common/internal/Errors.java b/common/src/main/java/dev/cel/common/internal/Errors.java index 3ee3ad19c..b2860355f 100644 --- a/common/src/main/java/dev/cel/common/internal/Errors.java +++ b/common/src/main/java/dev/cel/common/internal/Errors.java @@ -28,7 +28,7 @@ import java.util.Deque; import java.util.List; import java.util.Optional; -import org.jspecify.nullness.Nullable; +import org.jspecify.annotations.Nullable; /** * An object which manages error reporting. Enriches error messages by source context pointing to diff --git a/common/src/main/java/dev/cel/common/internal/ProtoAdapter.java b/common/src/main/java/dev/cel/common/internal/ProtoAdapter.java index b63825dc4..29fece49c 100644 --- a/common/src/main/java/dev/cel/common/internal/ProtoAdapter.java +++ b/common/src/main/java/dev/cel/common/internal/ProtoAdapter.java @@ -59,7 +59,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; -import org.jspecify.nullness.Nullable; +import org.jspecify.annotations.Nullable; /** * The {@code ProtoAdapter} utilities handle conversion between native Java objects which represent diff --git a/common/src/main/java/dev/cel/common/values/ListValue.java b/common/src/main/java/dev/cel/common/values/ListValue.java index 9cf6aa806..814884d34 100644 --- a/common/src/main/java/dev/cel/common/values/ListValue.java +++ b/common/src/main/java/dev/cel/common/values/ListValue.java @@ -24,7 +24,7 @@ import java.util.Comparator; import java.util.List; import java.util.function.UnaryOperator; -import org.jspecify.nullness.Nullable; +import org.jspecify.annotations.Nullable; /** * ListValue is an abstract representation of a generic list containing zero or more {@link diff --git a/common/src/main/java/dev/cel/common/values/MapValue.java b/common/src/main/java/dev/cel/common/values/MapValue.java index ff1bb3f56..0f79b0464 100644 --- a/common/src/main/java/dev/cel/common/values/MapValue.java +++ b/common/src/main/java/dev/cel/common/values/MapValue.java @@ -26,7 +26,7 @@ import java.util.Optional; import java.util.function.BiFunction; import java.util.function.Function; -import org.jspecify.nullness.Nullable; +import org.jspecify.annotations.Nullable; /** * MapValue is an abstract representation of a generic map containing {@link CelValue} as keys and diff --git a/common/src/main/java/dev/cel/common/values/OptionalValue.java b/common/src/main/java/dev/cel/common/values/OptionalValue.java index 45270ebb2..3866ef72b 100644 --- a/common/src/main/java/dev/cel/common/values/OptionalValue.java +++ b/common/src/main/java/dev/cel/common/values/OptionalValue.java @@ -21,7 +21,7 @@ import dev.cel.common.types.SimpleType; import java.util.NoSuchElementException; import java.util.Optional; -import org.jspecify.nullness.Nullable; +import org.jspecify.annotations.Nullable; /** * First-class support for CEL optionals. Supports similar semantics to java.util.Optional. Also diff --git a/runtime/src/main/java/dev/cel/runtime/Activation.java b/runtime/src/main/java/dev/cel/runtime/Activation.java index c51e77e0c..1894c16ca 100644 --- a/runtime/src/main/java/dev/cel/runtime/Activation.java +++ b/runtime/src/main/java/dev/cel/runtime/Activation.java @@ -31,7 +31,7 @@ import java.util.HashMap; import java.util.Map; import java.util.Optional; -import org.jspecify.nullness.Nullable; +import org.jspecify.annotations.Nullable; /** * An object which allows to bind names to values. diff --git a/runtime/src/main/java/dev/cel/runtime/CelRuntimeLegacyImpl.java b/runtime/src/main/java/dev/cel/runtime/CelRuntimeLegacyImpl.java index 9ef60304f..f5f96e5ca 100644 --- a/runtime/src/main/java/dev/cel/runtime/CelRuntimeLegacyImpl.java +++ b/runtime/src/main/java/dev/cel/runtime/CelRuntimeLegacyImpl.java @@ -48,7 +48,7 @@ import java.util.Map; import java.util.Optional; import java.util.function.Function; -import org.jspecify.nullness.Nullable; +import org.jspecify.annotations.Nullable; /** * {@code CelRuntime} implementation based on the legacy CEL-Java stack. diff --git a/runtime/src/main/java/dev/cel/runtime/DescriptorMessageProvider.java b/runtime/src/main/java/dev/cel/runtime/DescriptorMessageProvider.java index 5c0931a00..f4fbbfe27 100644 --- a/runtime/src/main/java/dev/cel/runtime/DescriptorMessageProvider.java +++ b/runtime/src/main/java/dev/cel/runtime/DescriptorMessageProvider.java @@ -35,7 +35,7 @@ import dev.cel.common.types.CelTypes; import java.util.Map; import java.util.Optional; -import org.jspecify.nullness.Nullable; +import org.jspecify.annotations.Nullable; /** * An implementation of {@link RuntimeTypeProvider} which relies on proto descriptors. diff --git a/runtime/src/main/java/dev/cel/runtime/DynamicMessageFactory.java b/runtime/src/main/java/dev/cel/runtime/DynamicMessageFactory.java index 60bfb6cd8..41f78b078 100644 --- a/runtime/src/main/java/dev/cel/runtime/DynamicMessageFactory.java +++ b/runtime/src/main/java/dev/cel/runtime/DynamicMessageFactory.java @@ -26,7 +26,7 @@ import dev.cel.common.internal.DefaultMessageFactory; import dev.cel.common.internal.ProtoMessageFactory; import java.util.Collection; -import org.jspecify.nullness.Nullable; +import org.jspecify.annotations.Nullable; /** * The {@code DynamicMessageFactory} creates {@link DynamicMessage} instances by protobuf name. diff --git a/runtime/src/main/java/dev/cel/runtime/GlobalResolver.java b/runtime/src/main/java/dev/cel/runtime/GlobalResolver.java index 2cc1a7d31..a088ae2c1 100644 --- a/runtime/src/main/java/dev/cel/runtime/GlobalResolver.java +++ b/runtime/src/main/java/dev/cel/runtime/GlobalResolver.java @@ -15,7 +15,7 @@ package dev.cel.runtime; import dev.cel.common.annotations.Internal; -import org.jspecify.nullness.Nullable; +import org.jspecify.annotations.Nullable; /** * An interface describing an object that can perform a lookup on a given name, returning the value diff --git a/runtime/src/main/java/dev/cel/runtime/InterpreterException.java b/runtime/src/main/java/dev/cel/runtime/InterpreterException.java index 98595ee88..e3e09aa24 100644 --- a/runtime/src/main/java/dev/cel/runtime/InterpreterException.java +++ b/runtime/src/main/java/dev/cel/runtime/InterpreterException.java @@ -20,7 +20,7 @@ import dev.cel.common.CelRuntimeException; import dev.cel.common.annotations.Internal; import dev.cel.common.internal.SafeStringFormatter; -import org.jspecify.nullness.Nullable; +import org.jspecify.annotations.Nullable; /** * An exception produced during interpretation of expressions. diff --git a/runtime/src/main/java/dev/cel/runtime/InterpreterUtil.java b/runtime/src/main/java/dev/cel/runtime/InterpreterUtil.java index 05a764632..c2dac9cd0 100644 --- a/runtime/src/main/java/dev/cel/runtime/InterpreterUtil.java +++ b/runtime/src/main/java/dev/cel/runtime/InterpreterUtil.java @@ -23,7 +23,7 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Set; -import org.jspecify.nullness.Nullable; +import org.jspecify.annotations.Nullable; /** * Util class for CEL interpreter. diff --git a/runtime/src/main/java/dev/cel/runtime/MessageFactory.java b/runtime/src/main/java/dev/cel/runtime/MessageFactory.java index e56825b4a..a7ec8de23 100644 --- a/runtime/src/main/java/dev/cel/runtime/MessageFactory.java +++ b/runtime/src/main/java/dev/cel/runtime/MessageFactory.java @@ -20,7 +20,7 @@ import dev.cel.common.internal.DefaultMessageFactory; import dev.cel.common.internal.ProtoMessageFactory; import java.util.Optional; -import org.jspecify.nullness.Nullable; +import org.jspecify.annotations.Nullable; /** * The {@code MessageFactory} provides a method to create a protobuf builder objects by name. diff --git a/runtime/src/main/java/dev/cel/runtime/RuntimeTypeProviderLegacyImpl.java b/runtime/src/main/java/dev/cel/runtime/RuntimeTypeProviderLegacyImpl.java index 96dc40d0c..dcb2b4ec3 100644 --- a/runtime/src/main/java/dev/cel/runtime/RuntimeTypeProviderLegacyImpl.java +++ b/runtime/src/main/java/dev/cel/runtime/RuntimeTypeProviderLegacyImpl.java @@ -34,7 +34,7 @@ import dev.cel.common.values.StringValue; import java.util.Map; import java.util.NoSuchElementException; -import org.jspecify.nullness.Nullable; +import org.jspecify.annotations.Nullable; /** Bridge between the old RuntimeTypeProvider and CelValueProvider APIs. */ @Internal diff --git a/runtime/src/main/java/dev/cel/runtime/StandardTypeResolver.java b/runtime/src/main/java/dev/cel/runtime/StandardTypeResolver.java index 3a46ebea5..c560827cc 100644 --- a/runtime/src/main/java/dev/cel/runtime/StandardTypeResolver.java +++ b/runtime/src/main/java/dev/cel/runtime/StandardTypeResolver.java @@ -35,7 +35,7 @@ import java.util.Collection; import java.util.Map; import java.util.Optional; -import org.jspecify.nullness.Nullable; +import org.jspecify.annotations.Nullable; /** * The {@code StandardTypeResolver} implements the {@link TypeResolver} and resolves types supported diff --git a/runtime/src/main/java/dev/cel/runtime/TypeResolver.java b/runtime/src/main/java/dev/cel/runtime/TypeResolver.java index 271c65bba..4bfa9ae7d 100644 --- a/runtime/src/main/java/dev/cel/runtime/TypeResolver.java +++ b/runtime/src/main/java/dev/cel/runtime/TypeResolver.java @@ -19,7 +19,7 @@ import com.google.errorprone.annotations.Immutable; import dev.cel.common.annotations.Internal; import dev.cel.common.types.CelType; -import org.jspecify.nullness.Nullable; +import org.jspecify.annotations.Nullable; /** * The {@code TypeResolver} determines the CEL type of Java-native values and assists with adapting diff --git a/runtime/src/test/java/dev/cel/runtime/RuntimeEqualityTest.java b/runtime/src/test/java/dev/cel/runtime/RuntimeEqualityTest.java index 250584f48..b75015213 100644 --- a/runtime/src/test/java/dev/cel/runtime/RuntimeEqualityTest.java +++ b/runtime/src/test/java/dev/cel/runtime/RuntimeEqualityTest.java @@ -52,7 +52,7 @@ import dev.cel.common.internal.DynamicProto; import java.util.Arrays; import java.util.List; -import org.jspecify.nullness.Nullable; +import org.jspecify.annotations.Nullable; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; From 6a1185be7c982668e871c2bbd842fb807d31e333 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Fri, 21 Jun 2024 12:59:13 -0700 Subject: [PATCH 130/486] Check for presence of optional indices to prevent autoboxing PiperOrigin-RevId: 645476381 --- .../src/main/java/dev/cel/runtime/DefaultInterpreter.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java b/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java index 7239edda3..b1b228803 100644 --- a/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java +++ b/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java @@ -711,7 +711,6 @@ private IntermediateResult evalBooleanNonstrict(ExecutionFrame frame, CelExpr ex private IntermediateResult evalList(ExecutionFrame frame, CelExpr unusedExpr, CelList listExpr) throws InterpreterException { - CallArgumentChecker argChecker = CallArgumentChecker.create(frame.getResolver()); List result = new ArrayList<>(listExpr.elements().size()); @@ -726,7 +725,11 @@ private IntermediateResult evalList(ExecutionFrame frame, CelExpr unusedExpr, Ce argChecker.checkArg(evaluatedElement); Object value = evaluatedElement.value(); - if (optionalIndicesSet.contains(i) && !isUnknownValue(value)) { + if (!optionalIndicesSet + .isEmpty() // Performance optimization to prevent autoboxing when there's no + // optionals. + && optionalIndicesSet.contains(i) + && !isUnknownValue(value)) { Optional optionalVal = (Optional) value; if (!optionalVal.isPresent()) { continue; From f2d263552bc0f57c7dddec468aeaae8229925974 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Mon, 24 Jun 2024 11:01:19 -0700 Subject: [PATCH 131/486] Remove PartialMessage and IncompleteData PiperOrigin-RevId: 646154419 --- .../src/main/java/dev/cel/runtime/BUILD.bazel | 5 - .../dev/cel/runtime/DefaultInterpreter.java | 18 +- .../java/dev/cel/runtime/IncompleteData.java | 26 - .../java/dev/cel/runtime/InterpreterUtil.java | 23 - .../java/dev/cel/runtime/PartialMessage.java | 181 ----- .../cel/runtime/PartialMessageOrBuilder.java | 46 -- .../cel/runtime/CelValueInterpreterTest.java | 15 - .../src/test/resources/unknownField.baseline | 518 +------------- .../test/resources/unknownResultSet.baseline | 657 +++--------------- .../dev/cel/testing/BaseInterpreterTest.java | 200 ++---- 10 files changed, 168 insertions(+), 1521 deletions(-) delete mode 100644 runtime/src/main/java/dev/cel/runtime/IncompleteData.java delete mode 100644 runtime/src/main/java/dev/cel/runtime/PartialMessage.java delete mode 100644 runtime/src/main/java/dev/cel/runtime/PartialMessageOrBuilder.java diff --git a/runtime/src/main/java/dev/cel/runtime/BUILD.bazel b/runtime/src/main/java/dev/cel/runtime/BUILD.bazel index 335c6e332..f51706987 100644 --- a/runtime/src/main/java/dev/cel/runtime/BUILD.bazel +++ b/runtime/src/main/java/dev/cel/runtime/BUILD.bazel @@ -8,7 +8,6 @@ package( BASE_SOURCES = [ "DefaultMetadata.java", - "IncompleteData.java", "InterpreterException.java", "MessageProvider.java", "Metadata.java", @@ -31,8 +30,6 @@ INTERPRETER_SOURCES = [ "Interpreter.java", "InterpreterUtil.java", "MessageFactory.java", - "PartialMessage.java", - "PartialMessageOrBuilder.java", "RuntimeTypeProvider.java", "RuntimeUnknownResolver.java", "UnknownTrackingInterpretable.java", @@ -98,7 +95,6 @@ java_library( "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", - "@maven//:com_google_protobuf_protobuf_java_util", "@maven//:org_jspecify_jspecify", ], ) @@ -247,7 +243,6 @@ java_library( ], deps = [ ":base", - "//common:error_codes", "//common/annotations", "@cel_spec//proto/cel/expr:expr_java_proto", "@maven//:com_google_errorprone_error_prone_annotations", diff --git a/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java b/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java index b1b228803..b35c4dea6 100644 --- a/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java +++ b/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java @@ -177,10 +177,7 @@ public Object evalTrackingUnknowns( ExecutionFrame frame = new ExecutionFrame(listener, resolver, celOptions.comprehensionMaxIterations()); IntermediateResult internalResult = evalInternal(frame, ast.getExpr()); - Object result = internalResult.value(); - // TODO: remove support for IncompleteData. - return InterpreterUtil.completeDataOnly( - result, "Incomplete data cannot be returned as a result."); + return internalResult.value(); } private IntermediateResult evalInternal(ExecutionFrame frame, CelExpr expr) @@ -388,10 +385,6 @@ private IntermediateResult evalCall(ExecutionFrame frame, CelExpr expr, CelCall // Default evaluation is strict so errors will propagate (via thrown Java exception) before // unknowns. argResults[i] = evalInternal(frame, callArgs.get(i)); - // TODO: remove support for IncompleteData after migrating users to attribute - // tracking unknowns. - InterpreterUtil.completeDataOnly( - argResults[i].value(), "Incomplete data does not support function calls."); } Optional indexAttr = @@ -719,9 +712,6 @@ private IntermediateResult evalList(ExecutionFrame frame, CelExpr unusedExpr, Ce for (int i = 0; i < elements.size(); i++) { CelExpr element = elements.get(i); IntermediateResult evaluatedElement = evalInternal(frame, element); - // TODO: remove support for IncompleteData. - InterpreterUtil.completeDataOnly( - evaluatedElement.value(), "Incomplete data cannot be an elem of a list."); argChecker.checkArg(evaluatedElement); Object value = evaluatedElement.value(); @@ -756,9 +746,6 @@ private IntermediateResult evalMap(ExecutionFrame frame, CelMap mapExpr) argChecker.checkArg(keyResult); IntermediateResult valueResult = evalInternal(frame, entry.value()); - // TODO: remove support for IncompleteData. - InterpreterUtil.completeDataOnly( - valueResult.value(), "Incomplete data cannot be a value of a map."); argChecker.checkArg(valueResult); if (celOptions.errorOnDuplicateMapKeys() && result.containsKey(keyResult.value())) { @@ -801,9 +788,6 @@ private IntermediateResult evalStruct(ExecutionFrame frame, CelExpr expr, CelStr Map fields = new HashMap<>(); for (CelStruct.Entry entry : structExpr.entries()) { IntermediateResult fieldResult = evalInternal(frame, entry.value()); - // TODO: remove support for IncompleteData - InterpreterUtil.completeDataOnly( - fieldResult.value(), "Incomplete data cannot be a field of a message."); argChecker.checkArg(fieldResult); Object value = fieldResult.value(); diff --git a/runtime/src/main/java/dev/cel/runtime/IncompleteData.java b/runtime/src/main/java/dev/cel/runtime/IncompleteData.java deleted file mode 100644 index 4859f63c6..000000000 --- a/runtime/src/main/java/dev/cel/runtime/IncompleteData.java +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2022 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.runtime; - -import dev.cel.common.annotations.Internal; - -/** - * Add an interface for interpreter to check if an object is an instance of {@link PartialMessage}. - * - *

Deprecated. New clients should use {@link CelAttribute} based unknowns. - */ -@Deprecated -@Internal -public interface IncompleteData {} diff --git a/runtime/src/main/java/dev/cel/runtime/InterpreterUtil.java b/runtime/src/main/java/dev/cel/runtime/InterpreterUtil.java index c2dac9cd0..7f2808c0e 100644 --- a/runtime/src/main/java/dev/cel/runtime/InterpreterUtil.java +++ b/runtime/src/main/java/dev/cel/runtime/InterpreterUtil.java @@ -16,8 +16,6 @@ import dev.cel.expr.ExprValue; import dev.cel.expr.UnknownSet; -import com.google.errorprone.annotations.CanIgnoreReturnValue; -import dev.cel.common.CelErrorCode; import dev.cel.common.annotations.Internal; import java.util.Arrays; import java.util.LinkedHashSet; @@ -62,27 +60,6 @@ public static boolean isUnknown(Object obj) { && ((ExprValue) obj).getKindCase() == ExprValue.KindCase.UNKNOWN; } - /** - * Throws an InterpreterException with {@code exceptionMessage} if the {@code obj} is an instance - * of {@link IncompleteData}. {@link IncompleteData} does not support some operators. - * - *

Returns the obj argument otherwise. - * - *

Deprecated. TODO: Can be removed once clients have stopped using - * IncompleteData. - */ - @CanIgnoreReturnValue - @Deprecated - public static Object completeDataOnly(Object obj, String exceptionMessage) - throws InterpreterException { - if (obj instanceof IncompleteData) { - throw new InterpreterException.Builder(exceptionMessage) - .setErrorCode(CelErrorCode.INVALID_ARGUMENT) - .build(); - } - return obj; - } - /** * Combine multiple ExprValue objects which has UnknownSet into one ExprValue * diff --git a/runtime/src/main/java/dev/cel/runtime/PartialMessage.java b/runtime/src/main/java/dev/cel/runtime/PartialMessage.java deleted file mode 100644 index 0d9ad5dca..000000000 --- a/runtime/src/main/java/dev/cel/runtime/PartialMessage.java +++ /dev/null @@ -1,181 +0,0 @@ -// Copyright 2022 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.runtime; - -import com.google.protobuf.Descriptors; -import com.google.protobuf.Descriptors.Descriptor; -import com.google.protobuf.Descriptors.FieldDescriptor; -import com.google.protobuf.Descriptors.OneofDescriptor; -import com.google.protobuf.FieldMask; -import com.google.protobuf.Message; -import com.google.protobuf.UnknownFieldSet; -import com.google.protobuf.util.FieldMaskUtil; -import dev.cel.common.annotations.Internal; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -/** - * Wrap a Message to throw an error on access to certain fields or sub-fields, as described by a - * FieldMask. - * - *

Deprecated. New clients should use {@link CelAttribute} based unknowns. - */ -@Deprecated -@Internal -public class PartialMessage implements PartialMessageOrBuilder, IncompleteData { - - private final Message message; - private final FieldMask fieldMask; - - @Override - public Message getDefaultInstanceForType() { - return message.getDefaultInstanceForType(); - } - - @Override - public boolean isInitialized() { - return message.isInitialized(); - } - - @Override - public List findInitializationErrors() { - return message.findInitializationErrors(); - } - - @Override - public String getInitializationErrorString() { - return message.getInitializationErrorString(); - } - - @Override - public Descriptor getDescriptorForType() { - return message.getDescriptorForType(); - } - - @Override - public Map getAllFields() { - return message.getAllFields(); - } - - @Override - public boolean hasOneof(OneofDescriptor oneof) { - return message.hasOneof(oneof); - } - - @Override - public FieldDescriptor getOneofFieldDescriptor(OneofDescriptor oneof) { - return message.getOneofFieldDescriptor(oneof); - } - - @Override - public boolean hasField(FieldDescriptor field) { - return message.hasField(field); - } - - /** Create relative field masks to the field specified by the name. */ - private FieldMask subpathMask(String name) { - FieldMask.Builder builder = FieldMask.newBuilder(); - for (String p : fieldMask.getPathsList()) { - if (!p.startsWith(name)) { - continue; - } - String tmp = p.substring(name.length() + 1); - if (tmp.length() > 0) { - builder.addPaths(tmp); - } - } - return builder.build(); - } - - @Override - public Object getField(Descriptors.FieldDescriptor field) { - String path = field.getName(); - - if (fieldMask.getPathsList().contains(path)) { - return InterpreterUtil.createUnknownExprValue(new ArrayList()); - } - - Object obj = message.getField(field); - FieldMask subFieldMask = subpathMask(path); - if (obj instanceof Message && !subFieldMask.getPathsList().isEmpty()) { - // Partial message means at least one of its field has been marked as unknown - return new PartialMessage((Message) obj, subFieldMask); - } else { - return obj; - } - } - - @Override - public int getRepeatedFieldCount(FieldDescriptor field) { - return message.getRepeatedFieldCount(field); - } - - @Override - public Object getRepeatedField(FieldDescriptor field, int index) { - return message.getRepeatedField(field, index); - } - - @Override - public UnknownFieldSet getUnknownFields() { - return message.getUnknownFields(); - } - - public PartialMessage(Message m) { - this.message = m; - this.fieldMask = FieldMask.getDefaultInstance(); - } - - public PartialMessage(Message m, FieldMask mask) { - this.message = m; - this.fieldMask = mask; - - if (m == null) { - throw new NullPointerException("The message in PartialMessage is null."); - } - if (!FieldMaskUtil.isValid(m.getDescriptorForType(), fieldMask)) { - throw new RuntimeException( - new InterpreterException.Builder("Invalid field mask for message:" + message).build()); - } - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append(this.getClass()); - sb.append("{\nmessage: {\n"); - sb.append(this.message); - sb.append("},\nfieldMask: {\n"); - for (Iterator it = fieldMask.getPathsList().iterator(); it.hasNext(); ) { - sb.append(" paths: ").append(it.next()); - if (it.hasNext()) { - sb.append(",\n"); - } - } - sb.append("\n}\n"); - return sb.toString(); - } - - @Override - public Message getMessage() { - return message; - } - - @Override - public FieldMask getFieldMask() { - return fieldMask; - } -} diff --git a/runtime/src/main/java/dev/cel/runtime/PartialMessageOrBuilder.java b/runtime/src/main/java/dev/cel/runtime/PartialMessageOrBuilder.java deleted file mode 100644 index 9009ea37e..000000000 --- a/runtime/src/main/java/dev/cel/runtime/PartialMessageOrBuilder.java +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2022 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.runtime; - -import com.google.protobuf.Descriptors.FieldDescriptor; -import com.google.protobuf.FieldMask; -import com.google.protobuf.Message; -import com.google.protobuf.MessageOrBuilder; -import dev.cel.common.annotations.Internal; - -/** - * Wrap Message to support Unknown value. - * - *

Deprecated. New clients should use {@link CelAttribute} based unknowns. - */ -@Deprecated -@Internal -public interface PartialMessageOrBuilder extends MessageOrBuilder { - /** Return original message. */ - public Message getMessage(); - - /* - * Return field mask. - */ - public FieldMask getFieldMask(); - - /** - * This method is similar to {@link MessageOrBuilder#getField(FieldDescriptor)}, with the - * following differences: This method may throw an InterpreterException wrapped with a - * RuntimeException, if the field path is set in the Field mask. - */ - @Override - public Object getField(FieldDescriptor field); -} diff --git a/runtime/src/test/java/dev/cel/runtime/CelValueInterpreterTest.java b/runtime/src/test/java/dev/cel/runtime/CelValueInterpreterTest.java index 4c657a0c8..2ef7a250f 100644 --- a/runtime/src/test/java/dev/cel/runtime/CelValueInterpreterTest.java +++ b/runtime/src/test/java/dev/cel/runtime/CelValueInterpreterTest.java @@ -22,7 +22,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; @@ -44,20 +43,6 @@ public CelValueInterpreterTest(boolean declareWithCelType, Eval eval) { super(declareWithCelType, eval); } - /** Test relies on PartialMessage, which is deprecated and not supported for CelValue. */ - @Override - @Test - public void unknownField() { - skipBaselineVerification(); - } - - /** Test relies on PartialMessage, which is deprecated and not supported for CelValue. */ - @Override - @Test - public void unknownResultSet() { - skipBaselineVerification(); - } - @Parameters public static List testData() { return new ArrayList<>( diff --git a/runtime/src/test/resources/unknownField.baseline b/runtime/src/test/resources/unknownField.baseline index 2831bfd9b..92f0a7385 100644 --- a/runtime/src/test/resources/unknownField.baseline +++ b/runtime/src/test/resources/unknownField.baseline @@ -3,30 +3,9 @@ declare x { value dev.cel.testing.testdata.proto3.TestAllTypes } =====> -bindings: {x=class dev.cel.runtime.PartialMessage{ -message: { -single_nested_message { -} -repeated_nested_message { - bb: 14 -} -single_duration { - seconds: 15 -} -single_timestamp { - seconds: 15 -} -}, -fieldMask: { - paths: map_int32_int64, - paths: single_int32, - paths: single_nested_message.bb, - paths: repeated_nested_message, - paths: single_duration.seconds -} -} +bindings: {} result: unknown { - exprs: 2 + exprs: 1 } @@ -35,30 +14,9 @@ declare x { value dev.cel.testing.testdata.proto3.TestAllTypes } =====> -bindings: {x=class dev.cel.runtime.PartialMessage{ -message: { -single_nested_message { -} -repeated_nested_message { - bb: 14 -} -single_duration { - seconds: 15 -} -single_timestamp { - seconds: 15 -} -}, -fieldMask: { - paths: map_int32_int64, - paths: single_int32, - paths: single_nested_message.bb, - paths: repeated_nested_message, - paths: single_duration.seconds -} -} +bindings: {} result: unknown { - exprs: 2 + exprs: 1 } @@ -67,30 +25,9 @@ declare x { value dev.cel.testing.testdata.proto3.TestAllTypes } =====> -bindings: {x=class dev.cel.runtime.PartialMessage{ -message: { -single_nested_message { -} -repeated_nested_message { - bb: 14 -} -single_duration { - seconds: 15 -} -single_timestamp { - seconds: 15 -} -}, -fieldMask: { - paths: map_int32_int64, - paths: single_int32, - paths: single_nested_message.bb, - paths: repeated_nested_message, - paths: single_duration.seconds -} -} +bindings: {} result: unknown { - exprs: 2 + exprs: 1 } @@ -99,465 +36,40 @@ declare x { value dev.cel.testing.testdata.proto3.TestAllTypes } =====> -bindings: {x=class dev.cel.runtime.PartialMessage{ -message: { -single_nested_message { -} -repeated_nested_message { - bb: 14 -} -single_duration { - seconds: 15 -} -single_timestamp { - seconds: 15 -} -}, -fieldMask: { - paths: map_int32_int64, - paths: single_int32, - paths: single_nested_message.bb, - paths: repeated_nested_message, - paths: single_duration.seconds -} -} -result: 15 - -Source: x.single_duration.getMilliseconds() -declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes -} -=====> -bindings: {x=class dev.cel.runtime.PartialMessage{ -message: { -single_nested_message { -} -repeated_nested_message { - bb: 14 -} -single_duration { - seconds: 15 -} -single_timestamp { - seconds: 15 -} -}, -fieldMask: { - paths: map_int32_int64, - paths: single_int32, - paths: single_nested_message.bb, - paths: repeated_nested_message, - paths: single_duration.seconds -} +bindings: {} +result: unknown { + exprs: 1 } -error: evaluation error: Incomplete data does not support function calls. -error_code: INVALID_ARGUMENT -Source: x.single_duration + x.single_duration -declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes -} -=====> -bindings: {x=class dev.cel.runtime.PartialMessage{ -message: { -single_nested_message { -} -repeated_nested_message { - bb: 14 -} -single_duration { - seconds: 15 -} -single_timestamp { - seconds: 15 -} -}, -fieldMask: { - paths: map_int32_int64, - paths: single_int32, - paths: single_nested_message.bb, - paths: repeated_nested_message, - paths: single_duration.seconds -} -} -error: evaluation error: Incomplete data does not support function calls. -error_code: INVALID_ARGUMENT Source: x.single_nested_message.bb declare x { value dev.cel.testing.testdata.proto3.TestAllTypes } =====> -bindings: {x=class dev.cel.runtime.PartialMessage{ -message: { -single_nested_message { -} -repeated_nested_message { - bb: 14 -} -single_duration { - seconds: 15 -} -single_timestamp { - seconds: 15 -} -}, -fieldMask: { - paths: map_int32_int64, - paths: single_int32, - paths: single_nested_message.bb, - paths: repeated_nested_message, - paths: single_duration.seconds -} -} +bindings: {} result: unknown { - exprs: 3 + exprs: 1 } -Source: x.single_nested_message -declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes -} -=====> -bindings: {x=class dev.cel.runtime.PartialMessage{ -message: { -single_nested_message { -} -repeated_nested_message { - bb: 14 -} -single_duration { - seconds: 15 -} -single_timestamp { - seconds: 15 -} -}, -fieldMask: { - paths: map_int32_int64, - paths: single_int32, - paths: single_nested_message.bb, - paths: repeated_nested_message, - paths: single_duration.seconds -} -} -error: evaluation error: Incomplete data cannot be returned as a result. -error_code: INVALID_ARGUMENT - -Source: TestAllTypes{single_nested_message: x.single_nested_message} -declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes -} -=====> -bindings: {x=class dev.cel.runtime.PartialMessage{ -message: { -single_nested_message { -} -repeated_nested_message { - bb: 14 -} -single_duration { - seconds: 15 -} -single_timestamp { - seconds: 15 -} -}, -fieldMask: { - paths: map_int32_int64, - paths: single_int32, - paths: single_nested_message.bb, - paths: repeated_nested_message, - paths: single_duration.seconds -} -} -error: evaluation error: Incomplete data cannot be a field of a message. -error_code: INVALID_ARGUMENT - Source: {1: x.single_int32} declare x { value dev.cel.testing.testdata.proto3.TestAllTypes } =====> -bindings: {x=class dev.cel.runtime.PartialMessage{ -message: { -single_nested_message { -} -repeated_nested_message { - bb: 14 -} -single_duration { - seconds: 15 -} -single_timestamp { - seconds: 15 -} -}, -fieldMask: { - paths: map_int32_int64, - paths: single_int32, - paths: single_nested_message.bb, - paths: repeated_nested_message, - paths: single_duration.seconds -} -} -result: unknown { - exprs: 5 -} - - -Source: {1: x.single_int64} -declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes -} -=====> -bindings: {x=class dev.cel.runtime.PartialMessage{ -message: { -single_nested_message { -} -repeated_nested_message { - bb: 14 -} -single_duration { - seconds: 15 -} -single_timestamp { - seconds: 15 -} -}, -fieldMask: { - paths: map_int32_int64, - paths: single_int32, - paths: single_nested_message.bb, - paths: repeated_nested_message, - paths: single_duration.seconds -} -} -result: {1=0} - -Source: {1: x.single_nested_message} -declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes -} -=====> -bindings: {x=class dev.cel.runtime.PartialMessage{ -message: { -single_nested_message { -} -repeated_nested_message { - bb: 14 -} -single_duration { - seconds: 15 -} -single_timestamp { - seconds: 15 -} -}, -fieldMask: { - paths: map_int32_int64, - paths: single_int32, - paths: single_nested_message.bb, - paths: repeated_nested_message, - paths: single_duration.seconds -} -} -error: evaluation error: Incomplete data cannot be a value of a map. -error_code: INVALID_ARGUMENT - -Source: [1, x.single_int32] -declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes -} -=====> -bindings: {x=class dev.cel.runtime.PartialMessage{ -message: { -single_nested_message { -} -repeated_nested_message { - bb: 14 -} -single_duration { - seconds: 15 -} -single_timestamp { - seconds: 15 -} -}, -fieldMask: { - paths: map_int32_int64, - paths: single_int32, - paths: single_nested_message.bb, - paths: repeated_nested_message, - paths: single_duration.seconds -} -} +bindings: {} result: unknown { exprs: 4 } -Source: [x.single_nested_message] -declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes -} -=====> -bindings: {x=class dev.cel.runtime.PartialMessage{ -message: { -single_nested_message { -} -repeated_nested_message { - bb: 14 -} -single_duration { - seconds: 15 -} -single_timestamp { - seconds: 15 -} -}, -fieldMask: { - paths: map_int32_int64, - paths: single_int32, - paths: single_nested_message.bb, - paths: repeated_nested_message, - paths: single_duration.seconds -} -} -error: evaluation error: Incomplete data cannot be an elem of a list. -error_code: INVALID_ARGUMENT - -Source: x.single_nested_message.bb -declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes -} -=====> -bindings: {x=class dev.cel.runtime.PartialMessage{ -message: { -single_nested_message { -} -repeated_nested_message { - bb: 14 -} -single_duration { - seconds: 15 -} -single_timestamp { - seconds: 15 -} -}, -fieldMask: { - paths: single_nested_message -} -} -result: unknown { - exprs: 2 -} - - -Source: (x.single_nested_message.bb == 42) || true -declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes -} -=====> -bindings: {x=class dev.cel.runtime.PartialMessage{ -message: { -single_nested_message { -} -repeated_nested_message { - bb: 14 -} -single_duration { - seconds: 15 -} -single_timestamp { - seconds: 15 -} -}, -fieldMask: { - paths: single_nested_message -} -} -result: true - -Source: (x.single_nested_message.bb == 42) || false -declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes -} -=====> -bindings: {x=class dev.cel.runtime.PartialMessage{ -message: { -single_nested_message { -} -repeated_nested_message { - bb: 14 -} -single_duration { - seconds: 15 -} -single_timestamp { - seconds: 15 -} -}, -fieldMask: { - paths: single_nested_message -} -} -result: unknown { - exprs: 2 -} - - -Source: (x.single_nested_message.bb == 42) && true +Source: [1, x.single_int32] declare x { value dev.cel.testing.testdata.proto3.TestAllTypes } =====> -bindings: {x=class dev.cel.runtime.PartialMessage{ -message: { -single_nested_message { -} -repeated_nested_message { - bb: 14 -} -single_duration { - seconds: 15 -} -single_timestamp { - seconds: 15 -} -}, -fieldMask: { - paths: single_nested_message -} -} +bindings: {} result: unknown { - exprs: 2 -} - - -Source: (x.single_nested_message.bb == 42) && false -declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes -} -=====> -bindings: {x=class dev.cel.runtime.PartialMessage{ -message: { -single_nested_message { -} -repeated_nested_message { - bb: 14 -} -single_duration { - seconds: 15 -} -single_timestamp { - seconds: 15 -} -}, -fieldMask: { - paths: single_nested_message -} + exprs: 3 } -result: false diff --git a/runtime/src/test/resources/unknownResultSet.baseline b/runtime/src/test/resources/unknownResultSet.baseline index aa9d032ff..eb7532b8b 100644 --- a/runtime/src/test/resources/unknownResultSet.baseline +++ b/runtime/src/test/resources/unknownResultSet.baseline @@ -1,44 +1,20 @@ -Source: x.single_int32 == 1 && x.single_string == "test" +Source: x.single_int32 == 1 && true declare x { value dev.cel.testing.testdata.proto3.TestAllTypes } =====> -bindings: {x=class dev.cel.runtime.PartialMessage{ -message: { -single_string: "test" -single_timestamp { - seconds: 15 -} -}, -fieldMask: { - paths: single_int32, - paths: single_int64, - paths: map_int32_int64 -} -} +bindings: {} result: unknown { - exprs: 2 + exprs: 1 } -Source: x.single_int32 == 1 && x.single_string != "test" +Source: x.single_int32 == 1 && false declare x { value dev.cel.testing.testdata.proto3.TestAllTypes } =====> -bindings: {x=class dev.cel.runtime.PartialMessage{ -message: { -single_string: "test" -single_timestamp { - seconds: 15 -} -}, -fieldMask: { - paths: single_int32, - paths: single_int64, - paths: map_int32_int64 -} -} +bindings: {} result: false Source: x.single_int32 == 1 && x.single_int64 == 1 @@ -46,22 +22,10 @@ declare x { value dev.cel.testing.testdata.proto3.TestAllTypes } =====> -bindings: {x=class dev.cel.runtime.PartialMessage{ -message: { -single_string: "test" -single_timestamp { - seconds: 15 -} -}, -fieldMask: { - paths: single_int32, - paths: single_int64, - paths: map_int32_int64 -} -} +bindings: {} result: unknown { - exprs: 2 - exprs: 7 + exprs: 1 + exprs: 6 } @@ -70,65 +34,29 @@ declare x { value dev.cel.testing.testdata.proto3.TestAllTypes } =====> -bindings: {x=class dev.cel.runtime.PartialMessage{ -message: { -single_string: "test" -single_timestamp { - seconds: 15 -} -}, -fieldMask: { - paths: single_int32, - paths: single_int64, - paths: map_int32_int64 -} -} +bindings: {} result: unknown { - exprs: 2 + exprs: 1 } -Source: x.single_string == "test" && x.single_int32 == 1 +Source: true && x.single_int32 == 1 declare x { value dev.cel.testing.testdata.proto3.TestAllTypes } =====> -bindings: {x=class dev.cel.runtime.PartialMessage{ -message: { -single_string: "test" -single_timestamp { - seconds: 15 -} -}, -fieldMask: { - paths: single_int32, - paths: single_int64, - paths: map_int32_int64 -} -} +bindings: {} result: unknown { - exprs: 7 + exprs: 3 } -Source: x.single_string != "test" && x.single_int32 == 1 +Source: false && x.single_int32 == 1 declare x { value dev.cel.testing.testdata.proto3.TestAllTypes } =====> -bindings: {x=class dev.cel.runtime.PartialMessage{ -message: { -single_string: "test" -single_timestamp { - seconds: 15 -} -}, -fieldMask: { - paths: single_int32, - paths: single_int64, - paths: map_int32_int64 -} -} +bindings: {} result: false Source: x.single_timestamp <= timestamp("bad timestamp string") && x.single_int32 == 1 @@ -136,21 +64,9 @@ declare x { value dev.cel.testing.testdata.proto3.TestAllTypes } =====> -bindings: {x=class dev.cel.runtime.PartialMessage{ -message: { -single_string: "test" -single_timestamp { - seconds: 15 -} -}, -fieldMask: { - paths: single_int32, - paths: single_int64, - paths: map_int32_int64 -} -} +bindings: {} result: unknown { - exprs: 8 + exprs: 7 } @@ -159,19 +75,7 @@ declare x { value dev.cel.testing.testdata.proto3.TestAllTypes } =====> -bindings: {x=class dev.cel.runtime.PartialMessage{ -message: { -single_string: "test" -single_timestamp { - seconds: 15 -} -}, -fieldMask: { - paths: single_int32, - paths: single_int64, - paths: map_int32_int64 -} -} +bindings: {} error: evaluation error: Failed to parse timestamp: invalid timestamp "bad timestamp string" error_code: BAD_FORMAT @@ -180,41 +84,22 @@ declare x { value dev.cel.testing.testdata.proto3.TestAllTypes } =====> -bindings: {x=class dev.cel.runtime.PartialMessage{ -message: { -single_string: "test" -single_timestamp { - seconds: 15 -} -}, -fieldMask: { - paths: single_int32, - paths: single_int64, - paths: map_int32_int64 -} +bindings: {} +result: unknown { + exprs: 1 + exprs: 6 } -result: true + Source: x.single_int32 == 1 || x.single_string != "test" declare x { value dev.cel.testing.testdata.proto3.TestAllTypes } =====> -bindings: {x=class dev.cel.runtime.PartialMessage{ -message: { -single_string: "test" -single_timestamp { - seconds: 15 -} -}, -fieldMask: { - paths: single_int32, - paths: single_int64, - paths: map_int32_int64 -} -} +bindings: {} result: unknown { - exprs: 2 + exprs: 1 + exprs: 6 } @@ -223,22 +108,10 @@ declare x { value dev.cel.testing.testdata.proto3.TestAllTypes } =====> -bindings: {x=class dev.cel.runtime.PartialMessage{ -message: { -single_string: "test" -single_timestamp { - seconds: 15 -} -}, -fieldMask: { - paths: single_int32, - paths: single_int64, - paths: map_int32_int64 -} -} +bindings: {} result: unknown { - exprs: 2 - exprs: 7 + exprs: 1 + exprs: 6 } @@ -247,64 +120,28 @@ declare x { value dev.cel.testing.testdata.proto3.TestAllTypes } =====> -bindings: {x=class dev.cel.runtime.PartialMessage{ -message: { -single_string: "test" -single_timestamp { - seconds: 15 -} -}, -fieldMask: { - paths: single_int32, - paths: single_int64, - paths: map_int32_int64 -} -} +bindings: {} result: unknown { - exprs: 2 + exprs: 1 } -Source: x.single_string == "test" || x.single_int32 == 1 +Source: true || x.single_int32 == 1 declare x { value dev.cel.testing.testdata.proto3.TestAllTypes } =====> -bindings: {x=class dev.cel.runtime.PartialMessage{ -message: { -single_string: "test" -single_timestamp { - seconds: 15 -} -}, -fieldMask: { - paths: single_int32, - paths: single_int64, - paths: map_int32_int64 -} -} +bindings: {} result: true -Source: x.single_string != "test" || x.single_int32 == 1 +Source: false || x.single_int32 == 1 declare x { value dev.cel.testing.testdata.proto3.TestAllTypes } =====> -bindings: {x=class dev.cel.runtime.PartialMessage{ -message: { -single_string: "test" -single_timestamp { - seconds: 15 -} -}, -fieldMask: { - paths: single_int32, - paths: single_int64, - paths: map_int32_int64 -} -} +bindings: {} result: unknown { - exprs: 7 + exprs: 3 } @@ -313,21 +150,9 @@ declare x { value dev.cel.testing.testdata.proto3.TestAllTypes } =====> -bindings: {x=class dev.cel.runtime.PartialMessage{ -message: { -single_string: "test" -single_timestamp { - seconds: 15 -} -}, -fieldMask: { - paths: single_int32, - paths: single_int64, - paths: map_int32_int64 -} -} +bindings: {} result: unknown { - exprs: 8 + exprs: 7 } @@ -336,19 +161,7 @@ declare x { value dev.cel.testing.testdata.proto3.TestAllTypes } =====> -bindings: {x=class dev.cel.runtime.PartialMessage{ -message: { -single_string: "test" -single_timestamp { - seconds: 15 -} -}, -fieldMask: { - paths: single_int32, - paths: single_int64, - paths: map_int32_int64 -} -} +bindings: {} error: evaluation error: Failed to parse timestamp: invalid timestamp "bad timestamp string" error_code: BAD_FORMAT @@ -360,21 +173,9 @@ declare f { function f int.(int) -> bool } =====> -bindings: {x=class dev.cel.runtime.PartialMessage{ -message: { -single_string: "test" -single_timestamp { - seconds: 15 -} -}, -fieldMask: { - paths: single_int32, - paths: single_int64, - paths: map_int32_int64 -} -} +bindings: {} result: unknown { - exprs: 2 + exprs: 1 } @@ -386,21 +187,9 @@ declare f { function f int.(int) -> bool } =====> -bindings: {x=class dev.cel.runtime.PartialMessage{ -message: { -single_string: "test" -single_timestamp { - seconds: 15 -} -}, -fieldMask: { - paths: single_int32, - paths: single_int64, - paths: map_int32_int64 -} -} +bindings: {} result: unknown { - exprs: 4 + exprs: 3 } @@ -412,22 +201,10 @@ declare f { function f int.(int) -> bool } =====> -bindings: {x=class dev.cel.runtime.PartialMessage{ -message: { -single_string: "test" -single_timestamp { - seconds: 15 -} -}, -fieldMask: { - paths: single_int32, - paths: single_int64, - paths: map_int32_int64 -} -} +bindings: {} result: unknown { - exprs: 2 - exprs: 5 + exprs: 1 + exprs: 4 } @@ -439,18 +216,10 @@ declare f { function f int.(int) -> bool } =====> -bindings: {y=class dev.cel.runtime.PartialMessage{ -message: { -single_string: "test" +bindings: {y=single_string: "test" single_timestamp { seconds: 15 } -}, -fieldMask: { - paths: single_int32, - paths: single_int64, - paths: map_int32_int64 -} } result: unknown { exprs: 1 @@ -481,21 +250,9 @@ declare f { function f int.(int) -> bool } =====> -bindings: {x=class dev.cel.runtime.PartialMessage{ -message: { -single_string: "test" -single_timestamp { - seconds: 15 -} -}, -fieldMask: { - paths: single_int32, - paths: single_int64, - paths: map_int32_int64 -} -} +bindings: {} result: unknown { - exprs: 2 + exprs: 1 } @@ -507,19 +264,7 @@ declare f { function f int.(int) -> bool } =====> -bindings: {x=class dev.cel.runtime.PartialMessage{ -message: { -single_string: "test" -single_timestamp { - seconds: 15 -} -}, -fieldMask: { - paths: single_int32, - paths: single_int64, - paths: map_int32_int64 -} -} +bindings: {} result: true Source: [0, 2, 4].exists(z, z == x.single_int32) @@ -530,21 +275,9 @@ declare f { function f int.(int) -> bool } =====> -bindings: {x=class dev.cel.runtime.PartialMessage{ -message: { -single_string: "test" -single_timestamp { - seconds: 15 -} -}, -fieldMask: { - paths: single_int32, - paths: single_int64, - paths: map_int32_int64 -} -} +bindings: {} result: unknown { - exprs: 10 + exprs: 9 } @@ -556,21 +289,9 @@ declare f { function f int.(int) -> bool } =====> -bindings: {x=class dev.cel.runtime.PartialMessage{ -message: { -single_string: "test" -single_timestamp { - seconds: 15 -} -}, -fieldMask: { - paths: single_int32, - paths: single_int64, - paths: map_int32_int64 -} -} +bindings: {} result: unknown { - exprs: 27 + exprs: 26 } @@ -582,21 +303,9 @@ declare f { function f int.(int) -> bool } =====> -bindings: {x=class dev.cel.runtime.PartialMessage{ -message: { -single_string: "test" -single_timestamp { - seconds: 15 -} -}, -fieldMask: { - paths: single_int32, - paths: single_int64, - paths: map_int32_int64 -} -} +bindings: {} result: unknown { - exprs: 13 + exprs: 12 } @@ -608,21 +317,9 @@ declare f { function f int.(int) -> bool } =====> -bindings: {x=class dev.cel.runtime.PartialMessage{ -message: { -single_string: "test" -single_timestamp { - seconds: 15 -} -}, -fieldMask: { - paths: single_int32, - paths: single_int64, - paths: map_int32_int64 -} -} +bindings: {} result: unknown { - exprs: 27 + exprs: 26 } @@ -634,22 +331,10 @@ declare f { function f int.(int) -> bool } =====> -bindings: {x=class dev.cel.runtime.PartialMessage{ -message: { -single_string: "test" -single_timestamp { - seconds: 15 -} -}, -fieldMask: { - paths: single_int32, - paths: single_int64, - paths: map_int32_int64 -} -} +bindings: {} result: unknown { - exprs: 18 - exprs: 27 + exprs: 17 + exprs: 26 } @@ -661,25 +346,13 @@ declare f { function f int.(int) -> bool } =====> -bindings: {x=class dev.cel.runtime.PartialMessage{ -message: { -single_string: "test" -single_timestamp { - seconds: 15 -} -}, -fieldMask: { - paths: single_int32, - paths: single_int64, - paths: map_int32_int64 -} -} +bindings: {} result: unknown { - exprs: 2 + exprs: 1 } -Source: x.single_string == "test" ? x.single_int32 : 2 +Source: true ? x.single_int32 : 2 declare x { value dev.cel.testing.testdata.proto3.TestAllTypes } @@ -687,25 +360,13 @@ declare f { function f int.(int) -> bool } =====> -bindings: {x=class dev.cel.runtime.PartialMessage{ -message: { -single_string: "test" -single_timestamp { - seconds: 15 -} -}, -fieldMask: { - paths: single_int32, - paths: single_int64, - paths: map_int32_int64 -} -} +bindings: {} result: unknown { - exprs: 7 + exprs: 3 } -Source: x.single_string == "test" ? 1 : x.single_int32 +Source: true ? 1 : x.single_int32 declare x { value dev.cel.testing.testdata.proto3.TestAllTypes } @@ -713,22 +374,10 @@ declare f { function f int.(int) -> bool } =====> -bindings: {x=class dev.cel.runtime.PartialMessage{ -message: { -single_string: "test" -single_timestamp { - seconds: 15 -} -}, -fieldMask: { - paths: single_int32, - paths: single_int64, - paths: map_int32_int64 -} -} +bindings: {} result: 1 -Source: x.single_string != "test" ? x.single_int32 : 2 +Source: false ? x.single_int32 : 2 declare x { value dev.cel.testing.testdata.proto3.TestAllTypes } @@ -736,22 +385,10 @@ declare f { function f int.(int) -> bool } =====> -bindings: {x=class dev.cel.runtime.PartialMessage{ -message: { -single_string: "test" -single_timestamp { - seconds: 15 -} -}, -fieldMask: { - paths: single_int32, - paths: single_int64, - paths: map_int32_int64 -} -} +bindings: {} result: 2 -Source: x.single_string != "test" ? 1 : x.single_int32 +Source: false ? 1 : x.single_int32 declare x { value dev.cel.testing.testdata.proto3.TestAllTypes } @@ -759,21 +396,9 @@ declare f { function f int.(int) -> bool } =====> -bindings: {x=class dev.cel.runtime.PartialMessage{ -message: { -single_string: "test" -single_timestamp { - seconds: 15 -} -}, -fieldMask: { - paths: single_int32, - paths: single_int64, - paths: map_int32_int64 -} -} +bindings: {} result: unknown { - exprs: 8 + exprs: 4 } @@ -785,21 +410,9 @@ declare f { function f int.(int) -> bool } =====> -bindings: {x=class dev.cel.runtime.PartialMessage{ -message: { -single_string: "test" -single_timestamp { - seconds: 15 -} -}, -fieldMask: { - paths: single_int32, - paths: single_int64, - paths: map_int32_int64 -} -} +bindings: {} result: unknown { - exprs: 2 + exprs: 1 } @@ -811,21 +424,9 @@ declare f { function f int.(int) -> bool } =====> -bindings: {x=class dev.cel.runtime.PartialMessage{ -message: { -single_string: "test" -single_timestamp { - seconds: 15 -} -}, -fieldMask: { - paths: single_int32, - paths: single_int64, - paths: map_int32_int64 -} -} +bindings: {} result: unknown { - exprs: 4 + exprs: 3 } @@ -837,21 +438,9 @@ declare f { function f int.(int) -> bool } =====> -bindings: {x=class dev.cel.runtime.PartialMessage{ -message: { -single_string: "test" -single_timestamp { - seconds: 15 -} -}, -fieldMask: { - paths: single_int32, - paths: single_int64, - paths: map_int32_int64 -} -} +bindings: {} result: unknown { - exprs: 5 + exprs: 4 } @@ -863,22 +452,10 @@ declare f { function f int.(int) -> bool } =====> -bindings: {x=class dev.cel.runtime.PartialMessage{ -message: { -single_string: "test" -single_timestamp { - seconds: 15 -} -}, -fieldMask: { - paths: single_int32, - paths: single_int64, - paths: map_int32_int64 -} -} +bindings: {} result: unknown { - exprs: 5 - exprs: 8 + exprs: 4 + exprs: 7 } @@ -890,21 +467,9 @@ declare f { function f int.(int) -> bool } =====> -bindings: {x=class dev.cel.runtime.PartialMessage{ -message: { -single_string: "test" -single_timestamp { - seconds: 15 -} -}, -fieldMask: { - paths: single_int32, - paths: single_int64, - paths: map_int32_int64 -} -} +bindings: {} result: unknown { - exprs: 4 + exprs: 3 } @@ -916,22 +481,10 @@ declare f { function f int.(int) -> bool } =====> -bindings: {x=class dev.cel.runtime.PartialMessage{ -message: { -single_string: "test" -single_timestamp { - seconds: 15 -} -}, -fieldMask: { - paths: single_int32, - paths: single_int64, - paths: map_int32_int64 -} -} +bindings: {} result: unknown { - exprs: 4 - exprs: 6 + exprs: 3 + exprs: 5 } @@ -943,21 +496,9 @@ declare f { function f int.(int) -> bool } =====> -bindings: {x=class dev.cel.runtime.PartialMessage{ -message: { -single_string: "test" -single_timestamp { - seconds: 15 -} -}, -fieldMask: { - paths: single_int32, - paths: single_int64, - paths: map_int32_int64 -} -} +bindings: {} result: unknown { - exprs: 4 + exprs: 3 } @@ -969,22 +510,8 @@ declare f { function f int.(int) -> bool } =====> -bindings: {x=class dev.cel.runtime.PartialMessage{ -message: { -single_string: "test" -single_timestamp { - seconds: 15 -} -}, -fieldMask: { - paths: single_int32, - paths: single_int64, - paths: map_int32_int64 -} -} +bindings: {} result: unknown { - exprs: 4 - exprs: 7 + exprs: 3 + exprs: 6 } - - diff --git a/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java b/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java index 43fadd81c..bc9afa55e 100644 --- a/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java +++ b/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java @@ -40,7 +40,6 @@ import com.google.protobuf.DoubleValue; import com.google.protobuf.Duration; import com.google.protobuf.DynamicMessage; -import com.google.protobuf.FieldMask; import com.google.protobuf.FloatValue; import com.google.protobuf.Int32Value; import com.google.protobuf.Int64Value; @@ -63,7 +62,6 @@ import dev.cel.common.types.CelTypes; import dev.cel.runtime.Activation; import dev.cel.runtime.InterpreterException; -import dev.cel.runtime.PartialMessage; import dev.cel.testing.testdata.proto3.StandaloneGlobalEnum; import dev.cel.testing.testdata.proto3.TestAllTypesProto.TestAllTypes; import dev.cel.testing.testdata.proto3.TestAllTypesProto.TestAllTypes.NestedEnum; @@ -1012,189 +1010,111 @@ public void timestampFunctions() throws Exception { public void unknownField() throws Exception { container = TestAllTypes.getDescriptor().getFile().getPackage(); declareVariable("x", CelTypes.createMessage(TestAllTypes.getDescriptor().getFullName())); - TestAllTypes val = - TestAllTypes.newBuilder() - .setSingleTimestamp(Timestamps.fromSeconds(15)) - .setSingleDuration(Durations.fromSeconds(15)) - .setSingleNestedMessage(NestedMessage.getDefaultInstance()) - .addRepeatedNestedMessage(0, NestedMessage.newBuilder().setBb(14).build()) - .build(); - - PartialMessage wm = - new PartialMessage( - val, - FieldMask.newBuilder() - .addPaths("map_int32_int64") - .addPaths("single_int32") - .addPaths("single_nested_message.bb") - .addPaths("repeated_nested_message") - .addPaths("single_duration.seconds") - .build()); // Unknown field is accessed. source = "x.single_int32"; - runTest(Activation.of("x", wm)); + runTest(Activation.EMPTY); source = "x.map_int32_int64[22]"; - runTest(Activation.of("x", wm)); + runTest(Activation.EMPTY); source = "x.repeated_nested_message[1]"; - runTest(Activation.of("x", wm)); + runTest(Activation.EMPTY); - // Function call for a known field. + // Function call for an unknown field. source = "x.single_timestamp.getSeconds()"; - runTest(Activation.of("x", wm)); - - // PartialMessage does not support function call - source = "x.single_duration.getMilliseconds()"; - runTest(Activation.of("x", wm)); - - // PartialMessage does not support operators. - source = "x.single_duration + x.single_duration"; - runTest(Activation.of("x", wm)); + runTest(Activation.EMPTY); // Unknown field in a nested message source = "x.single_nested_message.bb"; - runTest(Activation.of("x", wm)); - - // PartialMessage cannot be a final expr result. - source = "x.single_nested_message"; - runTest(Activation.of("x", wm)); - - // PartialMessage cannot be a field of another message. - source = "TestAllTypes{single_nested_message: x.single_nested_message}"; - runTest(Activation.of("x", wm)); + runTest(Activation.EMPTY); - // Unknown field cannot be a value of a map now. + // Unknown field access in a map. source = "{1: x.single_int32}"; - runTest(Activation.of("x", wm)); - - // Access a known field as a val of a map. - source = "{1: x.single_int64}"; - runTest(Activation.of("x", wm)); - - // PartialMessage cannot be a value of a map. - source = "{1: x.single_nested_message}"; - runTest(Activation.of("x", wm)); + runTest(Activation.EMPTY); - // Unknown field cannot be a value of a list now. + // Unknown field access in a list. source = "[1, x.single_int32]"; - runTest(Activation.of("x", wm)); - - // PartialMessage cannot be an elem in a list. - source = "[x.single_nested_message]"; - runTest(Activation.of("x", wm)); - - // Access a field in a nested message masked as unknown. - wm = new PartialMessage(val, FieldMask.newBuilder().addPaths("single_nested_message").build()); - - // Access unknown field. - source = "x.single_nested_message.bb"; - runTest(Activation.of("x", wm)); - - // Error or true should be true. - source = "(x.single_nested_message.bb == 42) || true"; - runTest(Activation.of("x", wm)); - - // Error or false should be error. - source = "(x.single_nested_message.bb == 42) || false"; - runTest(Activation.of("x", wm)); - - // Error and true should be error. - source = "(x.single_nested_message.bb == 42) && true"; - runTest(Activation.of("x", wm)); - - // Error and false should be false. - source = "(x.single_nested_message.bb == 42) && false"; - runTest(Activation.of("x", wm)); + runTest(Activation.EMPTY); } @Test public void unknownResultSet() throws Exception { container = TestAllTypes.getDescriptor().getFile().getPackage(); declareVariable("x", CelTypes.createMessage(TestAllTypes.getDescriptor().getFullName())); - TestAllTypes val = + TestAllTypes message = TestAllTypes.newBuilder() .setSingleString("test") .setSingleTimestamp(Timestamp.newBuilder().setSeconds(15)) .build(); - PartialMessage message = - new PartialMessage( - val, - FieldMask.newBuilder() - .addPaths("single_int32") - .addPaths("single_int64") - .addPaths("map_int32_int64") - .build()); - // unknown && true ==> unknown - source = "x.single_int32 == 1 && x.single_string == \"test\""; - runTest(Activation.of("x", message)); + source = "x.single_int32 == 1 && true"; + runTest(Activation.EMPTY); // unknown && false ==> false - source = "x.single_int32 == 1 && x.single_string != \"test\""; - runTest(Activation.of("x", message)); + source = "x.single_int32 == 1 && false"; + runTest(Activation.EMPTY); // unknown && Unknown ==> UnknownSet source = "x.single_int32 == 1 && x.single_int64 == 1"; - runTest(Activation.of("x", message)); + runTest(Activation.EMPTY); // unknown && error ==> unknown source = "x.single_int32 == 1 && x.single_timestamp <= timestamp(\"bad timestamp string\")"; - runTest(Activation.of("x", message)); + runTest(Activation.EMPTY); // true && unknown ==> unknown - source = "x.single_string == \"test\" && x.single_int32 == 1"; - runTest(Activation.of("x", message)); + source = "true && x.single_int32 == 1"; + runTest(Activation.EMPTY); // false && unknown ==> false - source = "x.single_string != \"test\" && x.single_int32 == 1"; - runTest(Activation.of("x", message)); + source = "false && x.single_int32 == 1"; + runTest(Activation.EMPTY); // error && unknown ==> unknown source = "x.single_timestamp <= timestamp(\"bad timestamp string\") && x.single_int32 == 1"; - runTest(Activation.of("x", message)); + runTest(Activation.EMPTY); // error && error ==> error source = "x.single_timestamp <= timestamp(\"bad timestamp string\") " + "&& x.single_timestamp > timestamp(\"another bad timestamp string\")"; - runTest(Activation.of("x", message)); + runTest(Activation.EMPTY); // unknown || true ==> true source = "x.single_int32 == 1 || x.single_string == \"test\""; - runTest(Activation.of("x", message)); + runTest(Activation.EMPTY); // unknown || false ==> unknown source = "x.single_int32 == 1 || x.single_string != \"test\""; - runTest(Activation.of("x", message)); + runTest(Activation.EMPTY); // unknown || unknown ==> UnknownSet source = "x.single_int32 == 1 || x.single_int64 == 1"; - runTest(Activation.of("x", message)); + runTest(Activation.EMPTY); // unknown || error ==> unknown source = "x.single_int32 == 1 || x.single_timestamp <= timestamp(\"bad timestamp string\")"; - runTest(Activation.of("x", message)); + runTest(Activation.EMPTY); // true || unknown ==> true - source = "x.single_string == \"test\" || x.single_int32 == 1"; - runTest(Activation.of("x", message)); + source = "true || x.single_int32 == 1"; + runTest(Activation.EMPTY); // false || unknown ==> unknown - source = "x.single_string != \"test\" || x.single_int32 == 1"; - runTest(Activation.of("x", message)); + source = "false || x.single_int32 == 1"; + runTest(Activation.EMPTY); // error || unknown ==> unknown source = "x.single_timestamp <= timestamp(\"bad timestamp string\") || x.single_int32 == 1"; - runTest(Activation.of("x", message)); + runTest(Activation.EMPTY); // error || error ==> error source = "x.single_timestamp <= timestamp(\"bad timestamp string\") " + "|| x.single_timestamp > timestamp(\"another bad timestamp string\")"; - runTest(Activation.of("x", message)); + runTest(Activation.EMPTY); // dispatch test declareFunction( @@ -1203,15 +1123,15 @@ public void unknownResultSet() throws Exception { // dispatch: unknown.f(1) ==> unknown source = "x.single_int32.f(1)"; - runTest(Activation.of("x", message)); + runTest(Activation.EMPTY); // dispatch: 1.f(unknown) ==> unknown source = "1.f(x.single_int32)"; - runTest(Activation.of("x", message)); + runTest(Activation.EMPTY); // dispatch: unknown.f(unknown) ==> unknownSet source = "x.single_int64.f(x.single_int32)"; - runTest(Activation.of("x", message)); + runTest(Activation.EMPTY); // ident is null(x is unbound) ==> unknown source = "x"; @@ -1226,91 +1146,91 @@ public void unknownResultSet() throws Exception { // comprehension test // iteRange is unknown => unknown source = "x.map_int32_int64.map(x, x > 0, x + 1)"; - runTest(Activation.of("x", message)); + runTest(Activation.EMPTY); // exists, loop condition encounters unknown => skip unknown and check other element source = "[0, 2, 4].exists(z, z == 2 || z == x.single_int32)"; - runTest(Activation.of("x", message)); + runTest(Activation.EMPTY); // exists, loop condition encounters unknown => skip unknown and check other element, no dupe id // in result source = "[0, 2, 4].exists(z, z == x.single_int32)"; - runTest(Activation.of("x", message)); + runTest(Activation.EMPTY); // exists_one, loop condition encounters unknown => collect all unknowns source = "[0, 2, 4].exists_one(z, z == 0 || (z == 2 && z == x.single_int32) " + "|| (z == 4 && z == x.single_int64))"; - runTest(Activation.of("x", message)); + runTest(Activation.EMPTY); // all, loop condition encounters unknown => skip unknown and check other element source = "[0, 2].all(z, z == 2 || z == x.single_int32)"; - runTest(Activation.of("x", message)); + runTest(Activation.EMPTY); // filter, loop condition encounters unknown => skip unknown and check other element source = "[0, 2, 4].filter(z, z == 0 || (z == 2 && z == x.single_int32) " + "|| (z == 4 && z == x.single_int64))"; - runTest(Activation.of("x", message)); + runTest(Activation.EMPTY); // map, loop condition encounters unknown => skip unknown and check other element source = "[0, 2, 4].map(z, z == 0 || (z == 2 && z == x.single_int32) " + "|| (z == 4 && z == x.single_int64))"; - runTest(Activation.of("x", message)); + runTest(Activation.EMPTY); // conditional test // unknown ? 1 : 2 ==> unknown source = "x.single_int32 == 1 ? 1 : 2"; - runTest(Activation.of("x", message)); + runTest(Activation.EMPTY); // true ? unknown : 2 ==> unknown - source = "x.single_string == \"test\" ? x.single_int32 : 2"; - runTest(Activation.of("x", message)); + source = "true ? x.single_int32 : 2"; + runTest(Activation.EMPTY); // true ? 1 : unknown ==> 1 - source = "x.single_string == \"test\" ? 1 : x.single_int32"; - runTest(Activation.of("x", message)); + source = "true ? 1 : x.single_int32"; + runTest(Activation.EMPTY); // false ? unknown : 2 ==> 2 - source = "x.single_string != \"test\" ? x.single_int32 : 2"; - runTest(Activation.of("x", message)); + source = "false ? x.single_int32 : 2"; + runTest(Activation.EMPTY); // false ? 1 : unknown ==> unknown - source = "x.single_string != \"test\" ? 1 : x.single_int32"; - runTest(Activation.of("x", message)); + source = "false ? 1 : x.single_int32"; + runTest(Activation.EMPTY); // unknown condition ? unknown : unknown ==> unknown condition source = "x.single_int64 == 1 ? x.single_int32 : x.single_int32"; - runTest(Activation.of("x", message)); + runTest(Activation.EMPTY); // map with unknown key => unknown source = "{x.single_int32: 2, 3: 4}"; - runTest(Activation.of("x", message)); + runTest(Activation.EMPTY); // map with unknown value => unknown source = "{1: x.single_int32, 3: 4}"; - runTest(Activation.of("x", message)); + runTest(Activation.EMPTY); // map with unknown key and value => unknownSet source = "{1: x.single_int32, x.single_int64: 4}"; - runTest(Activation.of("x", message)); + runTest(Activation.EMPTY); // list with unknown => unknown source = "[1, x.single_int32, 3, 4]"; - runTest(Activation.of("x", message)); + runTest(Activation.EMPTY); // list with multiple unknowns => unknownSet source = "[1, x.single_int32, x.single_int64, 4]"; - runTest(Activation.of("x", message)); + runTest(Activation.EMPTY); // message with unknown => unknown source = "TestAllTypes{single_int32: x.single_int32}.single_int32 == 2"; - runTest(Activation.of("x", message)); + runTest(Activation.EMPTY); // message with multiple unknowns => unknownSet source = "TestAllTypes{single_int32: x.single_int32, single_int64: x.single_int64}"; - runTest(Activation.of("x", message)); + runTest(Activation.EMPTY); } @Test From 0e2fd64e430ffdc00b4fb873bca6228e936d3215 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Tue, 25 Jun 2024 13:04:20 -0700 Subject: [PATCH 132/486] Remove celVarToDecl method PiperOrigin-RevId: 646579113 --- common/src/main/java/dev/cel/common/CelVarDecl.java | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/common/src/main/java/dev/cel/common/CelVarDecl.java b/common/src/main/java/dev/cel/common/CelVarDecl.java index 9c3930c3a..0543ed225 100644 --- a/common/src/main/java/dev/cel/common/CelVarDecl.java +++ b/common/src/main/java/dev/cel/common/CelVarDecl.java @@ -14,13 +14,9 @@ package dev.cel.common; -import dev.cel.expr.Decl; -import dev.cel.expr.Decl.IdentDecl; import com.google.auto.value.AutoValue; -import com.google.common.annotations.VisibleForTesting; import com.google.errorprone.annotations.CheckReturnValue; import dev.cel.common.types.CelType; -import dev.cel.common.types.CelTypes; /** Abstract representation of a CEL variable declaration. */ @AutoValue @@ -37,13 +33,4 @@ public abstract class CelVarDecl { public static CelVarDecl newVarDeclaration(String name, CelType type) { return new AutoValue_CelVarDecl(name, type); } - - /** Converts a {@link CelVarDecl} to a protobuf equivalent form {@code Decl} */ - @VisibleForTesting - public static Decl celVarToDecl(CelVarDecl varDecl) { - return Decl.newBuilder() - .setName(varDecl.name()) - .setIdent(IdentDecl.newBuilder().setType(CelTypes.celTypeToType(varDecl.type()))) - .build(); - } } From db83a4704459edbbe6fc0139742f0f100c4a702c Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Fri, 28 Jun 2024 13:37:37 -0700 Subject: [PATCH 133/486] Adapt the function dispatch result to allow for automatic Any unpacking PiperOrigin-RevId: 647784646 --- .../dev/cel/runtime/DefaultInterpreter.java | 9 +-- .../src/test/resources/packUnpackAny.baseline | 59 +++++++++++++++++++ .../dev/cel/testing/BaseInterpreterTest.java | 5 ++ 3 files changed, 69 insertions(+), 4 deletions(-) diff --git a/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java b/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java index b35c4dea6..80622c62c 100644 --- a/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java +++ b/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java @@ -411,10 +411,11 @@ private IntermediateResult evalCall(ExecutionFrame frame, CelExpr expr, CelCall Object[] argArray = Arrays.stream(argResults).map(IntermediateResult::value).toArray(); - return IntermediateResult.create( - attr, + Object dispatchResult = dispatcher.dispatch( - metadata, expr.id(), callExpr.function(), reference.overloadIds(), argArray)); + metadata, expr.id(), callExpr.function(), reference.overloadIds(), argArray); + dispatchResult = typeProvider.adapt(dispatchResult); + return IntermediateResult.create(attr, dispatchResult); } private Optional maybeContainerIndexAttribute( @@ -717,7 +718,7 @@ private IntermediateResult evalList(ExecutionFrame frame, CelExpr unusedExpr, Ce Object value = evaluatedElement.value(); if (!optionalIndicesSet .isEmpty() // Performance optimization to prevent autoboxing when there's no - // optionals. + // optionals. && optionalIndicesSet.contains(i) && !isUnknownValue(value)) { Optional optionalVal = (Optional) value; diff --git a/runtime/src/test/resources/packUnpackAny.baseline b/runtime/src/test/resources/packUnpackAny.baseline index 44466f853..2d57e9131 100644 --- a/runtime/src/test/resources/packUnpackAny.baseline +++ b/runtime/src/test/resources/packUnpackAny.baseline @@ -8,6 +8,9 @@ declare d { declare message { value dev.cel.testing.testdata.proto3.TestAllTypes } +declare list { + value list(dyn) +} =====> bindings: {d=seconds: 100 } +> {any=type_url: "type.googleapis.com/google.protobuf.Duration" @@ -25,6 +28,9 @@ declare d { declare message { value dev.cel.testing.testdata.proto3.TestAllTypes } +declare list { + value list(dyn) +} =====> bindings: {message=single_any { type_url: "type.googleapis.com/google.protobuf.Duration" @@ -45,6 +51,9 @@ declare d { declare message { value dev.cel.testing.testdata.proto3.TestAllTypes } +declare list { + value list(dyn) +} =====> bindings: {message=single_any { type_url: "type.googleapis.com/google.protobuf.Duration" @@ -64,6 +73,9 @@ declare d { declare message { value dev.cel.testing.testdata.proto3.TestAllTypes } +declare list { + value list(dyn) +} =====> bindings: {any=single_int64: 1 } @@ -79,12 +91,38 @@ declare d { declare message { value dev.cel.testing.testdata.proto3.TestAllTypes } +declare list { + value list(dyn) +} =====> bindings: {any=type_url: "type.googleapis.com/google.protobuf.Int64Value" value: "\b\001" } result: true +Source: list[0] == message +declare any { + value any +} +declare d { + value google.protobuf.Duration +} +declare message { + value dev.cel.testing.testdata.proto3.TestAllTypes +} +declare list { + value list(dyn) +} +=====> +bindings: {list=[type_url: "type.googleapis.com/dev.cel.testing.testdata.proto3.TestAllTypes" +value: "\242\0062\n,type.googleapis.com/google.protobuf.Duration\022\002\bd" +], message=single_any { + type_url: "type.googleapis.com/google.protobuf.Duration" + value: "\bd" +} +} +result: true + Source: TestAllTypes{single_any: d} declare any { value any @@ -95,6 +133,9 @@ declare d { declare message { value dev.cel.testing.testdata.proto3.TestAllTypes } +declare list { + value list(dyn) +} =====> bindings: {d=seconds: 100 } @@ -114,6 +155,9 @@ declare d { declare message { value dev.cel.testing.testdata.proto3.TestAllTypes } +declare list { + value list(dyn) +} =====> bindings: {message=single_int64: -1 } @@ -133,6 +177,9 @@ declare d { declare message { value dev.cel.testing.testdata.proto3.TestAllTypes } +declare list { + value list(dyn) +} =====> bindings: {message=single_uint64: 1 } @@ -152,6 +199,9 @@ declare d { declare message { value dev.cel.testing.testdata.proto3.TestAllTypes } +declare list { + value list(dyn) +} =====> bindings: {} result: single_any { @@ -170,6 +220,9 @@ declare d { declare message { value dev.cel.testing.testdata.proto3.TestAllTypes } +declare list { + value list(dyn) +} =====> bindings: {} result: single_any { @@ -188,6 +241,9 @@ declare d { declare message { value dev.cel.testing.testdata.proto3.TestAllTypes } +declare list { + value list(dyn) +} =====> bindings: {} result: single_any { @@ -206,6 +262,9 @@ declare d { declare message { value dev.cel.testing.testdata.proto3.TestAllTypes } +declare list { + value list(dyn) +} =====> bindings: {message=single_bytes: "happy" } diff --git a/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java b/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java index bc9afa55e..795145508 100644 --- a/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java +++ b/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java @@ -569,6 +569,7 @@ public void packUnpackAny() throws Exception { declareVariable("any", CelTypes.ANY); declareVariable("d", CelTypes.DURATION); declareVariable("message", CelTypes.createMessage(TestAllTypes.getDescriptor().getFullName())); + declareVariable("list", CelTypes.createList(CelTypes.DYN)); Duration duration = Durations.fromSeconds(100); Any any = Any.pack(duration); TestAllTypes message = TestAllTypes.newBuilder().setSingleAny(any).build(); @@ -584,6 +585,10 @@ public void packUnpackAny() throws Exception { runTest(Activation.of("any", TestAllTypes.newBuilder().setSingleInt64(1).build())); source = "any == 1"; runTest(Activation.of("any", Any.pack(Int64Value.of(1)))); + source = "list[0] == message"; + runTest( + Activation.copyOf( + ImmutableMap.of("list", ImmutableList.of(Any.pack(message)), "message", message))); // pack any source = "TestAllTypes{single_any: d}"; From cd4596a50c388ad62edf3a2f54c828e3c0769abf Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Mon, 1 Jul 2024 13:48:25 -0700 Subject: [PATCH 134/486] Compute line offsets once when constructing CelCodePointArray PiperOrigin-RevId: 648474659 --- .../main/java/dev/cel/common/CelSource.java | 22 +++--- .../common/internal/BasicCodePointArray.java | 16 +++- .../common/internal/CelCodePointArray.java | 46 ++++++++++- .../common/internal/EmptyCodePointArray.java | 6 ++ .../common/internal/Latin1CodePointArray.java | 17 +++- .../internal/SupplementalCodePointArray.java | 17 +++- .../cel/common/CelAbstractSyntaxTreeTest.java | 6 +- .../java/dev/cel/common/CelSourceTest.java | 11 +++ .../java/dev/cel/common/internal/BUILD.bazel | 1 + .../internal/CelCodePointArrayTest.java | 77 +++++++++++++++++++ 10 files changed, 186 insertions(+), 33 deletions(-) create mode 100644 common/src/test/java/dev/cel/common/internal/CelCodePointArrayTest.java diff --git a/common/src/main/java/dev/cel/common/CelSource.java b/common/src/main/java/dev/cel/common/CelSource.java index aea607ccd..de779b05b 100644 --- a/common/src/main/java/dev/cel/common/CelSource.java +++ b/common/src/main/java/dev/cel/common/CelSource.java @@ -16,9 +16,9 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; import com.google.auto.value.AutoValue; -import com.google.common.base.Splitter; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; @@ -37,8 +37,6 @@ /** Represents the source content of an expression and related metadata. */ @Immutable public final class CelSource { - private static final Splitter LINE_SPLITTER = Splitter.on('\n'); - private final CelCodePointArray codePoints; private final String description; private final ImmutableList lineOffsets; @@ -194,13 +192,8 @@ public static Builder newBuilder() { } public static Builder newBuilder(String text) { - List lineOffsets = new ArrayList<>(); - int lineOffset = 0; - for (String line : LINE_SPLITTER.split(text)) { - lineOffset += (int) (line.codePoints().count() + 1); - lineOffsets.add(lineOffset); - } - return new Builder(CelCodePointArray.fromString(text), lineOffsets); + CelCodePointArray codePointArray = CelCodePointArray.fromString(text); + return new Builder(codePointArray, codePointArray.lineOffsets()); } /** Builder for {@link CelSource}. */ @@ -212,6 +205,7 @@ public static final class Builder { private final Map macroCalls; private final ImmutableSet.Builder extensions; + private final boolean lineOffsetsAlreadyComputed; private String description; private Builder() { @@ -225,6 +219,7 @@ private Builder(CelCodePointArray codePoints, List lineOffsets) { this.macroCalls = new HashMap<>(); this.extensions = ImmutableSet.builder(); this.description = ""; + this.lineOffsetsAlreadyComputed = !lineOffsets.isEmpty(); } @CanIgnoreReturnValue @@ -236,6 +231,9 @@ public Builder setDescription(String description) { @CanIgnoreReturnValue public Builder addLineOffsets(int lineOffset) { checkArgument(lineOffset >= 0); + checkState( + !lineOffsetsAlreadyComputed, + "Line offsets were already been computed through the provided code points."); lineOffsets.add(lineOffset); return this; } @@ -362,8 +360,8 @@ private LineAndOffset(int line, int offset) { this.offset = offset; } - int line; - int offset; + private final int line; + private final int offset; } /** diff --git a/common/src/main/java/dev/cel/common/internal/BasicCodePointArray.java b/common/src/main/java/dev/cel/common/internal/BasicCodePointArray.java index f4f9ef6c3..251f09d61 100644 --- a/common/src/main/java/dev/cel/common/internal/BasicCodePointArray.java +++ b/common/src/main/java/dev/cel/common/internal/BasicCodePointArray.java @@ -19,6 +19,7 @@ import static com.google.common.base.Preconditions.checkPositionIndexes; import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.ImmutableList; import com.google.errorprone.annotations.Immutable; import dev.cel.common.annotations.Internal; @@ -38,21 +39,23 @@ public final class BasicCodePointArray extends CelCodePointArray { private final int offset; private final int size; + private final ImmutableList lineOffsets; - BasicCodePointArray(char[] codePoints, int size) { - this(codePoints, 0, size); + BasicCodePointArray(char[] codePoints, int size, ImmutableList lineOffsets) { + this(codePoints, 0, lineOffsets, size); } - BasicCodePointArray(char[] codePoints, int offset, int size) { + BasicCodePointArray(char[] codePoints, int offset, ImmutableList lineOffsets, int size) { this.codePoints = checkNotNull(codePoints); this.offset = offset; this.size = size; + this.lineOffsets = lineOffsets; } @Override public BasicCodePointArray slice(int i, int j) { checkPositionIndexes(i, j, size()); - return new BasicCodePointArray(codePoints, offset + i, j - i); + return new BasicCodePointArray(codePoints, offset + i, lineOffsets, j - i); } @Override @@ -66,6 +69,11 @@ public int size() { return size; } + @Override + public ImmutableList lineOffsets() { + return lineOffsets; + } + @Override public String toString() { return new String(codePoints, offset, size); diff --git a/common/src/main/java/dev/cel/common/internal/CelCodePointArray.java b/common/src/main/java/dev/cel/common/internal/CelCodePointArray.java index 178b2ac55..94d94b5dc 100644 --- a/common/src/main/java/dev/cel/common/internal/CelCodePointArray.java +++ b/common/src/main/java/dev/cel/common/internal/CelCodePointArray.java @@ -16,6 +16,7 @@ import static com.google.common.base.Strings.isNullOrEmpty; +import com.google.common.collect.ImmutableList; import com.google.errorprone.annotations.Immutable; import dev.cel.common.annotations.Internal; import java.util.PrimitiveIterator; @@ -41,6 +42,9 @@ public abstract class CelCodePointArray { /** Returns the number of code points. */ public abstract int size(); + /** Returns the line offsets. */ + public abstract ImmutableList lineOffsets(); + public final int length() { return size(); } @@ -60,8 +64,11 @@ public static CelCodePointArray fromString(String text) { PrimitiveIterator.OfInt codePoints = text.codePoints().iterator(); byte[] byteArray = new byte[text.length()]; int byteIndex = 0; + + LineOffsetContext lineOffsetContext = new LineOffsetContext(); while (codePoints.hasNext()) { int codePoint = codePoints.nextInt(); + lineOffsetContext.process(codePoint); if (codePoint <= 0xff) { byteArray[byteIndex++] = (byte) codePoint; continue; @@ -76,6 +83,7 @@ public static CelCodePointArray fromString(String text) { charArray[charIndex++] = (char) codePoint; while (codePoints.hasNext()) { codePoint = codePoints.nextInt(); + lineOffsetContext.process(codePoint); if (codePoint <= 0xffff) { charArray[charIndex++] = (char) codePoint; continue; @@ -89,11 +97,15 @@ public static CelCodePointArray fromString(String text) { intArray[intIndex++] = codePoint; while (codePoints.hasNext()) { codePoint = codePoints.nextInt(); + lineOffsetContext.process(codePoint); intArray[intIndex++] = codePoint; } - return new SupplementalCodePointArray(intArray, intIndex); + + return new SupplementalCodePointArray( + intArray, intIndex, lineOffsetContext.buildLineOffsets()); } - return new BasicCodePointArray(charArray, charIndex); + + return new BasicCodePointArray(charArray, charIndex, lineOffsetContext.buildLineOffsets()); } int[] intArray = new int[text.length()]; int intIndex = 0; @@ -104,10 +116,36 @@ public static CelCodePointArray fromString(String text) { intArray[intIndex++] = codePoint; while (codePoints.hasNext()) { codePoint = codePoints.nextInt(); + lineOffsetContext.process(codePoint); intArray[intIndex++] = codePoint; } - return new SupplementalCodePointArray(intArray, intIndex); + + return new SupplementalCodePointArray( + intArray, intIndex, lineOffsetContext.buildLineOffsets()); + } + + return new Latin1CodePointArray(byteArray, byteIndex, lineOffsetContext.buildLineOffsets()); + } + + private static class LineOffsetContext { + private static final int NEWLINE_CODE_POINT = 10; + + private final ImmutableList.Builder lineOffsetBuilder; + private int lineOffsetCodePoints; + + private void process(int codePoint) { + lineOffsetCodePoints++; + if (codePoint == NEWLINE_CODE_POINT) { + lineOffsetBuilder.add(lineOffsetCodePoints); + } + } + + private ImmutableList buildLineOffsets() { + return lineOffsetBuilder.add(lineOffsetCodePoints + 1).build(); + } + + private LineOffsetContext() { + this.lineOffsetBuilder = ImmutableList.builder(); } - return new Latin1CodePointArray(byteArray, byteIndex); } } diff --git a/common/src/main/java/dev/cel/common/internal/EmptyCodePointArray.java b/common/src/main/java/dev/cel/common/internal/EmptyCodePointArray.java index 95352d83b..8bca7bf31 100644 --- a/common/src/main/java/dev/cel/common/internal/EmptyCodePointArray.java +++ b/common/src/main/java/dev/cel/common/internal/EmptyCodePointArray.java @@ -14,6 +14,7 @@ package dev.cel.common.internal; +import com.google.common.collect.ImmutableList; import com.google.errorprone.annotations.DoNotCall; import com.google.errorprone.annotations.Immutable; import dev.cel.common.annotations.Internal; @@ -55,6 +56,11 @@ public int size() { return 0; } + @Override + public ImmutableList lineOffsets() { + return ImmutableList.of(1); + } + @Override public String toString() { return ""; diff --git a/common/src/main/java/dev/cel/common/internal/Latin1CodePointArray.java b/common/src/main/java/dev/cel/common/internal/Latin1CodePointArray.java index 854df7fa7..a06448aba 100644 --- a/common/src/main/java/dev/cel/common/internal/Latin1CodePointArray.java +++ b/common/src/main/java/dev/cel/common/internal/Latin1CodePointArray.java @@ -20,6 +20,7 @@ import static java.nio.charset.StandardCharsets.ISO_8859_1; import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.ImmutableList; import com.google.errorprone.annotations.Immutable; import dev.cel.common.annotations.Internal; @@ -38,21 +39,24 @@ public final class Latin1CodePointArray extends CelCodePointArray { private final int offset; private final int size; + private final ImmutableList lineOffsets; - Latin1CodePointArray(byte[] codePoints, int size) { - this(codePoints, 0, size); + Latin1CodePointArray(byte[] codePoints, int size, ImmutableList lineOffsets) { + this(codePoints, 0, lineOffsets, size); } - Latin1CodePointArray(byte[] codePoints, int offset, int size) { + Latin1CodePointArray( + byte[] codePoints, int offset, ImmutableList lineOffsets, int size) { this.codePoints = checkNotNull(codePoints); this.offset = offset; this.size = size; + this.lineOffsets = lineOffsets; } @Override public Latin1CodePointArray slice(int i, int j) { checkPositionIndexes(i, j, size()); - return new Latin1CodePointArray(codePoints, offset + i, j - i); + return new Latin1CodePointArray(codePoints, offset + i, lineOffsets, j - i); } @Override @@ -66,6 +70,11 @@ public int size() { return size; } + @Override + public ImmutableList lineOffsets() { + return lineOffsets; + } + @Override public String toString() { return new String(codePoints, offset, size, ISO_8859_1); diff --git a/common/src/main/java/dev/cel/common/internal/SupplementalCodePointArray.java b/common/src/main/java/dev/cel/common/internal/SupplementalCodePointArray.java index 8090a591d..30f2fce27 100644 --- a/common/src/main/java/dev/cel/common/internal/SupplementalCodePointArray.java +++ b/common/src/main/java/dev/cel/common/internal/SupplementalCodePointArray.java @@ -19,6 +19,7 @@ import static com.google.common.base.Preconditions.checkPositionIndexes; import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.ImmutableList; import com.google.errorprone.annotations.Immutable; import dev.cel.common.annotations.Internal; @@ -38,21 +39,24 @@ public final class SupplementalCodePointArray extends CelCodePointArray { private final int offset; private final int size; + private final ImmutableList lineOffsets; - SupplementalCodePointArray(int[] codePoints, int size) { - this(codePoints, 0, size); + SupplementalCodePointArray(int[] codePoints, int size, ImmutableList lineOffsets) { + this(codePoints, 0, lineOffsets, size); } - SupplementalCodePointArray(int[] codePoints, int offset, int size) { + SupplementalCodePointArray( + int[] codePoints, int offset, ImmutableList lineOffsets, int size) { this.codePoints = checkNotNull(codePoints); this.offset = offset; this.size = size; + this.lineOffsets = lineOffsets; } @Override public SupplementalCodePointArray slice(int i, int j) { checkPositionIndexes(i, j, size()); - return new SupplementalCodePointArray(codePoints, offset + i, j - i); + return new SupplementalCodePointArray(codePoints, offset + i, lineOffsets, j - i); } @Override @@ -66,6 +70,11 @@ public int size() { return size; } + @Override + public ImmutableList lineOffsets() { + return lineOffsets; + } + @Override public String toString() { return new String(codePoints, offset, size); diff --git a/common/src/test/java/dev/cel/common/CelAbstractSyntaxTreeTest.java b/common/src/test/java/dev/cel/common/CelAbstractSyntaxTreeTest.java index 78c16c165..48e28894a 100644 --- a/common/src/test/java/dev/cel/common/CelAbstractSyntaxTreeTest.java +++ b/common/src/test/java/dev/cel/common/CelAbstractSyntaxTreeTest.java @@ -150,11 +150,7 @@ public void getSource_hasDescriptionEqualToSourceLocation() { public void parsedExpression_createAst() { CelExpr celExpr = CelExpr.newBuilder().setId(1).setConstant(CelConstant.ofValue(2)).build(); CelSource celSource = - CelSource.newBuilder("expression") - .setDescription("desc") - .addPositions(1, 5) - .addLineOffsets(10) - .build(); + CelSource.newBuilder("expression").setDescription("desc").addPositions(1, 5).build(); CelAbstractSyntaxTree ast = CelAbstractSyntaxTree.newParsedAst(celExpr, celSource); diff --git a/common/src/test/java/dev/cel/common/CelSourceTest.java b/common/src/test/java/dev/cel/common/CelSourceTest.java index a97eeb853..d8b3701e3 100644 --- a/common/src/test/java/dev/cel/common/CelSourceTest.java +++ b/common/src/test/java/dev/cel/common/CelSourceTest.java @@ -181,4 +181,15 @@ public void source_withExtension() { .containsExactly(Component.COMPONENT_PARSER, Component.COMPONENT_TYPE_CHECKER); assertThat(celSource.getExtensions()).hasSize(1); } + + @Test + public void source_lineOffsetsAlreadyComputed_throws() { + CelSource.Builder sourceBuilder = CelSource.newBuilder("text"); + + IllegalStateException e = + assertThrows(IllegalStateException.class, () -> sourceBuilder.addLineOffsets(1)); + assertThat(e) + .hasMessageThat() + .contains("Line offsets were already been computed through the provided code points."); + } } diff --git a/common/src/test/java/dev/cel/common/internal/BUILD.bazel b/common/src/test/java/dev/cel/common/internal/BUILD.bazel index 41d98f6c8..af0a673aa 100644 --- a/common/src/test/java/dev/cel/common/internal/BUILD.bazel +++ b/common/src/test/java/dev/cel/common/internal/BUILD.bazel @@ -10,6 +10,7 @@ java_library( srcs = glob(["*.java"]), resources = ["//common/src/test/resources"], deps = [ + "//:auto_value", "//:java_truth", "//common", "//common:options", diff --git a/common/src/test/java/dev/cel/common/internal/CelCodePointArrayTest.java b/common/src/test/java/dev/cel/common/internal/CelCodePointArrayTest.java new file mode 100644 index 000000000..7cb02c5a8 --- /dev/null +++ b/common/src/test/java/dev/cel/common/internal/CelCodePointArrayTest.java @@ -0,0 +1,77 @@ +// Copyright 2024 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.common.internal; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.auto.value.AutoValue; +import com.google.common.collect.ImmutableList; +import com.google.testing.junit.testparameterinjector.TestParameter; +import com.google.testing.junit.testparameterinjector.TestParameterInjector; +import com.google.testing.junit.testparameterinjector.TestParameterValuesProvider; +import java.util.Arrays; +import java.util.List; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(TestParameterInjector.class) +public final class CelCodePointArrayTest { + + @Test + public void computeLineOffset( + @TestParameter(valuesProvider = LineOffsetDataProvider.class) LineOffsetTestCase testCase) { + CelCodePointArray codePointArray = CelCodePointArray.fromString(testCase.text()); + + assertThat(codePointArray.lineOffsets()) + .containsExactlyElementsIn(testCase.offsets()) + .inOrder(); + } + + @AutoValue + abstract static class LineOffsetTestCase { + abstract String text(); + + abstract ImmutableList offsets(); + + static LineOffsetTestCase of(String text, Integer... offsets) { + return of(text, Arrays.asList(offsets)); + } + + static LineOffsetTestCase of(String text, List offsets) { + return new AutoValue_CelCodePointArrayTest_LineOffsetTestCase( + text, ImmutableList.copyOf(offsets)); + } + } + + private static final class LineOffsetDataProvider extends TestParameterValuesProvider { + + @Override + protected List provideValues(Context context) { + return Arrays.asList( + // Empty + LineOffsetTestCase.of("", 1), + // ISO-8859-1 + LineOffsetTestCase.of("hello world", 12), + LineOffsetTestCase.of("hello\nworld", 6, 12), + LineOffsetTestCase.of("hello\nworld\n\nfoo\n", 6, 12, 13, 17, 18), + // BMP + LineOffsetTestCase.of("abc 가나다", 8), + LineOffsetTestCase.of("abc\n가나다\n我b很好\n", 4, 8, 13, 14), + // SMP + LineOffsetTestCase.of(" text 가나다 😦😁😑 ", 15), + LineOffsetTestCase.of(" text\n가나다 \n😦😁😑\n\n", 6, 11, 15, 16, 17)); + } + } +} From 039df1f037f1188d17d39e276b444c9646b964bd Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Mon, 1 Jul 2024 14:15:19 -0700 Subject: [PATCH 135/486] Add an interface for encapsulating Source properties PiperOrigin-RevId: 648483048 --- common/BUILD.bazel | 6 ++ .../src/main/java/dev/cel/common/BUILD.bazel | 15 +++++ .../main/java/dev/cel/common/CelIssue.java | 2 +- .../main/java/dev/cel/common/CelSource.java | 36 +++-------- .../java/dev/cel/common/CelSourceHelper.java | 61 +++++++++++++++++++ .../src/main/java/dev/cel/common/Source.java | 46 ++++++++++++++ 6 files changed, 136 insertions(+), 30 deletions(-) create mode 100644 common/src/main/java/dev/cel/common/CelSourceHelper.java create mode 100644 common/src/main/java/dev/cel/common/Source.java diff --git a/common/BUILD.bazel b/common/BUILD.bazel index 649c49186..e3d61aad9 100644 --- a/common/BUILD.bazel +++ b/common/BUILD.bazel @@ -59,3 +59,9 @@ java_library( name = "proto_json_adapter", exports = ["//common/src/main/java/dev/cel/common:proto_json_adapter"], ) + +java_library( + name = "source", + visibility = ["//visibility:public"], + exports = ["//common/src/main/java/dev/cel/common:source"], +) diff --git a/common/src/main/java/dev/cel/common/BUILD.bazel b/common/src/main/java/dev/cel/common/BUILD.bazel index 633279a0b..8036dafba 100644 --- a/common/src/main/java/dev/cel/common/BUILD.bazel +++ b/common/src/main/java/dev/cel/common/BUILD.bazel @@ -39,6 +39,7 @@ java_library( ], deps = [ ":error_codes", + ":source", "//:auto_value", "//common/annotations", "//common/ast", @@ -62,6 +63,7 @@ java_library( ], deps = [ ":common", + ":source", "//:auto_value", "//common/annotations", "//common/internal:safe_string_formatter", @@ -175,3 +177,16 @@ java_library( "@maven//:com_google_protobuf_protobuf_java_util", ], ) + +java_library( + name = "source", + srcs = [ + "CelSourceHelper.java", + "Source.java", + ], + deps = [ + "//common/annotations", + "//common/internal", + "@maven//:com_google_guava_guava", + ], +) diff --git a/common/src/main/java/dev/cel/common/CelIssue.java b/common/src/main/java/dev/cel/common/CelIssue.java index 7f7417a53..1e3cdb58e 100644 --- a/common/src/main/java/dev/cel/common/CelIssue.java +++ b/common/src/main/java/dev/cel/common/CelIssue.java @@ -74,7 +74,7 @@ public static CelIssue formatError(int line, int column, String message) { private static final char WIDE_HAT = '\uff3e'; /** Returns a string representing this error that is suitable for displaying to humans. */ - public String toDisplayString(CelSource source) { + public String toDisplayString(Source source) { // Based onhttps://github.com/google/cel-go/blob/v0.5.1/common/error.go#L42. String result = SafeStringFormatter.format( diff --git a/common/src/main/java/dev/cel/common/CelSource.java b/common/src/main/java/dev/cel/common/CelSource.java index de779b05b..b8ffe2598 100644 --- a/common/src/main/java/dev/cel/common/CelSource.java +++ b/common/src/main/java/dev/cel/common/CelSource.java @@ -36,7 +36,8 @@ /** Represents the source content of an expression and related metadata. */ @Immutable -public final class CelSource { +public final class CelSource implements Source { + private final CelCodePointArray codePoints; private final String description; private final ImmutableList lineOffsets; @@ -53,10 +54,12 @@ private CelSource(Builder builder) { this.extensions = checkNotNull(builder.extensions.build()); } + @Override public CelCodePointArray getContent() { return codePoints; } + @Override public String getDescription() { return description; } @@ -107,24 +110,9 @@ public Optional getOffsetLocation(int offset) { return getOffsetLocationImpl(lineOffsets, offset); } - /** - * Get the text from the source expression that corresponds to {@code line}. - * - * @param line the line number starting from 1. - */ + @Override public Optional getSnippet(int line) { - checkArgument(line > 0); - int start = findLineOffset(lineOffsets, line); - if (start == -1) { - return Optional.empty(); - } - int end = findLineOffset(lineOffsets, line + 1); - if (end == -1) { - end = codePoints.size(); - } else { - end--; - } - return Optional.of(end != start ? codePoints.slice(start, end).toString() : ""); + return CelSourceHelper.getSnippet(codePoints, line); } /** @@ -138,7 +126,7 @@ private static Optional getLocationOffsetImpl( List lineOffsets, int line, int column) { checkArgument(line > 0); checkArgument(column >= 0); - int offset = findLineOffset(lineOffsets, line); + int offset = CelSourceHelper.findLineOffset(lineOffsets, line); if (offset == -1) { return Optional.empty(); } @@ -155,16 +143,6 @@ public static Optional getOffsetLocationImpl( return Optional.of(CelSourceLocation.of(lineAndOffset.line, offset - lineAndOffset.offset)); } - private static int findLineOffset(List lineOffsets, int line) { - if (line == 1) { - return 0; - } - if (line > 1 && line <= lineOffsets.size()) { - return lineOffsets.get(line - 2); - } - return -1; - } - private static LineAndOffset findLine(List lineOffsets, int offset) { int line = 1; for (int index = 0; index < lineOffsets.size(); index++) { diff --git a/common/src/main/java/dev/cel/common/CelSourceHelper.java b/common/src/main/java/dev/cel/common/CelSourceHelper.java new file mode 100644 index 000000000..4fde5db7b --- /dev/null +++ b/common/src/main/java/dev/cel/common/CelSourceHelper.java @@ -0,0 +1,61 @@ +// Copyright 2024 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.common; + +import static com.google.common.base.Preconditions.checkArgument; + +import com.google.common.collect.ImmutableList; +import dev.cel.common.annotations.Internal; +import dev.cel.common.internal.CelCodePointArray; +import java.util.List; +import java.util.Optional; + +/** + * Helper methods for common source handling in CEL. + * + *

CEL Library Internals. Do Not Use. + */ +@Internal +public final class CelSourceHelper { + + /** Extract the snippet text that corresponds to {@code line}. */ + public static Optional getSnippet(CelCodePointArray content, int line) { + checkArgument(line > 0); + ImmutableList lineOffsets = content.lineOffsets(); + int start = findLineOffset(lineOffsets, line); + if (start == -1) { + return Optional.empty(); + } + int end = findLineOffset(lineOffsets, line + 1); + if (end == -1) { + end = content.size(); + } else { + end--; + } + return Optional.of(end != start ? content.slice(start, end).toString() : ""); + } + + static int findLineOffset(List lineOffsets, int line) { + if (line == 1) { + return 0; + } + if (line > 1 && line <= lineOffsets.size()) { + return lineOffsets.get(line - 2); + } + return -1; + } + + private CelSourceHelper() {} +} diff --git a/common/src/main/java/dev/cel/common/Source.java b/common/src/main/java/dev/cel/common/Source.java new file mode 100644 index 000000000..33a9927a6 --- /dev/null +++ b/common/src/main/java/dev/cel/common/Source.java @@ -0,0 +1,46 @@ +// Copyright 2024 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.common; + +import dev.cel.common.annotations.Internal; +import dev.cel.common.internal.CelCodePointArray; +import java.util.Optional; + +/** + * Common interface definition for source properties. + * + *

CEL Library Internals. Do Not Use. Consumers should instead use the canonical implementations + * such as CelSource. + */ +@Internal +public interface Source { + + /** Gets the original textual content of this source, represented in an array of code points. */ + CelCodePointArray getContent(); + + /** + * Gets the description of this source that may optionally be set (example: location of the file + * containing the source). + */ + String getDescription(); + + /** + * Get the text from the source text that corresponds to {@code line}. Snippets are split based on + * the newline ('\n'). + * + * @param line the line number starting from 1. + */ + Optional getSnippet(int line); +} From acc2ff3c602921b09768bbb27b654f32e0ee1e38 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Mon, 1 Jul 2024 15:18:57 -0700 Subject: [PATCH 136/486] Add PolicySource PiperOrigin-RevId: 648501376 --- policy/BUILD.bazel | 9 +++ .../src/main/java/dev/cel/policy/BUILD.bazel | 20 +++++++ .../java/dev/cel/policy/CelPolicySource.java | 58 +++++++++++++++++++ .../src/test/java/dev/cel/policy/BUILD.bazel | 24 ++++++++ .../dev/cel/policy/CelPolicySourceTest.java | 48 +++++++++++++++ 5 files changed, 159 insertions(+) create mode 100644 policy/BUILD.bazel create mode 100644 policy/src/main/java/dev/cel/policy/BUILD.bazel create mode 100644 policy/src/main/java/dev/cel/policy/CelPolicySource.java create mode 100644 policy/src/test/java/dev/cel/policy/BUILD.bazel create mode 100644 policy/src/test/java/dev/cel/policy/CelPolicySourceTest.java diff --git a/policy/BUILD.bazel b/policy/BUILD.bazel new file mode 100644 index 000000000..5dfc04ed8 --- /dev/null +++ b/policy/BUILD.bazel @@ -0,0 +1,9 @@ +package( + default_applicable_licenses = ["//:license"], + default_visibility = ["//visibility:public"], +) + +java_library( + name = "policy_source", + exports = ["//policy/src/main/java/dev/cel/policy:policy_source"], +) diff --git a/policy/src/main/java/dev/cel/policy/BUILD.bazel b/policy/src/main/java/dev/cel/policy/BUILD.bazel new file mode 100644 index 000000000..c9c896255 --- /dev/null +++ b/policy/src/main/java/dev/cel/policy/BUILD.bazel @@ -0,0 +1,20 @@ +package( + default_applicable_licenses = ["//:license"], + default_visibility = [ + "//policy:__pkg__", + ], +) + +java_library( + name = "policy_source", + srcs = [ + "CelPolicySource.java", + ], + deps = [ + "//:auto_value", + "//common:source", + "//common/internal", + "@maven//:com_google_errorprone_error_prone_annotations", + "@maven//:com_google_guava_guava", + ], +) diff --git a/policy/src/main/java/dev/cel/policy/CelPolicySource.java b/policy/src/main/java/dev/cel/policy/CelPolicySource.java new file mode 100644 index 000000000..b4c110d80 --- /dev/null +++ b/policy/src/main/java/dev/cel/policy/CelPolicySource.java @@ -0,0 +1,58 @@ +// Copyright 2024 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.policy; + +import com.google.auto.value.AutoValue; +import com.google.errorprone.annotations.CheckReturnValue; +import dev.cel.common.CelSourceHelper; +import dev.cel.common.Source; +import dev.cel.common.internal.CelCodePointArray; +import java.util.Optional; + +/** CelPolicySource represents the source content of a policy and its related metadata. */ +@AutoValue +public abstract class CelPolicySource implements Source { + + @Override + public abstract CelCodePointArray getContent(); + + @Override + public abstract String getDescription(); + + @Override + public Optional getSnippet(int line) { + return CelSourceHelper.getSnippet(getContent(), line); + } + + /** Builder for {@link CelPolicySource}. */ + @AutoValue.Builder + public abstract static class Builder { + + public abstract Builder setContent(CelCodePointArray content); + + public abstract Builder setDescription(String description); + + @CheckReturnValue + public abstract CelPolicySource build(); + } + + public abstract Builder toBuilder(); + + public static Builder newBuilder(String text) { + return new AutoValue_CelPolicySource.Builder() + .setContent(CelCodePointArray.fromString(text)) + .setDescription(""); + } +} diff --git a/policy/src/test/java/dev/cel/policy/BUILD.bazel b/policy/src/test/java/dev/cel/policy/BUILD.bazel new file mode 100644 index 000000000..26c7996bf --- /dev/null +++ b/policy/src/test/java/dev/cel/policy/BUILD.bazel @@ -0,0 +1,24 @@ +load("//:testing.bzl", "junit4_test_suites") + +package(default_applicable_licenses = ["//:license"]) + +java_library( + name = "tests", + testonly = True, + srcs = glob(["*.java"]), + deps = [ + "//:java_truth", + "//policy:policy_source", + "@maven//:com_google_testparameterinjector_test_parameter_injector", + "@maven//:junit_junit", + ], +) + +junit4_test_suites( + name = "test_suites", + sizes = [ + "small", + ], + src_dir = "src/test/java", + deps = [":tests"], +) diff --git a/policy/src/test/java/dev/cel/policy/CelPolicySourceTest.java b/policy/src/test/java/dev/cel/policy/CelPolicySourceTest.java new file mode 100644 index 000000000..9dc309b3f --- /dev/null +++ b/policy/src/test/java/dev/cel/policy/CelPolicySourceTest.java @@ -0,0 +1,48 @@ +// Copyright 2024 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.policy; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.testing.junit.testparameterinjector.TestParameterInjector; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(TestParameterInjector.class) +public final class CelPolicySourceTest { + + @Test + public void constructPolicySource_success() { + CelPolicySource policySource = CelPolicySource.newBuilder("hello world").build(); + + assertThat(policySource.getContent().toString()).isEqualTo("hello world"); + assertThat(policySource.getDescription()).isEqualTo(""); + } + + @Test + public void getSnippet_success() { + CelPolicySource policySource = CelPolicySource.newBuilder("hello\nworld").build(); + + assertThat(policySource.getSnippet(1)).hasValue("hello"); + assertThat(policySource.getSnippet(2)).hasValue("world"); + } + + @Test + public void getSnippet_returnsEmpty() { + CelPolicySource policySource = CelPolicySource.newBuilder("hello\nworld").build(); + + assertThat(policySource.getSnippet(3)).isEmpty(); + } +} From 26f25bb78cc0126b37f16aa75d6b351e62cc0518 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Mon, 1 Jul 2024 21:51:13 -0700 Subject: [PATCH 137/486] Flag guard the function dispatch result adaptation change PiperOrigin-RevId: 648585602 --- .../src/main/java/dev/cel/common/CelOptions.java | 15 ++++++++++++++- .../java/dev/cel/runtime/DefaultInterpreter.java | 4 +++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/common/src/main/java/dev/cel/common/CelOptions.java b/common/src/main/java/dev/cel/common/CelOptions.java index f421bee68..fb5ec6ad7 100644 --- a/common/src/main/java/dev/cel/common/CelOptions.java +++ b/common/src/main/java/dev/cel/common/CelOptions.java @@ -93,6 +93,8 @@ public abstract class CelOptions { public abstract int comprehensionMaxIterations(); + public abstract boolean unwrapWellKnownTypesOnFunctionDispatch(); + public abstract Builder toBuilder(); public ImmutableSet toExprFeatures() { @@ -182,7 +184,8 @@ public static Builder newBuilder() { .resolveTypeDependencies(true) .enableUnknownTracking(false) .enableCelValue(false) - .comprehensionMaxIterations(-1); + .comprehensionMaxIterations(-1) + .unwrapWellKnownTypesOnFunctionDispatch(true); } /** @@ -466,6 +469,16 @@ public abstract static class Builder { */ public abstract Builder comprehensionMaxIterations(int value); + /** + * If disabled, CEL runtime will no longer adapt the function dispatch results for protobuf's + * well known types to other types. This option is enabled by default. + * + * @deprecated This will be removed in the future. Please update your codebase to be conformant + * with CEL specification. + */ + @Deprecated + public abstract Builder unwrapWellKnownTypesOnFunctionDispatch(boolean value); + public abstract CelOptions build(); } } diff --git a/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java b/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java index 80622c62c..babec5dda 100644 --- a/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java +++ b/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java @@ -414,7 +414,9 @@ private IntermediateResult evalCall(ExecutionFrame frame, CelExpr expr, CelCall Object dispatchResult = dispatcher.dispatch( metadata, expr.id(), callExpr.function(), reference.overloadIds(), argArray); - dispatchResult = typeProvider.adapt(dispatchResult); + if (celOptions.unwrapWellKnownTypesOnFunctionDispatch()) { + dispatchResult = typeProvider.adapt(dispatchResult); + } return IntermediateResult.create(attr, dispatchResult); } From 2478747d98da268e5e794828232681d6c810a992 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Tue, 2 Jul 2024 10:20:52 -0700 Subject: [PATCH 138/486] Implement YAML parser for policy configs PiperOrigin-RevId: 648760977 --- WORKSPACE | 1 + policy/BUILD.bazel | 27 +- .../src/main/java/dev/cel/policy/BUILD.bazel | 102 +++- .../java/dev/cel/policy/CelPolicyConfig.java | 364 ++++++++++++++ .../dev/cel/policy/CelPolicyConfigParser.java | 31 ++ .../java/dev/cel/policy/CelPolicySource.java | 6 +- .../policy/CelPolicyValidationException.java | 30 ++ .../cel/policy/CelPolicyYamlConfigParser.java | 392 ++++++++++++++++ .../java/dev/cel/policy/ParserContext.java | 33 ++ .../main/java/dev/cel/policy/ValueString.java | 47 ++ .../main/java/dev/cel/policy/YamlHelper.java | 123 +++++ .../dev/cel/policy/YamlParserContextImpl.java | 95 ++++ .../src/test/java/dev/cel/policy/BUILD.bazel | 8 +- .../dev/cel/policy/CelPolicySourceTest.java | 12 +- .../policy/CelPolicyYamlConfigParserTest.java | 443 ++++++++++++++++++ 15 files changed, 1703 insertions(+), 11 deletions(-) create mode 100644 policy/src/main/java/dev/cel/policy/CelPolicyConfig.java create mode 100644 policy/src/main/java/dev/cel/policy/CelPolicyConfigParser.java create mode 100644 policy/src/main/java/dev/cel/policy/CelPolicyValidationException.java create mode 100644 policy/src/main/java/dev/cel/policy/CelPolicyYamlConfigParser.java create mode 100644 policy/src/main/java/dev/cel/policy/ParserContext.java create mode 100644 policy/src/main/java/dev/cel/policy/ValueString.java create mode 100644 policy/src/main/java/dev/cel/policy/YamlHelper.java create mode 100644 policy/src/main/java/dev/cel/policy/YamlParserContextImpl.java create mode 100644 policy/src/test/java/dev/cel/policy/CelPolicyYamlConfigParserTest.java diff --git a/WORKSPACE b/WORKSPACE index cd72fce2c..09fdb0443 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -75,6 +75,7 @@ maven_install( "org.antlr:antlr4-runtime:" + ANTLR4_VERSION, "org.jspecify:jspecify:0.3.0", "org.threeten:threeten-extra:1.8.0", + "org.yaml:snakeyaml:2.2", ], repositories = [ "https://maven.google.com", diff --git a/policy/BUILD.bazel b/policy/BUILD.bazel index 5dfc04ed8..487bce068 100644 --- a/policy/BUILD.bazel +++ b/policy/BUILD.bazel @@ -1,9 +1,30 @@ package( default_applicable_licenses = ["//:license"], - default_visibility = ["//visibility:public"], + default_visibility = ["//visibility:public"], # TODO: Expose to public ) java_library( - name = "policy_source", - exports = ["//policy/src/main/java/dev/cel/policy:policy_source"], + name = "source", + exports = ["//policy/src/main/java/dev/cel/policy:source"], +) + +java_library( + name = "validation_exception", + exports = ["//policy/src/main/java/dev/cel/policy:validation_exception"], +) + +java_library( + name = "config", + exports = ["//policy/src/main/java/dev/cel/policy:config"], +) + +java_library( + name = "config_parser", + exports = ["//policy/src/main/java/dev/cel/policy:config_parser"], +) + +java_library( + name = "yaml_config_parser", + visibility = ["//visibility:public"], + exports = ["//policy/src/main/java/dev/cel/policy:yaml_config_parser"], ) diff --git a/policy/src/main/java/dev/cel/policy/BUILD.bazel b/policy/src/main/java/dev/cel/policy/BUILD.bazel index c9c896255..5fc24e33d 100644 --- a/policy/src/main/java/dev/cel/policy/BUILD.bazel +++ b/policy/src/main/java/dev/cel/policy/BUILD.bazel @@ -6,10 +6,12 @@ package( ) java_library( - name = "policy_source", + name = "source", srcs = [ "CelPolicySource.java", ], + tags = [ + ], deps = [ "//:auto_value", "//common:source", @@ -18,3 +20,101 @@ java_library( "@maven//:com_google_guava_guava", ], ) + +java_library( + name = "validation_exception", + srcs = [ + "CelPolicyValidationException.java", + ], + tags = [ + ], +) + +java_library( + name = "config", + srcs = [ + "CelPolicyConfig.java", + ], + tags = [ + ], + deps = [ + ":source", + "//:auto_value", + "@maven//:com_google_errorprone_error_prone_annotations", + "@maven//:com_google_guava_guava", + ], +) + +java_library( + name = "config_parser", + srcs = [ + "CelPolicyConfigParser.java", + ], + tags = [ + ], + deps = [ + ":config", + ":validation_exception", + ], +) + +java_library( + name = "yaml_config_parser", + srcs = [ + "CelPolicyYamlConfigParser.java", + ], + tags = [ + ], + deps = [ + ":config", + ":config_parser", + ":parser_context", + ":policy_common_internal", + ":source", + ":validation_exception", + "//common/internal", + "@maven//:com_google_guava_guava", + "@maven//:org_yaml_snakeyaml", + ], +) + +java_library( + name = "value_string", + srcs = [ + "ValueString.java", + ], + visibility = ["//visibility:private"], + deps = [ + "//:auto_value", + ], +) + +java_library( + name = "parser_context", + srcs = [ + "ParserContext.java", + ], + visibility = ["//visibility:private"], + deps = [ + "//common:source", + ], +) + +java_library( + name = "policy_common_internal", + srcs = [ + "YamlHelper.java", + "YamlParserContextImpl.java", + ], + visibility = ["//visibility:private"], + deps = [ + ":parser_context", + ":value_string", + "//common", + "//common:compiler_common", + "//common:source", + "//common/internal", + "@maven//:com_google_guava_guava", + "@maven//:org_yaml_snakeyaml", + ], +) diff --git a/policy/src/main/java/dev/cel/policy/CelPolicyConfig.java b/policy/src/main/java/dev/cel/policy/CelPolicyConfig.java new file mode 100644 index 000000000..4d15c4d8b --- /dev/null +++ b/policy/src/main/java/dev/cel/policy/CelPolicyConfig.java @@ -0,0 +1,364 @@ +// Copyright 2024 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.policy; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.collect.ImmutableList.toImmutableList; +import static java.util.Arrays.stream; + +import com.google.auto.value.AutoValue; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import com.google.errorprone.annotations.CanIgnoreReturnValue; +import com.google.errorprone.annotations.CheckReturnValue; +import java.util.AbstractMap; +import java.util.Arrays; +import java.util.Optional; + +/** + * CelPolicyConfig represents the policy configuration object to extend the CEL's compilation and + * runtime environment with. + */ +@AutoValue +public abstract class CelPolicyConfig { + + /** Config source. */ + public abstract CelPolicySource configSource(); + + /** Name of the config. */ + public abstract String name(); + + /** + * An optional description of the config (example: location of the file containing the config + * content). + */ + public abstract String description(); + + /** + * Container name to use as the namespace for resolving CEL expression variables and functions. + */ + public abstract String container(); + + /** + * Canonical extensions to enable in the environment, such as Optional, String and Math + * extensions. + */ + public abstract ImmutableSet extensions(); + + /** New variable declarations to add in the compilation environment. */ + public abstract ImmutableSet variables(); + + /** New function declarations to add in the compilation environment. */ + public abstract ImmutableSet functions(); + + /** Builder for {@link CelPolicyConfig}. */ + @AutoValue.Builder + public abstract static class Builder { + + public abstract Builder setConfigSource(CelPolicySource value); + + public abstract Builder setName(String name); + + public abstract Builder setDescription(String description); + + public abstract Builder setContainer(String container); + + public abstract Builder setExtensions(ImmutableSet extensions); + + public abstract Builder setVariables(ImmutableSet variables); + + public abstract Builder setFunctions(ImmutableSet functions); + + @CheckReturnValue + public abstract CelPolicyConfig build(); + } + + /** Creates a new builder to construct a {@link CelPolicyConfig} instance. */ + public static Builder newBuilder() { + return new AutoValue_CelPolicyConfig.Builder() + .setName("") + .setDescription("") + .setContainer("") + .setExtensions(ImmutableSet.of()) + .setVariables(ImmutableSet.of()) + .setFunctions(ImmutableSet.of()); + } + + /** Represents a policy variable declaration. */ + @AutoValue + public abstract static class VariableDecl { + + /** Fully qualified variable name. */ + public abstract String name(); + + /** The type of the variable. */ + public abstract TypeDecl type(); + + /** Builder for {@link VariableDecl}. */ + @AutoValue.Builder + public abstract static class Builder { + + abstract Optional name(); + + abstract Optional type(); + + public abstract Builder setName(String name); + + public abstract Builder setType(TypeDecl typeDecl); + + ImmutableList getMissingRequiredFieldNames() { + return getMissingRequiredFields( + new AbstractMap.SimpleEntry<>("name", name()), + new AbstractMap.SimpleEntry<>("type", type())); + } + + /** Builds a new instance of {@link VariableDecl}. */ + public abstract VariableDecl build(); + } + + public static Builder newBuilder() { + return new AutoValue_CelPolicyConfig_VariableDecl.Builder(); + } + + /** Creates a new builder to construct a {@link VariableDecl} instance. */ + public static VariableDecl create(String name, TypeDecl type) { + return newBuilder().setName(name).setType(type).build(); + } + } + + /** Represents a policy function declaration. */ + @AutoValue + public abstract static class FunctionDecl { + + public abstract String name(); + + public abstract ImmutableSet overloads(); + + /** Builder for {@link FunctionDecl}. */ + @AutoValue.Builder + public abstract static class Builder { + + abstract Optional name(); + + abstract Optional> overloads(); + + public abstract Builder setName(String name); + + public abstract Builder setOverloads(ImmutableSet overloads); + + ImmutableList getMissingRequiredFieldNames() { + return getMissingRequiredFields( + new AbstractMap.SimpleEntry<>("name", name()), + new AbstractMap.SimpleEntry<>("overloads", overloads())); + } + + /** Builds a new instance of {@link FunctionDecl}. */ + public abstract FunctionDecl build(); + } + + /** Creates a new builder to construct a {@link FunctionDecl} instance. */ + public static Builder newBuilder() { + return new AutoValue_CelPolicyConfig_FunctionDecl.Builder(); + } + + /** Creates a new {@link FunctionDecl} with the provided function name and its overloads. */ + public static FunctionDecl create(String name, ImmutableSet overloads) { + return newBuilder().setName(name).setOverloads(overloads).build(); + } + } + + /** Represents an overload declaraion on a policy function. */ + @AutoValue + public abstract static class OverloadDecl { + + /** + * A unique overload ID. Required. This should follow the typical naming convention used in CEL + * (e.g: targetType_func_argType1_argType...) + */ + public abstract String id(); + + /** Target of the function overload if it's a receiver style (example: foo in `foo.f(...)`) */ + public abstract Optional target(); + + /** List of function overload type values. */ + public abstract ImmutableList arguments(); + + /** Return type of the overload. Required. */ + public abstract TypeDecl returnType(); + + /** Builder for {@link OverloadDecl}. */ + @AutoValue.Builder + public abstract static class Builder { + + abstract Optional id(); + + abstract Optional returnType(); + + public abstract Builder setId(String overloadId); + + public abstract Builder setTarget(TypeDecl target); + + // This should stay package-private to encourage add/set methods to be used instead. + abstract ImmutableList.Builder argumentsBuilder(); + + public abstract Builder setArguments(ImmutableList args); + + @CanIgnoreReturnValue + public Builder addArguments(Iterable args) { + this.argumentsBuilder().addAll(checkNotNull(args)); + return this; + } + + @CanIgnoreReturnValue + public Builder addArguments(TypeDecl... args) { + return addArguments(Arrays.asList(args)); + } + + public abstract Builder setReturnType(TypeDecl returnType); + + ImmutableList getMissingRequiredFieldNames() { + return getMissingRequiredFields( + new AbstractMap.SimpleEntry<>("id", id()), + new AbstractMap.SimpleEntry<>("return", returnType())); + } + + /** Builds a new instance of {@link OverloadDecl}. */ + @CheckReturnValue + public abstract OverloadDecl build(); + } + + /** Creates a new builder to construct a {@link OverloadDecl} instance. */ + public static Builder newBuilder() { + return new AutoValue_CelPolicyConfig_OverloadDecl.Builder().setArguments(ImmutableList.of()); + } + } + + /** + * Represents an abstract type declaration used to declare functions and variables in a policy. + */ + @AutoValue + public abstract static class TypeDecl { + + public abstract String name(); + + public abstract ImmutableList params(); + + public abstract Boolean isTypeParam(); + + /** Builder for {@link TypeDecl}. */ + @AutoValue.Builder + public abstract static class Builder { + + abstract Optional name(); + + public abstract Builder setName(String name); + + // This should stay package-private to encourage add/set methods to be used instead. + abstract ImmutableList.Builder paramsBuilder(); + + public abstract Builder setParams(ImmutableList typeDecls); + + @CanIgnoreReturnValue + public Builder addParams(TypeDecl... params) { + return addParams(Arrays.asList(params)); + } + + @CanIgnoreReturnValue + public Builder addParams(Iterable params) { + this.paramsBuilder().addAll(checkNotNull(params)); + return this; + } + + public abstract Builder setIsTypeParam(boolean isTypeParam); + + ImmutableList getMissingRequiredFieldNames() { + return getMissingRequiredFields(new AbstractMap.SimpleEntry<>("type_name", name())); + } + + @CheckReturnValue + public abstract TypeDecl build(); + } + + /** Creates a new {@link TypeDecl} with the provided name. */ + public static TypeDecl create(String name) { + return newBuilder().setName(name).build(); + } + + public static Builder newBuilder() { + return new AutoValue_CelPolicyConfig_TypeDecl.Builder().setIsTypeParam(false); + } + } + + /** + * Represents a configuration for a canonical CEL extension that can be enabled in the + * environment. + */ + @AutoValue + public abstract static class ExtensionConfig { + + /** Name of the extension (ex: bindings, optional, math, etc).". */ + public abstract String name(); + + /** + * Version of the extension. Presently, this field is ignored as CEL-Java extensions are not + * versioned. + */ + public abstract Integer version(); + + /** Builder for {@link ExtensionConfig}. */ + @AutoValue.Builder + public abstract static class Builder { + + abstract Optional name(); + + abstract Optional version(); + + public abstract Builder setName(String name); + + public abstract Builder setVersion(Integer version); + + ImmutableList getMissingRequiredFieldNames() { + return getMissingRequiredFields(new AbstractMap.SimpleEntry<>("name", name())); + } + + /** Builds a new instance of {@link ExtensionConfig}. */ + public abstract ExtensionConfig build(); + } + + /** Creates a new builder to construct a {@link ExtensionConfig} instance. */ + public static Builder newBuilder() { + return new AutoValue_CelPolicyConfig_ExtensionConfig.Builder().setVersion(0); + } + + /** Create a new extension config with the specified name and version set to 0. */ + public static ExtensionConfig of(String name) { + return of(name, 0); + } + + /** Create a new extension config with the specified name and version. */ + public static ExtensionConfig of(String name, int version) { + return newBuilder().setName(name).setVersion(version).build(); + } + } + + @SafeVarargs + private static ImmutableList getMissingRequiredFields( + AbstractMap.SimpleEntry>... requiredFields) { + return stream(requiredFields) + .filter(entry -> !entry.getValue().isPresent()) + .map(AbstractMap.SimpleEntry::getKey) + .collect(toImmutableList()); + } +} diff --git a/policy/src/main/java/dev/cel/policy/CelPolicyConfigParser.java b/policy/src/main/java/dev/cel/policy/CelPolicyConfigParser.java new file mode 100644 index 000000000..9b03a1dd9 --- /dev/null +++ b/policy/src/main/java/dev/cel/policy/CelPolicyConfigParser.java @@ -0,0 +1,31 @@ +// Copyright 2024 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.policy; + +/** Public interface for parsing CEL policy sources. */ +public interface CelPolicyConfigParser { + + /** Parsers the input {@code policyConfigSource} and returns a {@link CelPolicyConfig}. */ + CelPolicyConfig parse(String policyConfigSource) throws CelPolicyValidationException; + + /** + * Parses the input {@code policyConfigSource} and returns a {@link CelPolicyConfig}. + * + *

The {@code description} may be used to help tailor error messages for the location where the + * {@code policySource} originates, e.g. a file name or form UI element. + */ + CelPolicyConfig parse(String policyConfigSource, String description) + throws CelPolicyValidationException; +} diff --git a/policy/src/main/java/dev/cel/policy/CelPolicySource.java b/policy/src/main/java/dev/cel/policy/CelPolicySource.java index b4c110d80..75565b563 100644 --- a/policy/src/main/java/dev/cel/policy/CelPolicySource.java +++ b/policy/src/main/java/dev/cel/policy/CelPolicySource.java @@ -50,9 +50,9 @@ public abstract static class Builder { public abstract Builder toBuilder(); - public static Builder newBuilder(String text) { + public static Builder newBuilder(CelCodePointArray celCodePointArray) { return new AutoValue_CelPolicySource.Builder() - .setContent(CelCodePointArray.fromString(text)) - .setDescription(""); + .setDescription("") + .setContent(celCodePointArray); } } diff --git a/policy/src/main/java/dev/cel/policy/CelPolicyValidationException.java b/policy/src/main/java/dev/cel/policy/CelPolicyValidationException.java new file mode 100644 index 000000000..1f7dc6ac2 --- /dev/null +++ b/policy/src/main/java/dev/cel/policy/CelPolicyValidationException.java @@ -0,0 +1,30 @@ +// Copyright 2024 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.policy; + +/** + * CelPolicyValidationException encapsulates all issues that arise when parsing or compiling a + * policy. + */ +public final class CelPolicyValidationException extends Exception { + + CelPolicyValidationException(String message) { + super(message); + } + + CelPolicyValidationException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/policy/src/main/java/dev/cel/policy/CelPolicyYamlConfigParser.java b/policy/src/main/java/dev/cel/policy/CelPolicyYamlConfigParser.java new file mode 100644 index 000000000..0cc348cc5 --- /dev/null +++ b/policy/src/main/java/dev/cel/policy/CelPolicyYamlConfigParser.java @@ -0,0 +1,392 @@ +// Copyright 2024 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.policy; + +import static dev.cel.policy.YamlHelper.ERROR; +import static dev.cel.policy.YamlHelper.assertRequiredFields; +import static dev.cel.policy.YamlHelper.assertYamlType; +import static dev.cel.policy.YamlHelper.newBoolean; +import static dev.cel.policy.YamlHelper.newInteger; +import static dev.cel.policy.YamlHelper.newString; +import static dev.cel.policy.YamlHelper.parseYamlSource; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import dev.cel.common.internal.CelCodePointArray; +import dev.cel.policy.CelPolicyConfig.ExtensionConfig; +import dev.cel.policy.CelPolicyConfig.FunctionDecl; +import dev.cel.policy.CelPolicyConfig.OverloadDecl; +import dev.cel.policy.CelPolicyConfig.TypeDecl; +import dev.cel.policy.CelPolicyConfig.VariableDecl; +import dev.cel.policy.YamlHelper.YamlNodeType; +import org.yaml.snakeyaml.nodes.MappingNode; +import org.yaml.snakeyaml.nodes.Node; +import org.yaml.snakeyaml.nodes.NodeTuple; +import org.yaml.snakeyaml.nodes.ScalarNode; +import org.yaml.snakeyaml.nodes.SequenceNode; + +/** Package-private class for parsing YAML config files. */ +final class CelPolicyYamlConfigParser implements CelPolicyConfigParser { + // Sentinel values to be returned for various declarations when parsing failure is encountered. + private static final TypeDecl ERROR_TYPE_DECL = TypeDecl.create(ERROR); + private static final VariableDecl ERROR_VARIABLE_DECL = + VariableDecl.create(ERROR, ERROR_TYPE_DECL); + private static final FunctionDecl ERROR_FUNCTION_DECL = + FunctionDecl.create(ERROR, ImmutableSet.of()); + private static final ExtensionConfig ERROR_EXTENSION_DECL = ExtensionConfig.of(ERROR); + + @Override + public CelPolicyConfig parse(String policyConfigSource) throws CelPolicyValidationException { + return parse(policyConfigSource, ""); + } + + @Override + public CelPolicyConfig parse(String policyConfigSource, String description) + throws CelPolicyValidationException { + ParserImpl parser = new ParserImpl(); + + return parser.parseYaml(policyConfigSource, description); + } + + private ImmutableSet parseVariables(ParserContext ctx, Node node) { + long valueId = ctx.collectMetadata(node); + ImmutableSet.Builder variableSetBuilder = ImmutableSet.builder(); + if (!assertYamlType(ctx, valueId, node, YamlNodeType.LIST)) { + return variableSetBuilder.build(); + } + + SequenceNode variableListNode = (SequenceNode) node; + for (Node elementNode : variableListNode.getValue()) { + variableSetBuilder.add(parseVariable(ctx, elementNode)); + } + + return variableSetBuilder.build(); + } + + private VariableDecl parseVariable(ParserContext ctx, Node node) { + long variableId = ctx.collectMetadata(node); + if (!assertYamlType(ctx, variableId, node, YamlNodeType.MAP)) { + return ERROR_VARIABLE_DECL; + } + + MappingNode variableMap = (MappingNode) node; + VariableDecl.Builder builder = VariableDecl.newBuilder(); + for (NodeTuple nodeTuple : variableMap.getValue()) { + Node keyNode = nodeTuple.getKeyNode(); + long keyId = ctx.collectMetadata(keyNode); + Node valueNode = nodeTuple.getValueNode(); + String keyName = ((ScalarNode) keyNode).getValue(); + switch (keyName) { + case "name": + builder.setName(newString(ctx, valueNode)); + break; + case "type": + builder.setType(parseTypeDecl(ctx, valueNode)); + break; + default: + ctx.reportError(keyId, String.format("Unsupported variable tag: %s", keyName)); + break; + } + } + + if (!assertRequiredFields(ctx, variableId, builder.getMissingRequiredFieldNames())) { + return ERROR_VARIABLE_DECL; + } + + return builder.build(); + } + + private ImmutableSet parseFunctions(ParserContext ctx, Node node) { + long valueId = ctx.collectMetadata(node); + ImmutableSet.Builder functionSetBuilder = ImmutableSet.builder(); + if (!assertYamlType(ctx, valueId, node, YamlNodeType.LIST)) { + return functionSetBuilder.build(); + } + + SequenceNode functionListNode = (SequenceNode) node; + for (Node elementNode : functionListNode.getValue()) { + functionSetBuilder.add(parseFunction(ctx, elementNode)); + } + + return functionSetBuilder.build(); + } + + private FunctionDecl parseFunction(ParserContext ctx, Node node) { + long functionId = ctx.collectMetadata(node); + if (!assertYamlType(ctx, functionId, node, YamlNodeType.MAP)) { + return ERROR_FUNCTION_DECL; + } + + MappingNode functionMap = (MappingNode) node; + FunctionDecl.Builder builder = FunctionDecl.newBuilder(); + for (NodeTuple nodeTuple : functionMap.getValue()) { + Node keyNode = nodeTuple.getKeyNode(); + long keyId = ctx.collectMetadata(keyNode); + Node valueNode = nodeTuple.getValueNode(); + String keyName = ((ScalarNode) keyNode).getValue(); + switch (keyName) { + case "name": + builder.setName(newString(ctx, valueNode)); + break; + case "overloads": + builder.setOverloads(parseOverloads(ctx, valueNode)); + break; + default: + ctx.reportError(keyId, String.format("Unsupported function tag: %s", keyName)); + break; + } + } + + if (!assertRequiredFields(ctx, functionId, builder.getMissingRequiredFieldNames())) { + return ERROR_FUNCTION_DECL; + } + + return builder.build(); + } + + private static ImmutableSet parseOverloads(ParserContext ctx, Node node) { + long listId = ctx.collectMetadata(node); + ImmutableSet.Builder overloadSetBuilder = ImmutableSet.builder(); + if (!assertYamlType(ctx, listId, node, YamlNodeType.LIST)) { + return overloadSetBuilder.build(); + } + + SequenceNode overloadListNode = (SequenceNode) node; + for (Node overloadMapNode : overloadListNode.getValue()) { + long overloadMapId = ctx.collectMetadata(overloadMapNode); + if (!assertYamlType(ctx, overloadMapId, overloadMapNode, YamlNodeType.MAP)) { + continue; + } + + MappingNode mapNode = (MappingNode) overloadMapNode; + OverloadDecl.Builder overloadDeclBuilder = OverloadDecl.newBuilder(); + for (NodeTuple nodeTuple : mapNode.getValue()) { + Node keyNode = nodeTuple.getKeyNode(); + long keyId = ctx.collectMetadata(keyNode); + if (!assertYamlType(ctx, keyId, keyNode, YamlNodeType.STRING, YamlNodeType.TEXT)) { + continue; + } + + Node valueNode = nodeTuple.getValueNode(); + String fieldName = ((ScalarNode) keyNode).getValue(); + switch (fieldName) { + case "id": + overloadDeclBuilder.setId(newString(ctx, valueNode)); + break; + case "args": + overloadDeclBuilder.addArguments(parseOverloadArguments(ctx, valueNode)); + break; + case "return": + overloadDeclBuilder.setReturnType(parseTypeDecl(ctx, valueNode)); + break; + case "target": + overloadDeclBuilder.setTarget(parseTypeDecl(ctx, valueNode)); + break; + default: + ctx.reportError(keyId, String.format("Unsupported overload tag: %s", fieldName)); + break; + } + } + + if (assertRequiredFields( + ctx, overloadMapId, overloadDeclBuilder.getMissingRequiredFieldNames())) { + overloadSetBuilder.add(overloadDeclBuilder.build()); + } + } + + return overloadSetBuilder.build(); + } + + private static ImmutableList parseOverloadArguments( + ParserContext ctx, Node node) { + long listValueId = ctx.collectMetadata(node); + if (!assertYamlType(ctx, listValueId, node, YamlNodeType.LIST)) { + return ImmutableList.of(); + } + SequenceNode paramsListNode = (SequenceNode) node; + ImmutableList.Builder builder = ImmutableList.builder(); + for (Node elementNode : paramsListNode.getValue()) { + builder.add(parseTypeDecl(ctx, elementNode)); + } + + return builder.build(); + } + + private static ImmutableSet parseExtensions(ParserContext ctx, Node node) { + long valueId = ctx.collectMetadata(node); + ImmutableSet.Builder extensionConfigBuilder = ImmutableSet.builder(); + if (!assertYamlType(ctx, valueId, node, YamlNodeType.LIST)) { + return extensionConfigBuilder.build(); + } + + SequenceNode extensionListNode = (SequenceNode) node; + for (Node elementNode : extensionListNode.getValue()) { + extensionConfigBuilder.add(parseExtension(ctx, elementNode)); + } + + return extensionConfigBuilder.build(); + } + + private static ExtensionConfig parseExtension(ParserContext ctx, Node node) { + long extensionId = ctx.collectMetadata(node); + if (!assertYamlType(ctx, extensionId, node, YamlNodeType.MAP)) { + return ERROR_EXTENSION_DECL; + } + + MappingNode extensionMap = (MappingNode) node; + ExtensionConfig.Builder builder = ExtensionConfig.newBuilder(); + for (NodeTuple nodeTuple : extensionMap.getValue()) { + Node keyNode = nodeTuple.getKeyNode(); + long keyId = ctx.collectMetadata(keyNode); + Node valueNode = nodeTuple.getValueNode(); + String keyName = ((ScalarNode) keyNode).getValue(); + switch (keyName) { + case "name": + builder.setName(newString(ctx, valueNode)); + break; + case "version": + builder.setVersion(newInteger(ctx, valueNode)); + break; + default: + ctx.reportError(keyId, String.format("Unsupported extension tag: %s", keyName)); + break; + } + } + + if (!assertRequiredFields(ctx, extensionId, builder.getMissingRequiredFieldNames())) { + return ERROR_EXTENSION_DECL; + } + + return builder.build(); + } + + private static TypeDecl parseTypeDecl(ParserContext ctx, Node node) { + TypeDecl.Builder builder = TypeDecl.newBuilder(); + long id = ctx.collectMetadata(node); + if (!assertYamlType(ctx, id, node, YamlNodeType.MAP)) { + return ERROR_TYPE_DECL; + } + + MappingNode mapNode = (MappingNode) node; + for (NodeTuple nodeTuple : mapNode.getValue()) { + Node keyNode = nodeTuple.getKeyNode(); + long keyId = ctx.collectMetadata(keyNode); + if (!assertYamlType(ctx, keyId, keyNode, YamlNodeType.STRING, YamlNodeType.TEXT)) { + continue; + } + + Node valueNode = nodeTuple.getValueNode(); + String fieldName = ((ScalarNode) keyNode).getValue(); + switch (fieldName) { + case "type_name": + builder.setName(newString(ctx, valueNode)); + break; + case "is_type_param": + builder.setIsTypeParam(newBoolean(ctx, valueNode)); + break; + case "params": + long listValueId = ctx.collectMetadata(node); + if (!assertYamlType(ctx, listValueId, valueNode, YamlNodeType.LIST)) { + break; + } + SequenceNode paramsListNode = (SequenceNode) valueNode; + for (Node elementNode : paramsListNode.getValue()) { + builder.addParams(parseTypeDecl(ctx, elementNode)); + } + break; + default: + ctx.reportError(keyId, String.format("Unsupported type decl tag: %s", fieldName)); + break; + } + } + + if (!assertRequiredFields(ctx, id, builder.getMissingRequiredFieldNames())) { + return ERROR_TYPE_DECL; + } + + return builder.build(); + } + + private class ParserImpl { + + private CelPolicyConfig parseYaml(String source, String description) + throws CelPolicyValidationException { + Node node; + try { + node = parseYamlSource(source); + } catch (RuntimeException e) { + throw new CelPolicyValidationException("YAML document is malformed: " + e.getMessage(), e); + } + + CelCodePointArray configCodePointArray = CelCodePointArray.fromString(source); + ParserContext ctx = YamlParserContextImpl.newInstance(configCodePointArray); + CelPolicyConfig.Builder policyConfig = parseConfig(ctx, node); + CelPolicySource configSource = + CelPolicySource.newBuilder(configCodePointArray).setDescription(description).build(); + if (ctx.hasError()) { + throw new CelPolicyValidationException(ctx.getIssueString(configSource)); + } + return policyConfig.setConfigSource(configSource).build(); + } + + private CelPolicyConfig.Builder parseConfig(ParserContext ctx, Node node) { + CelPolicyConfig.Builder builder = CelPolicyConfig.newBuilder(); + long id = ctx.collectMetadata(node); + if (!assertYamlType(ctx, id, node, YamlNodeType.MAP)) { + return builder; + } + MappingNode rootNode = (MappingNode) node; + for (NodeTuple nodeTuple : rootNode.getValue()) { + Node keyNode = nodeTuple.getKeyNode(); + long keyId = ctx.collectMetadata(keyNode); + if (!assertYamlType(ctx, keyId, keyNode, YamlNodeType.STRING, YamlNodeType.TEXT)) { + continue; + } + Node valueNode = nodeTuple.getValueNode(); + String fieldName = ((ScalarNode) keyNode).getValue(); + switch (fieldName) { + case "name": + builder.setName(newString(ctx, valueNode)); + break; + case "description": + builder.setDescription(newString(ctx, valueNode)); + break; + case "container": + builder.setContainer(newString(ctx, valueNode)); + break; + case "variables": + builder.setVariables(parseVariables(ctx, valueNode)); + break; + case "functions": + builder.setFunctions(parseFunctions(ctx, valueNode)); + break; + case "extensions": + builder.setExtensions(parseExtensions(ctx, valueNode)); + break; + default: + ctx.reportError(id, "Unknown config tag: " + fieldName); + // continue handling the rest of the nodes + } + } + return builder; + } + } + + static CelPolicyYamlConfigParser newInstance() { + return new CelPolicyYamlConfigParser(); + } + + private CelPolicyYamlConfigParser() {} +} diff --git a/policy/src/main/java/dev/cel/policy/ParserContext.java b/policy/src/main/java/dev/cel/policy/ParserContext.java new file mode 100644 index 000000000..ec4c72f20 --- /dev/null +++ b/policy/src/main/java/dev/cel/policy/ParserContext.java @@ -0,0 +1,33 @@ +// Copyright 2024 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.policy; + +import dev.cel.common.Source; + +/** + * ParserContext declares a set of interfaces for creating and managing metadata for parsed + * policies. + */ +public interface ParserContext { + long nextId(); + + long collectMetadata(T node); + + void reportError(long id, String message); + + String getIssueString(Source source); + + boolean hasError(); +} diff --git a/policy/src/main/java/dev/cel/policy/ValueString.java b/policy/src/main/java/dev/cel/policy/ValueString.java new file mode 100644 index 000000000..b1de15be5 --- /dev/null +++ b/policy/src/main/java/dev/cel/policy/ValueString.java @@ -0,0 +1,47 @@ +// Copyright 2024 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.policy; + +import com.google.auto.value.AutoValue; + +/** ValueString contains an identifier corresponding to source metadata and a simple string. */ +@AutoValue +public abstract class ValueString { + + /** A unique identifier. This is populated by the parser. */ + abstract long id(); + + abstract String value(); + + @AutoValue.Builder + abstract static class Builder { + + abstract Builder setId(long id); + + abstract Builder setValue(String value); + + abstract ValueString build(); + } + + /** Builder for {@link ValueString}. */ + static Builder newBuilder() { + return new AutoValue_ValueString.Builder().setId(0).setValue(""); + } + + /** Creates a new {@link ValueString} instance with the specified ID and string value. */ + static ValueString of(long id, String value) { + return newBuilder().setId(id).setValue(value).build(); + } +} diff --git a/policy/src/main/java/dev/cel/policy/YamlHelper.java b/policy/src/main/java/dev/cel/policy/YamlHelper.java new file mode 100644 index 000000000..a29e8c73b --- /dev/null +++ b/policy/src/main/java/dev/cel/policy/YamlHelper.java @@ -0,0 +1,123 @@ +// Copyright 2024 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.policy; + +import static java.util.Arrays.stream; +import static java.util.stream.Collectors.joining; + +import com.google.common.base.Joiner; +import java.io.StringReader; +import java.util.List; +import org.yaml.snakeyaml.LoaderOptions; +import org.yaml.snakeyaml.Yaml; +import org.yaml.snakeyaml.constructor.SafeConstructor; +import org.yaml.snakeyaml.nodes.Node; +import org.yaml.snakeyaml.nodes.ScalarNode; + +final class YamlHelper { + static final String ERROR = "*error*"; + + enum YamlNodeType { + MAP("tag:yaml.org,2002:map"), + STRING("tag:yaml.org,2002:str"), + BOOLEAN("tag:yaml.org,2002:bool"), + INTEGER("tag:yaml.org,2002:int"), + DOUBLE("tag:yaml.org,2002:float"), + TEXT("!txt"), + LIST("tag:yaml.org,2002:seq"), + ; + + private final String tag; + + String tag() { + return tag; + } + + YamlNodeType(String tag) { + this.tag = tag; + } + } + + static Node parseYamlSource(String policyContent) { + Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions())); + + return yaml.compose(new StringReader(policyContent)); + } + + static boolean assertRequiredFields( + ParserContext ctx, long id, List missingRequiredFields) { + if (missingRequiredFields.isEmpty()) { + return true; + } + + ctx.reportError( + id, + String.format( + "Missing required attribute(s): %s", Joiner.on(", ").join(missingRequiredFields))); + return false; + } + + static boolean assertYamlType( + ParserContext ctx, long id, Node node, YamlNodeType... expectedNodeTypes) { + String nodeTag = node.getTag().getValue(); + for (YamlNodeType expectedNodeType : expectedNodeTypes) { + if (expectedNodeType.tag().equals(nodeTag)) { + return true; + } + } + ctx.reportError( + id, + String.format( + "Got yaml node type %s, wanted type(s) [%s]", + nodeTag, stream(expectedNodeTypes).map(YamlNodeType::tag).collect(joining(" ")))); + return false; + } + + static Integer newInteger(ParserContext ctx, Node node) { + long id = ctx.collectMetadata(node); + if (!assertYamlType(ctx, id, node, YamlNodeType.INTEGER)) { + return 0; + } + + return Integer.parseInt(((ScalarNode) node).getValue()); + } + + static boolean newBoolean(ParserContext ctx, Node node) { + long id = ctx.collectMetadata(node); + if (!assertYamlType(ctx, id, node, YamlNodeType.BOOLEAN)) { + return false; + } + + return Boolean.parseBoolean(((ScalarNode) node).getValue()); + } + + static String newString(ParserContext ctx, Node node) { + return YamlHelper.newValueString(ctx, node).value(); + } + + static ValueString newValueString(ParserContext ctx, Node node) { + long id = ctx.collectMetadata(node); + if (!assertYamlType(ctx, id, node, YamlNodeType.STRING, YamlNodeType.TEXT)) { + return ValueString.of(id, ERROR); + } + + ScalarNode scalarNode = (ScalarNode) node; + + // TODO: Compute relative source for multiline strings + return ValueString.of(id, scalarNode.getValue()); + } + + private YamlHelper() {} +} diff --git a/policy/src/main/java/dev/cel/policy/YamlParserContextImpl.java b/policy/src/main/java/dev/cel/policy/YamlParserContextImpl.java new file mode 100644 index 000000000..34f70db6c --- /dev/null +++ b/policy/src/main/java/dev/cel/policy/YamlParserContextImpl.java @@ -0,0 +1,95 @@ +// Copyright 2024 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.policy; + +import static com.google.common.collect.ImmutableList.toImmutableList; + +import com.google.common.base.Joiner; +import dev.cel.common.CelIssue; +import dev.cel.common.CelSourceLocation; +import dev.cel.common.Source; +import dev.cel.common.internal.CelCodePointArray; +import java.util.ArrayList; +import java.util.HashMap; +import org.yaml.snakeyaml.DumperOptions; +import org.yaml.snakeyaml.nodes.Node; +import org.yaml.snakeyaml.nodes.ScalarNode; + +/** Package-private class to assist with storing policy parsing context. */ +final class YamlParserContextImpl implements ParserContext { + + private static final Joiner JOINER = Joiner.on('\n'); + + private final ArrayList issues; + private final HashMap idToLocationMap; + private final HashMap idToOffsetMap; + private final CelCodePointArray policyContent; + private long id; + + @Override + public void reportError(long id, String message) { + issues.add(CelIssue.formatError(idToLocationMap.get(id), message)); + } + + @Override + public String getIssueString(Source source) { + return JOINER.join( + issues.stream().map(iss -> iss.toDisplayString(source)).collect(toImmutableList())); + } + + @Override + public boolean hasError() { + return !issues.isEmpty(); + } + + @Override + public long collectMetadata(Node node) { + long id = nextId(); + int line = node.getStartMark().getLine() + 1; // Yaml lines are 0 indexed + int column = node.getStartMark().getColumn(); + if (node instanceof ScalarNode) { + DumperOptions.ScalarStyle style = ((ScalarNode) node).getScalarStyle(); + if (style.equals(DumperOptions.ScalarStyle.SINGLE_QUOTED) + || style.equals(DumperOptions.ScalarStyle.DOUBLE_QUOTED)) { + column++; + } + } + idToLocationMap.put(id, CelSourceLocation.of(line, column)); + + int offset = 0; + if (line > 1) { + offset = policyContent.lineOffsets().get(line - 2) + column; + } + idToOffsetMap.put(id, offset); + + return id; + } + + @Override + public long nextId() { + return ++id; + } + + static ParserContext newInstance(CelCodePointArray policyContent) { + return new YamlParserContextImpl(policyContent); + } + + private YamlParserContextImpl(CelCodePointArray policyContent) { + this.issues = new ArrayList<>(); + this.idToLocationMap = new HashMap<>(); + this.idToOffsetMap = new HashMap<>(); + this.policyContent = policyContent; + } +} diff --git a/policy/src/test/java/dev/cel/policy/BUILD.bazel b/policy/src/test/java/dev/cel/policy/BUILD.bazel index 26c7996bf..951b45f6a 100644 --- a/policy/src/test/java/dev/cel/policy/BUILD.bazel +++ b/policy/src/test/java/dev/cel/policy/BUILD.bazel @@ -8,7 +8,13 @@ java_library( srcs = glob(["*.java"]), deps = [ "//:java_truth", - "//policy:policy_source", + "//common/internal", + "//policy:config", + "//policy:config_parser", + "//policy:source", + "//policy:validation_exception", + "//policy:yaml_config_parser", + "@maven//:com_google_guava_guava", "@maven//:com_google_testparameterinjector_test_parameter_injector", "@maven//:junit_junit", ], diff --git a/policy/src/test/java/dev/cel/policy/CelPolicySourceTest.java b/policy/src/test/java/dev/cel/policy/CelPolicySourceTest.java index 9dc309b3f..9aa73ee6c 100644 --- a/policy/src/test/java/dev/cel/policy/CelPolicySourceTest.java +++ b/policy/src/test/java/dev/cel/policy/CelPolicySourceTest.java @@ -17,6 +17,7 @@ import static com.google.common.truth.Truth.assertThat; import com.google.testing.junit.testparameterinjector.TestParameterInjector; +import dev.cel.common.internal.CelCodePointArray; import org.junit.Test; import org.junit.runner.RunWith; @@ -25,7 +26,10 @@ public final class CelPolicySourceTest { @Test public void constructPolicySource_success() { - CelPolicySource policySource = CelPolicySource.newBuilder("hello world").build(); + CelPolicySource policySource = + CelPolicySource.newBuilder(CelCodePointArray.fromString("hello world")) + .setDescription("") + .build(); assertThat(policySource.getContent().toString()).isEqualTo("hello world"); assertThat(policySource.getDescription()).isEqualTo(""); @@ -33,7 +37,8 @@ public void constructPolicySource_success() { @Test public void getSnippet_success() { - CelPolicySource policySource = CelPolicySource.newBuilder("hello\nworld").build(); + CelPolicySource policySource = + CelPolicySource.newBuilder(CelCodePointArray.fromString("hello\nworld")).build(); assertThat(policySource.getSnippet(1)).hasValue("hello"); assertThat(policySource.getSnippet(2)).hasValue("world"); @@ -41,7 +46,8 @@ public void getSnippet_success() { @Test public void getSnippet_returnsEmpty() { - CelPolicySource policySource = CelPolicySource.newBuilder("hello\nworld").build(); + CelPolicySource policySource = + CelPolicySource.newBuilder(CelCodePointArray.fromString("hello\nworld")).build(); assertThat(policySource.getSnippet(3)).isEmpty(); } diff --git a/policy/src/test/java/dev/cel/policy/CelPolicyYamlConfigParserTest.java b/policy/src/test/java/dev/cel/policy/CelPolicyYamlConfigParserTest.java new file mode 100644 index 000000000..020d9f689 --- /dev/null +++ b/policy/src/test/java/dev/cel/policy/CelPolicyYamlConfigParserTest.java @@ -0,0 +1,443 @@ +// Copyright 2024 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.policy; + +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertThrows; + +import com.google.common.collect.ImmutableSet; +import com.google.testing.junit.testparameterinjector.TestParameter; +import com.google.testing.junit.testparameterinjector.TestParameterInjector; +import dev.cel.policy.CelPolicyConfig.ExtensionConfig; +import dev.cel.policy.CelPolicyConfig.FunctionDecl; +import dev.cel.policy.CelPolicyConfig.OverloadDecl; +import dev.cel.policy.CelPolicyConfig.TypeDecl; +import dev.cel.policy.CelPolicyConfig.VariableDecl; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(TestParameterInjector.class) +public final class CelPolicyYamlConfigParserTest { + + private static final CelPolicyConfigParser POLICY_CONFIG_PARSER = + CelPolicyYamlConfigParser.newInstance(); + + @Test + public void config_setBasicProperties() throws Exception { + String yamlConfig = "name: hello\n" + "description: empty\n" + "container: pb.pkg\n"; + + CelPolicyConfig policyConfig = POLICY_CONFIG_PARSER.parse(yamlConfig); + + assertThat(policyConfig) + .isEqualTo( + CelPolicyConfig.newBuilder() + .setConfigSource(policyConfig.configSource()) + .setName("hello") + .setDescription("empty") + .setContainer("pb.pkg") + .build()); + } + + @Test + public void config_setExtensions() throws Exception { + String yamlConfig = + "extensions:\n" + + " - name: 'bindings'\n" + + " - name: 'encoders'\n" + + " - name: 'math'\n" + + " - name: 'optional'\n" + + " - name: 'protos'\n" + + " - name: 'sets'\n" + + " - name: 'strings'\n" + + " version: 1"; + + CelPolicyConfig policyConfig = POLICY_CONFIG_PARSER.parse(yamlConfig); + + assertThat(policyConfig) + .isEqualTo( + CelPolicyConfig.newBuilder() + .setConfigSource(policyConfig.configSource()) + .setExtensions( + ImmutableSet.of( + ExtensionConfig.of("bindings"), + ExtensionConfig.of("encoders"), + ExtensionConfig.of("math"), + ExtensionConfig.of("optional"), + ExtensionConfig.of("protos"), + ExtensionConfig.of("sets"), + ExtensionConfig.of("strings", 1))) + .build()); + } + + @Test + public void config_setFunctions() throws Exception { + String yamlConfig = + "functions:\n" + + " - name: 'coalesce'\n" + + " overloads:\n" + + " - id: 'null_coalesce_int'\n" + + " target:\n" + + " type_name: 'null_type'\n" + + " args:\n" + + " - type_name: 'int'\n" + + " return:\n" + + " type_name: 'int'\n" + + " - id: 'coalesce_null_int'\n" + + " args:\n" + + " - type_name: 'null_type'\n" + + " - type_name: 'int'\n" + + " return:\n" + + " type_name: 'int' \n" + + " - id: 'int_coalesce_int'\n" + + " target: \n" + + " type_name: 'int'\n" + + " args:\n" + + " - type_name: 'int'\n" + + " return: \n" + + " type_name: 'int'\n" + + " - id: 'optional_T_coalesce_T'\n" + + " target: \n" + + " type_name: 'optional_type'\n" + + " params:\n" + + " - type_name: 'T'\n" + + " is_type_param: true\n" + + " args:\n" + + " - type_name: 'T'\n" + + " is_type_param: true\n" + + " return: \n" + + " type_name: 'T'\n" + + " is_type_param: true"; + + CelPolicyConfig policyConfig = POLICY_CONFIG_PARSER.parse(yamlConfig); + + assertThat(policyConfig) + .isEqualTo( + CelPolicyConfig.newBuilder() + .setConfigSource(policyConfig.configSource()) + .setFunctions( + ImmutableSet.of( + FunctionDecl.create( + "coalesce", + ImmutableSet.of( + OverloadDecl.newBuilder() + .setId("null_coalesce_int") + .setTarget(TypeDecl.create("null_type")) + .addArguments(TypeDecl.create("int")) + .setReturnType(TypeDecl.create("int")) + .build(), + OverloadDecl.newBuilder() + .setId("coalesce_null_int") + .addArguments( + TypeDecl.create("null_type"), TypeDecl.create("int")) + .setReturnType(TypeDecl.create("int")) + .build(), + OverloadDecl.newBuilder() + .setId("int_coalesce_int") + .setTarget(TypeDecl.create("int")) + .addArguments(TypeDecl.create("int")) + .setReturnType(TypeDecl.create("int")) + .build(), + OverloadDecl.newBuilder() + .setId("optional_T_coalesce_T") + .setTarget( + TypeDecl.newBuilder() + .setName("optional_type") + .addParams( + TypeDecl.newBuilder() + .setName("T") + .setIsTypeParam(true) + .build()) + .build()) + .addArguments( + TypeDecl.newBuilder() + .setName("T") + .setIsTypeParam(true) + .build()) + .setReturnType( + TypeDecl.newBuilder() + .setName("T") + .setIsTypeParam(true) + .build()) + .build())))) + .build()); + } + + @Test + public void config_setListVariable() throws Exception { + String yamlConfig = + "variables:\n" + + "- name: 'request'\n" + + " type:\n" + + " type_name: 'list'\n" + + " params:\n" + + " - type_name: 'string'"; + + CelPolicyConfig policyConfig = POLICY_CONFIG_PARSER.parse(yamlConfig); + + assertThat(policyConfig) + .isEqualTo( + CelPolicyConfig.newBuilder() + .setConfigSource(policyConfig.configSource()) + .setVariables( + ImmutableSet.of( + VariableDecl.create( + "request", + TypeDecl.newBuilder() + .setName("list") + .addParams(TypeDecl.create("string")) + .build()))) + .build()); + } + + @Test + public void config_setMapVariable() throws Exception { + String yamlConfig = + "variables:\n" + + "- name: 'request'\n" + + " type:\n" + + " type_name: 'map'\n" + + " params:\n" + + " - type_name: 'string'\n" + + " - type_name: 'dyn'"; + + CelPolicyConfig policyConfig = POLICY_CONFIG_PARSER.parse(yamlConfig); + + assertThat(policyConfig) + .isEqualTo( + CelPolicyConfig.newBuilder() + .setConfigSource(policyConfig.configSource()) + .setVariables( + ImmutableSet.of( + VariableDecl.create( + "request", + TypeDecl.newBuilder() + .setName("map") + .addParams(TypeDecl.create("string"), TypeDecl.create("dyn")) + .build()))) + .build()); + } + + @Test + public void config_setMessageVariable() throws Exception { + String yamlConfig = + "variables:\n" + + "- name: 'request'\n" + + " type:\n" + + " type_name: 'google.rpc.context.AttributeContext.Request'"; + + CelPolicyConfig policyConfig = POLICY_CONFIG_PARSER.parse(yamlConfig); + + assertThat(policyConfig) + .isEqualTo( + CelPolicyConfig.newBuilder() + .setConfigSource(policyConfig.configSource()) + .setVariables( + ImmutableSet.of( + VariableDecl.create( + "request", + TypeDecl.create("google.rpc.context.AttributeContext.Request")))) + .build()); + } + + @Test + public void config_parseErrors(@TestParameter ConfigParseErrorTestcase testCase) { + CelPolicyValidationException e = + assertThrows( + CelPolicyValidationException.class, + () -> POLICY_CONFIG_PARSER.parse(testCase.yamlConfig)); + assertThat(e).hasMessageThat().isEqualTo(testCase.expectedErrorMessage); + } + + // Note: dangling comments in expressions below is to retain the newlines by preventing auto + // formatter from compressing them in a single line. + private enum ConfigParseErrorTestcase { + MALFORMED_YAML_DOCUMENT( + "a:\na", + "YAML document is malformed: while scanning a simple key\n" + + " in 'reader', line 2, column 1:\n" + + " a\n" + + " ^\n" + + "could not find expected ':'\n" + + " in 'reader', line 2, column 2:\n" + + " a\n" + + " ^\n"), + ILLEGAL_YAML_TYPE_CONFIG_KEY( + "1: test", + "ERROR: :1:1: Got yaml node type tag:yaml.org,2002:int, wanted type(s)" + + " [tag:yaml.org,2002:str !txt]\n" + + " | 1: test\n" + + " | ^"), + ILLEGAL_YAML_TYPE_CONFIG_VALUE( + "test: 1", "ERROR: :1:1: Unknown config tag: test\n" + " | test: 1\n" + " | ^"), + ILLEGAL_YAML_TYPE_VARIABLE_LIST( + "variables: 1", + "ERROR: :1:12: Got yaml node type tag:yaml.org,2002:int, wanted type(s)" + + " [tag:yaml.org,2002:seq]\n" + + " | variables: 1\n" + + " | ...........^"), + ILLEGAL_YAML_TYPE_VARIABLE_VALUE( + "variables:\n - 1", + "ERROR: :2:4: Got yaml node type tag:yaml.org,2002:int, wanted type(s)" + + " [tag:yaml.org,2002:map]\n" + + " | - 1\n" + + " | ...^"), + ILLEGAL_YAML_TYPE_FUNCTION_LIST( + "functions: 1", + "ERROR: :1:12: Got yaml node type tag:yaml.org,2002:int, wanted type(s)" + + " [tag:yaml.org,2002:seq]\n" + + " | functions: 1\n" + + " | ...........^"), + ILLEGAL_YAML_TYPE_FUNCTION_VALUE( + "functions:\n - 1", + "ERROR: :2:4: Got yaml node type tag:yaml.org,2002:int, wanted type(s)" + + " [tag:yaml.org,2002:map]\n" + + " | - 1\n" + + " | ...^"), + ILLEGAL_YAML_TYPE_OVERLOAD_LIST( + "functions:\n" // + + " - name: foo\n" // + + " overloads: 1", + "ERROR: :3:15: Got yaml node type tag:yaml.org,2002:int, wanted type(s)" + + " [tag:yaml.org,2002:seq]\n" + + " | overloads: 1\n" + + " | ..............^"), + ILLEGAL_YAML_TYPE_OVERLOAD_VALUE( + "functions:\n" // + + " - name: foo\n" // + + " overloads:\n" // + + " - 2", + "ERROR: :4:7: Got yaml node type tag:yaml.org,2002:int, wanted type(s)" + + " [tag:yaml.org,2002:map]\n" + + " | - 2\n" + + " | ......^"), + ILLEGAL_YAML_TYPE_OVERLOAD_VALUE_MAP_KEY( + "functions:\n" // + + " - name: foo\n" // + + " overloads:\n" // + + " - 2: test", + "ERROR: :4:9: Got yaml node type tag:yaml.org,2002:int, wanted type(s)" + + " [tag:yaml.org,2002:str !txt]\n" + + " | - 2: test\n" + + " | ........^\n" + + "ERROR: :4:9: Missing required attribute(s): id, return\n" + + " | - 2: test\n" + + " | ........^"), + ILLEGAL_YAML_TYPE_EXTENSION_LIST( + "extensions: 1", + "ERROR: :1:13: Got yaml node type tag:yaml.org,2002:int, wanted type(s)" + + " [tag:yaml.org,2002:seq]\n" + + " | extensions: 1\n" + + " | ............^"), + ILLEGAL_YAML_TYPE_EXTENSION_VALUE( + "extensions:\n - 1", + "ERROR: :2:4: Got yaml node type tag:yaml.org,2002:int, wanted type(s)" + + " [tag:yaml.org,2002:map]\n" + + " | - 1\n" + + " | ...^"), + ILLEGAL_YAML_TYPE_TYPE_DECL( + "variables:\n" // + + " - name: foo\n" // + + " type: 1", + "ERROR: :3:10: Got yaml node type tag:yaml.org,2002:int, wanted type(s)" + + " [tag:yaml.org,2002:map]\n" + + " | type: 1\n" + + " | .........^"), + ILLEGAL_YAML_TYPE_TYPE_VALUE( + "variables:\n" + + " - name: foo\n" + + " type:\n" + + " type_name: bar\n" + + " 1: hello", + "ERROR: :5:6: Got yaml node type tag:yaml.org,2002:int, wanted type(s)" + + " [tag:yaml.org,2002:str !txt]\n" + + " | 1: hello\n" + + " | .....^"), + ILLEGAL_YAML_TYPE_TYPE_PARAMS_LIST( + "variables:\n" + + " - name: foo\n" + + " type:\n" + + " type_name: bar\n" + + " params: 1", + "ERROR: :4:6: Got yaml node type tag:yaml.org,2002:int, wanted type(s)" + + " [tag:yaml.org,2002:seq]\n" + + " | type_name: bar\n" + + " | .....^"), + UNSUPPORTED_CONFIG_TAG( + "unsupported: test", + "ERROR: :1:1: Unknown config tag: unsupported\n" + + " | unsupported: test\n" + + " | ^"), + UNSUPPORTED_EXTENSION_TAG( + "extensions:\n" // + + " - name: foo\n" // + + " unsupported: test", + "ERROR: :3:5: Unsupported extension tag: unsupported\n" + + " | unsupported: test\n" + + " | ....^"), + UNSUPPORTED_TYPE_DECL_TAG( + "variables:\n" + + "- name: foo\n" + + " type:\n" + + " type_name: bar\n" + + " unsupported: hello", + "ERROR: :5:6: Unsupported type decl tag: unsupported\n" + + " | unsupported: hello\n" + + " | .....^"), + MISSING_VARIABLE_PROPERTIES( + "variables:\n - illegal: 2", + "ERROR: :2:4: Unsupported variable tag: illegal\n" + + " | - illegal: 2\n" + + " | ...^\n" + + "ERROR: :2:4: Missing required attribute(s): name, type\n" + + " | - illegal: 2\n" + + " | ...^"), + MISSING_OVERLOAD_RETURN( + "functions:\n" + + " - name: 'missing_return'\n" + + " overloads:\n" + + " - id: 'zero_arity'\n", + "ERROR: :4:9: Missing required attribute(s): return\n" + + " | - id: 'zero_arity'\n" + + " | ........^"), + MISSING_FUNCTION_NAME( + "functions:\n" + + " - overloads:\n" + + " - id: 'foo'\n" + + " return:\n" + + " type_name: 'string'\n", + "ERROR: :2:5: Missing required attribute(s): name\n" + + " | - overloads:\n" + + " | ....^"), + MISSING_OVERLOAD( + "functions:\n" + " - name: 'missing_overload'\n", + "ERROR: :2:5: Missing required attribute(s): overloads\n" + + " | - name: 'missing_overload'\n" + + " | ....^"), + MISSING_EXTENSION_NAME( + "extensions:\n" + "- version: 0", + "ERROR: :2:3: Missing required attribute(s): name\n" + + " | - version: 0\n" + + " | ..^"), + ; + + private final String yamlConfig; + private final String expectedErrorMessage; + + ConfigParseErrorTestcase(String yamlConfig, String expectedErrorMessage) { + this.yamlConfig = yamlConfig; + this.expectedErrorMessage = expectedErrorMessage; + } + } +} From 99b52f5145b761e63a4b387e616eda0ffc6cf34f Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Tue, 2 Jul 2024 10:38:43 -0700 Subject: [PATCH 139/486] Create a separate interface for validating required fields in a builder PiperOrigin-RevId: 648767398 --- .../src/main/java/dev/cel/policy/BUILD.bazel | 13 +++++ .../java/dev/cel/policy/CelPolicyConfig.java | 56 ++++++++----------- .../dev/cel/policy/RequiredFieldsChecker.java | 49 ++++++++++++++++ 3 files changed, 85 insertions(+), 33 deletions(-) create mode 100644 policy/src/main/java/dev/cel/policy/RequiredFieldsChecker.java diff --git a/policy/src/main/java/dev/cel/policy/BUILD.bazel b/policy/src/main/java/dev/cel/policy/BUILD.bazel index 5fc24e33d..85b0f4d38 100644 --- a/policy/src/main/java/dev/cel/policy/BUILD.bazel +++ b/policy/src/main/java/dev/cel/policy/BUILD.bazel @@ -38,6 +38,7 @@ java_library( tags = [ ], deps = [ + ":required_fields_checker", ":source", "//:auto_value", "@maven//:com_google_errorprone_error_prone_annotations", @@ -89,6 +90,18 @@ java_library( ], ) +java_library( + name = "required_fields_checker", + srcs = [ + "RequiredFieldsChecker.java", + ], + visibility = ["//visibility:private"], + deps = [ + "//:auto_value", + "@maven//:com_google_guava_guava", + ], +) + java_library( name = "parser_context", srcs = [ diff --git a/policy/src/main/java/dev/cel/policy/CelPolicyConfig.java b/policy/src/main/java/dev/cel/policy/CelPolicyConfig.java index 4d15c4d8b..c9b63bf3b 100644 --- a/policy/src/main/java/dev/cel/policy/CelPolicyConfig.java +++ b/policy/src/main/java/dev/cel/policy/CelPolicyConfig.java @@ -15,15 +15,12 @@ package dev.cel.policy; import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.collect.ImmutableList.toImmutableList; -import static java.util.Arrays.stream; import com.google.auto.value.AutoValue; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.errorprone.annotations.CheckReturnValue; -import java.util.AbstractMap; import java.util.Arrays; import java.util.Optional; @@ -108,7 +105,7 @@ public abstract static class VariableDecl { /** Builder for {@link VariableDecl}. */ @AutoValue.Builder - public abstract static class Builder { + public abstract static class Builder implements RequiredFieldsChecker { abstract Optional name(); @@ -118,10 +115,10 @@ public abstract static class Builder { public abstract Builder setType(TypeDecl typeDecl); - ImmutableList getMissingRequiredFieldNames() { - return getMissingRequiredFields( - new AbstractMap.SimpleEntry<>("name", name()), - new AbstractMap.SimpleEntry<>("type", type())); + @Override + public ImmutableList requiredFields() { + return ImmutableList.of( + RequiredField.of("name", this::name), RequiredField.of("type", this::type)); } /** Builds a new instance of {@link VariableDecl}. */ @@ -148,7 +145,7 @@ public abstract static class FunctionDecl { /** Builder for {@link FunctionDecl}. */ @AutoValue.Builder - public abstract static class Builder { + public abstract static class Builder implements RequiredFieldsChecker { abstract Optional name(); @@ -158,10 +155,10 @@ public abstract static class Builder { public abstract Builder setOverloads(ImmutableSet overloads); - ImmutableList getMissingRequiredFieldNames() { - return getMissingRequiredFields( - new AbstractMap.SimpleEntry<>("name", name()), - new AbstractMap.SimpleEntry<>("overloads", overloads())); + @Override + public ImmutableList requiredFields() { + return ImmutableList.of( + RequiredField.of("name", this::name), RequiredField.of("overloads", this::overloads)); } /** Builds a new instance of {@link FunctionDecl}. */ @@ -200,7 +197,7 @@ public abstract static class OverloadDecl { /** Builder for {@link OverloadDecl}. */ @AutoValue.Builder - public abstract static class Builder { + public abstract static class Builder implements RequiredFieldsChecker { abstract Optional id(); @@ -228,10 +225,10 @@ public Builder addArguments(TypeDecl... args) { public abstract Builder setReturnType(TypeDecl returnType); - ImmutableList getMissingRequiredFieldNames() { - return getMissingRequiredFields( - new AbstractMap.SimpleEntry<>("id", id()), - new AbstractMap.SimpleEntry<>("return", returnType())); + @Override + public ImmutableList requiredFields() { + return ImmutableList.of( + RequiredField.of("id", this::id), RequiredField.of("return", this::returnType)); } /** Builds a new instance of {@link OverloadDecl}. */ @@ -259,7 +256,7 @@ public abstract static class TypeDecl { /** Builder for {@link TypeDecl}. */ @AutoValue.Builder - public abstract static class Builder { + public abstract static class Builder implements RequiredFieldsChecker { abstract Optional name(); @@ -283,8 +280,9 @@ public Builder addParams(Iterable params) { public abstract Builder setIsTypeParam(boolean isTypeParam); - ImmutableList getMissingRequiredFieldNames() { - return getMissingRequiredFields(new AbstractMap.SimpleEntry<>("type_name", name())); + @Override + public ImmutableList requiredFields() { + return ImmutableList.of(RequiredField.of("type_name", this::name)); } @CheckReturnValue @@ -319,7 +317,7 @@ public abstract static class ExtensionConfig { /** Builder for {@link ExtensionConfig}. */ @AutoValue.Builder - public abstract static class Builder { + public abstract static class Builder implements RequiredFieldsChecker { abstract Optional name(); @@ -329,8 +327,9 @@ public abstract static class Builder { public abstract Builder setVersion(Integer version); - ImmutableList getMissingRequiredFieldNames() { - return getMissingRequiredFields(new AbstractMap.SimpleEntry<>("name", name())); + @Override + public ImmutableList requiredFields() { + return ImmutableList.of(RequiredField.of("name", this::name)); } /** Builds a new instance of {@link ExtensionConfig}. */ @@ -352,13 +351,4 @@ public static ExtensionConfig of(String name, int version) { return newBuilder().setName(name).setVersion(version).build(); } } - - @SafeVarargs - private static ImmutableList getMissingRequiredFields( - AbstractMap.SimpleEntry>... requiredFields) { - return stream(requiredFields) - .filter(entry -> !entry.getValue().isPresent()) - .map(AbstractMap.SimpleEntry::getKey) - .collect(toImmutableList()); - } } diff --git a/policy/src/main/java/dev/cel/policy/RequiredFieldsChecker.java b/policy/src/main/java/dev/cel/policy/RequiredFieldsChecker.java new file mode 100644 index 000000000..e46b2822a --- /dev/null +++ b/policy/src/main/java/dev/cel/policy/RequiredFieldsChecker.java @@ -0,0 +1,49 @@ +// Copyright 2024 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.policy; + +import static com.google.common.collect.ImmutableList.toImmutableList; + +import com.google.auto.value.AutoValue; +import com.google.common.collect.ImmutableList; +import java.util.Optional; +import java.util.function.Supplier; + +/** + * Interface to be implemented on a builder that can be used to verify all required fields being + * set. + */ +interface RequiredFieldsChecker { + + ImmutableList requiredFields(); + + default ImmutableList getMissingRequiredFieldNames() { + return requiredFields().stream() + .filter(entry -> !entry.fieldValue().get().isPresent()) + .map(RequiredField::displayName) + .collect(toImmutableList()); + } + + @AutoValue + abstract class RequiredField { + abstract String displayName(); + + abstract Supplier> fieldValue(); + + static RequiredField of(String displayName, Supplier> fieldValue) { + return new AutoValue_RequiredFieldsChecker_RequiredField(displayName, fieldValue); + } + } +} From e0f0225988fadb99962d679de58db9826f5c9d25 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Tue, 2 Jul 2024 11:32:29 -0700 Subject: [PATCH 140/486] Add the capability to extend CEL environment from parsed config PiperOrigin-RevId: 648788074 --- .../src/main/java/dev/cel/bundle/CelImpl.java | 5 + .../main/java/dev/cel/checker/CelChecker.java | 4 + .../dev/cel/checker/CelCheckerLegacyImpl.java | 9 + .../java/dev/cel/common/types/SimpleType.java | 20 ++ .../dev/cel/compiler/CelCompilerImpl.java | 5 + .../src/main/java/dev/cel/policy/BUILD.bazel | 8 + .../java/dev/cel/policy/CelPolicyConfig.java | 175 +++++++++++++++++- .../src/test/java/dev/cel/policy/BUILD.bazel | 3 + .../policy/CelPolicyYamlConfigParserTest.java | 97 ++++++++++ 9 files changed, 317 insertions(+), 9 deletions(-) diff --git a/bundle/src/main/java/dev/cel/bundle/CelImpl.java b/bundle/src/main/java/dev/cel/bundle/CelImpl.java index ad062d113..317eeb49c 100644 --- a/bundle/src/main/java/dev/cel/bundle/CelImpl.java +++ b/bundle/src/main/java/dev/cel/bundle/CelImpl.java @@ -87,6 +87,11 @@ public CelValidationResult check(CelAbstractSyntaxTree ast) { return compiler.get().check(ast); } + @Override + public CelTypeProvider getTypeProvider() { + return compiler.get().getTypeProvider(); + } + @Override public CelRuntime.Program createProgram(CelAbstractSyntaxTree ast) throws CelEvaluationException { return runtime.get().createProgram(ast); diff --git a/checker/src/main/java/dev/cel/checker/CelChecker.java b/checker/src/main/java/dev/cel/checker/CelChecker.java index 4022212cb..077850be1 100644 --- a/checker/src/main/java/dev/cel/checker/CelChecker.java +++ b/checker/src/main/java/dev/cel/checker/CelChecker.java @@ -17,6 +17,7 @@ import com.google.errorprone.annotations.Immutable; import dev.cel.common.CelAbstractSyntaxTree; import dev.cel.common.CelValidationResult; +import dev.cel.common.types.CelTypeProvider; /** Public interface for type-checking parsed CEL expressions. */ @Immutable @@ -29,5 +30,8 @@ public interface CelChecker { */ CelValidationResult check(CelAbstractSyntaxTree ast); + /** Returns the underlying type provider. */ + CelTypeProvider getTypeProvider(); + CelCheckerBuilder toCheckerBuilder(); } diff --git a/checker/src/main/java/dev/cel/checker/CelCheckerLegacyImpl.java b/checker/src/main/java/dev/cel/checker/CelCheckerLegacyImpl.java index 950c919e3..a177b259d 100644 --- a/checker/src/main/java/dev/cel/checker/CelCheckerLegacyImpl.java +++ b/checker/src/main/java/dev/cel/checker/CelCheckerLegacyImpl.java @@ -75,6 +75,7 @@ public final class CelCheckerLegacyImpl implements CelChecker, EnvVisitable { @SuppressWarnings("Immutable") private final TypeProvider typeProvider; + private final CelTypeProvider celTypeProvider; private final boolean standardEnvironmentEnabled; // Builder is mutable by design. APIs must make defensive copies in and out of this class. @@ -98,6 +99,11 @@ public CelValidationResult check(CelAbstractSyntaxTree ast) { return new CelValidationResult(checkedAst, ImmutableList.of()); } + @Override + public CelTypeProvider getTypeProvider() { + return this.celTypeProvider; + } + @Override public CelCheckerBuilder toCheckerBuilder() { return new Builder(checkerBuilder); @@ -422,6 +428,7 @@ public CelCheckerLegacyImpl build() { functionDeclarations.build(), Optional.fromNullable(expectedResultType), legacyProvider, + messageTypeProvider, standardEnvironmentEnabled, this); } @@ -469,6 +476,7 @@ private CelCheckerLegacyImpl( ImmutableSet functionDeclarations, Optional expectedResultType, TypeProvider typeProvider, + CelTypeProvider celTypeProvider, boolean standardEnvironmentEnabled, Builder checkerBuilder) { this.celOptions = celOptions; @@ -477,6 +485,7 @@ private CelCheckerLegacyImpl( this.functionDeclarations = functionDeclarations; this.expectedResultType = expectedResultType; this.typeProvider = typeProvider; + this.celTypeProvider = celTypeProvider; this.standardEnvironmentEnabled = standardEnvironmentEnabled; this.checkerBuilder = new Builder(checkerBuilder); } diff --git a/common/src/main/java/dev/cel/common/types/SimpleType.java b/common/src/main/java/dev/cel/common/types/SimpleType.java index 378c669f1..cbf02e9c6 100644 --- a/common/src/main/java/dev/cel/common/types/SimpleType.java +++ b/common/src/main/java/dev/cel/common/types/SimpleType.java @@ -15,8 +15,10 @@ package dev.cel.common.types; import com.google.auto.value.AutoValue; +import com.google.common.collect.ImmutableMap; import com.google.errorprone.annotations.CheckReturnValue; import com.google.errorprone.annotations.Immutable; +import java.util.Optional; /** Simple types represent scalar, dynamic, and error values. */ @AutoValue @@ -42,6 +44,19 @@ public abstract class SimpleType extends CelType { public static final CelType TIMESTAMP = create(CelKind.TIMESTAMP, "google.protobuf.Timestamp"); public static final CelType UINT = create(CelKind.UINT, "uint"); + private static final ImmutableMap TYPE_MAP = + ImmutableMap.of( + DYN.name(), DYN, + BOOL.name(), BOOL, + BYTES.name(), BYTES, + DOUBLE.name(), DOUBLE, + DURATION.name(), DURATION, + INT.name(), INT, + NULL_TYPE.name(), NULL_TYPE, + STRING.name(), STRING, + TIMESTAMP.name(), TIMESTAMP, + UINT.name(), UINT); + @Override public abstract CelKind kind(); @@ -56,6 +71,11 @@ public boolean isAssignableFrom(CelType other) { || (other instanceof NullableType && other.isAssignableFrom(this)); } + /** Returns a matching SimpleType by its name if one exists. */ + public static Optional findByName(String typeName) { + return Optional.ofNullable(TYPE_MAP.get(typeName)); + } + private static CelType create(CelKind kind, String name) { return new AutoValue_SimpleType(kind, name); } diff --git a/compiler/src/main/java/dev/cel/compiler/CelCompilerImpl.java b/compiler/src/main/java/dev/cel/compiler/CelCompilerImpl.java index ac81f5d0c..13da89f2f 100644 --- a/compiler/src/main/java/dev/cel/compiler/CelCompilerImpl.java +++ b/compiler/src/main/java/dev/cel/compiler/CelCompilerImpl.java @@ -74,6 +74,11 @@ public CelValidationResult check(CelAbstractSyntaxTree ast) { return checker.check(ast); } + @Override + public CelTypeProvider getTypeProvider() { + return checker.getTypeProvider(); + } + @Override public void accept(EnvVisitor envVisitor) { if (checker instanceof EnvVisitable) { diff --git a/policy/src/main/java/dev/cel/policy/BUILD.bazel b/policy/src/main/java/dev/cel/policy/BUILD.bazel index 85b0f4d38..03fc041b6 100644 --- a/policy/src/main/java/dev/cel/policy/BUILD.bazel +++ b/policy/src/main/java/dev/cel/policy/BUILD.bazel @@ -40,7 +40,15 @@ java_library( deps = [ ":required_fields_checker", ":source", + ":validation_exception", "//:auto_value", + "//bundle:cel", + "//common:compiler_common", + "//common:options", + "//common/types", + "//common/types:type_providers", + "//extensions", + "//extensions:optional_library", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", ], diff --git a/policy/src/main/java/dev/cel/policy/CelPolicyConfig.java b/policy/src/main/java/dev/cel/policy/CelPolicyConfig.java index c9b63bf3b..13f2bad66 100644 --- a/policy/src/main/java/dev/cel/policy/CelPolicyConfig.java +++ b/policy/src/main/java/dev/cel/policy/CelPolicyConfig.java @@ -15,12 +15,29 @@ package dev.cel.policy; import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; +import static com.google.common.collect.ImmutableList.toImmutableList; import com.google.auto.value.AutoValue; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.errorprone.annotations.CheckReturnValue; +import dev.cel.bundle.Cel; +import dev.cel.bundle.CelBuilder; +import dev.cel.common.CelFunctionDecl; +import dev.cel.common.CelOptions; +import dev.cel.common.CelOverloadDecl; +import dev.cel.common.CelVarDecl; +import dev.cel.common.types.CelType; +import dev.cel.common.types.CelTypeProvider; +import dev.cel.common.types.ListType; +import dev.cel.common.types.MapType; +import dev.cel.common.types.OptionalType; +import dev.cel.common.types.SimpleType; +import dev.cel.common.types.TypeParamType; +import dev.cel.extensions.CelExtensions; +import dev.cel.extensions.CelOptionalLibrary; import java.util.Arrays; import java.util.Optional; @@ -93,6 +110,66 @@ public static Builder newBuilder() { .setFunctions(ImmutableSet.of()); } + /** Extends the provided {@code cel} environment with this configuration. */ + public Cel extend(Cel cel, CelOptions celOptions) throws CelPolicyValidationException { + try { + CelTypeProvider celTypeProvider = cel.getTypeProvider(); + CelBuilder celBuilder = + cel.toCelBuilder() + .setTypeProvider(celTypeProvider) + .setContainer(container()) + .addVarDeclarations( + variables().stream() + .map(v -> v.toCelVarDecl(celTypeProvider)) + .collect(toImmutableList())) + .addFunctionDeclarations( + functions().stream() + .map(f -> f.toCelFunctionDecl(celTypeProvider)) + .collect(toImmutableList())); + + addAllExtensions(celBuilder, celOptions); + + return celBuilder.build(); + } catch (RuntimeException e) { + throw new CelPolicyValidationException(e.getMessage(), e); + } + } + + private void addAllExtensions(CelBuilder celBuilder, CelOptions celOptions) { + for (ExtensionConfig extensionConfig : extensions()) { + switch (extensionConfig.name()) { + case "bindings": + celBuilder.addCompilerLibraries(CelExtensions.bindings()); + break; + case "encoders": + celBuilder.addCompilerLibraries(CelExtensions.encoders()); + celBuilder.addRuntimeLibraries(CelExtensions.encoders()); + break; + case "math": + celBuilder.addCompilerLibraries(CelExtensions.math(celOptions)); + celBuilder.addRuntimeLibraries(CelExtensions.math(celOptions)); + break; + case "optional": + celBuilder.addCompilerLibraries(CelOptionalLibrary.INSTANCE); + celBuilder.addRuntimeLibraries(CelOptionalLibrary.INSTANCE); + break; + case "protos": + celBuilder.addCompilerLibraries(CelExtensions.protos()); + break; + case "strings": + celBuilder.addCompilerLibraries(CelExtensions.strings()); + celBuilder.addRuntimeLibraries(CelExtensions.strings()); + break; + case "sets": + celBuilder.addCompilerLibraries(CelExtensions.sets()); + celBuilder.addRuntimeLibraries(CelExtensions.sets()); + break; + default: + throw new IllegalArgumentException("Unrecognized extension: " + extensionConfig.name()); + } + } + } + /** Represents a policy variable declaration. */ @AutoValue public abstract static class VariableDecl { @@ -107,9 +184,9 @@ public abstract static class VariableDecl { @AutoValue.Builder public abstract static class Builder implements RequiredFieldsChecker { - abstract Optional name(); + public abstract Optional name(); - abstract Optional type(); + public abstract Optional type(); public abstract Builder setName(String name); @@ -133,6 +210,11 @@ public static Builder newBuilder() { public static VariableDecl create(String name, TypeDecl type) { return newBuilder().setName(name).setType(type).build(); } + + /** Converts this policy variable declaration into a {@link CelVarDecl}. */ + public CelVarDecl toCelVarDecl(CelTypeProvider celTypeProvider) { + return CelVarDecl.newVarDeclaration(name(), type().toCelType(celTypeProvider)); + } } /** Represents a policy function declaration. */ @@ -147,9 +229,9 @@ public abstract static class FunctionDecl { @AutoValue.Builder public abstract static class Builder implements RequiredFieldsChecker { - abstract Optional name(); + public abstract Optional name(); - abstract Optional> overloads(); + public abstract Optional> overloads(); public abstract Builder setName(String name); @@ -174,6 +256,15 @@ public static Builder newBuilder() { public static FunctionDecl create(String name, ImmutableSet overloads) { return newBuilder().setName(name).setOverloads(overloads).build(); } + + /** Converts this policy function declaration into a {@link CelFunctionDecl}. */ + public CelFunctionDecl toCelFunctionDecl(CelTypeProvider celTypeProvider) { + return CelFunctionDecl.newFunctionDeclaration( + name(), + overloads().stream() + .map(o -> o.toCelOverloadDecl(celTypeProvider)) + .collect(toImmutableList())); + } } /** Represents an overload declaraion on a policy function. */ @@ -199,9 +290,9 @@ public abstract static class OverloadDecl { @AutoValue.Builder public abstract static class Builder implements RequiredFieldsChecker { - abstract Optional id(); + public abstract Optional id(); - abstract Optional returnType(); + public abstract Optional returnType(); public abstract Builder setId(String overloadId); @@ -240,6 +331,28 @@ public ImmutableList requiredFields() { public static Builder newBuilder() { return new AutoValue_CelPolicyConfig_OverloadDecl.Builder().setArguments(ImmutableList.of()); } + + /** Converts this policy function overload into a {@link CelOverloadDecl}. */ + public CelOverloadDecl toCelOverloadDecl(CelTypeProvider celTypeProvider) { + CelOverloadDecl.Builder builder = + CelOverloadDecl.newBuilder() + .setIsInstanceFunction(false) + .setOverloadId(id()) + .setResultType(returnType().toCelType(celTypeProvider)); + + target() + .ifPresent( + t -> + builder + .setIsInstanceFunction(true) + .addParameterTypes(t.toCelType(celTypeProvider))); + + for (TypeDecl type : arguments()) { + builder.addParameterTypes(type.toCelType(celTypeProvider)); + } + + return builder.build(); + } } /** @@ -258,7 +371,7 @@ public abstract static class TypeDecl { @AutoValue.Builder public abstract static class Builder implements RequiredFieldsChecker { - abstract Optional name(); + public abstract Optional name(); public abstract Builder setName(String name); @@ -297,6 +410,50 @@ public static TypeDecl create(String name) { public static Builder newBuilder() { return new AutoValue_CelPolicyConfig_TypeDecl.Builder().setIsTypeParam(false); } + + /** Converts this type declaration into a {@link CelType}. */ + public CelType toCelType(CelTypeProvider celTypeProvider) { + switch (name()) { + case "list": + if (params().size() != 1) { + throw new IllegalArgumentException( + "List type has unexpected param count: " + params().size()); + } + + CelType elementType = params().get(0).toCelType(celTypeProvider); + return ListType.create(elementType); + case "map": + if (params().size() != 2) { + throw new IllegalArgumentException( + "Map type has unexpected param count: " + params().size()); + } + + CelType keyType = params().get(0).toCelType(celTypeProvider); + CelType valueType = params().get(1).toCelType(celTypeProvider); + return MapType.create(keyType, valueType); + default: + if (isTypeParam()) { + return TypeParamType.create(name()); + } + + CelType simpleType = SimpleType.findByName(name()).orElse(null); + if (simpleType != null) { + return simpleType; + } + + if (name().equals(OptionalType.NAME)) { + checkState( + params().size() == 1, + "Optional type must have exactly 1 parameter. Found %s", + params().size()); + return OptionalType.create(params().get(0).toCelType(celTypeProvider)); + } + + return celTypeProvider + .findType(name()) + .orElseThrow(() -> new IllegalArgumentException("Undefined type name: " + name())); + } + } } /** @@ -319,9 +476,9 @@ public abstract static class ExtensionConfig { @AutoValue.Builder public abstract static class Builder implements RequiredFieldsChecker { - abstract Optional name(); + public abstract Optional name(); - abstract Optional version(); + public abstract Optional version(); public abstract Builder setName(String name); diff --git a/policy/src/test/java/dev/cel/policy/BUILD.bazel b/policy/src/test/java/dev/cel/policy/BUILD.bazel index 951b45f6a..b4844833a 100644 --- a/policy/src/test/java/dev/cel/policy/BUILD.bazel +++ b/policy/src/test/java/dev/cel/policy/BUILD.bazel @@ -8,12 +8,15 @@ java_library( srcs = glob(["*.java"]), deps = [ "//:java_truth", + "//bundle:cel", + "//common:options", "//common/internal", "//policy:config", "//policy:config_parser", "//policy:source", "//policy:validation_exception", "//policy:yaml_config_parser", + "@maven//:com_google_api_grpc_proto_google_common_protos", "@maven//:com_google_guava_guava", "@maven//:com_google_testparameterinjector_test_parameter_injector", "@maven//:junit_junit", diff --git a/policy/src/test/java/dev/cel/policy/CelPolicyYamlConfigParserTest.java b/policy/src/test/java/dev/cel/policy/CelPolicyYamlConfigParserTest.java index 020d9f689..235126270 100644 --- a/policy/src/test/java/dev/cel/policy/CelPolicyYamlConfigParserTest.java +++ b/policy/src/test/java/dev/cel/policy/CelPolicyYamlConfigParserTest.java @@ -18,8 +18,12 @@ import static org.junit.Assert.assertThrows; import com.google.common.collect.ImmutableSet; +import com.google.rpc.context.AttributeContext; import com.google.testing.junit.testparameterinjector.TestParameter; import com.google.testing.junit.testparameterinjector.TestParameterInjector; +import dev.cel.bundle.Cel; +import dev.cel.bundle.CelFactory; +import dev.cel.common.CelOptions; import dev.cel.policy.CelPolicyConfig.ExtensionConfig; import dev.cel.policy.CelPolicyConfig.FunctionDecl; import dev.cel.policy.CelPolicyConfig.OverloadDecl; @@ -31,6 +35,11 @@ @RunWith(TestParameterInjector.class) public final class CelPolicyYamlConfigParserTest { + private static final Cel CEL_WITH_MESSAGE_TYPES = + CelFactory.standardCelBuilder() + .addMessageTypes(AttributeContext.Request.getDescriptor()) + .build(); + private static final CelPolicyConfigParser POLICY_CONFIG_PARSER = CelPolicyYamlConfigParser.newInstance(); @@ -79,6 +88,7 @@ public void config_setExtensions() throws Exception { ExtensionConfig.of("sets"), ExtensionConfig.of("strings", 1))) .build()); + assertThat(policyConfig.extend(CEL_WITH_MESSAGE_TYPES, CelOptions.DEFAULT)).isNotNull(); } @Test @@ -172,6 +182,7 @@ public void config_setFunctions() throws Exception { .build()) .build())))) .build()); + assertThat(policyConfig.extend(CEL_WITH_MESSAGE_TYPES, CelOptions.DEFAULT)).isNotNull(); } @Test @@ -227,6 +238,7 @@ public void config_setMapVariable() throws Exception { .addParams(TypeDecl.create("string"), TypeDecl.create("dyn")) .build()))) .build()); + assertThat(policyConfig.extend(CEL_WITH_MESSAGE_TYPES, CelOptions.DEFAULT)).isNotNull(); } @Test @@ -249,6 +261,7 @@ public void config_setMessageVariable() throws Exception { "request", TypeDecl.create("google.rpc.context.AttributeContext.Request")))) .build()); + assertThat(policyConfig.extend(CEL_WITH_MESSAGE_TYPES, CelOptions.DEFAULT)).isNotNull(); } @Test @@ -260,6 +273,18 @@ public void config_parseErrors(@TestParameter ConfigParseErrorTestcase testCase) assertThat(e).hasMessageThat().isEqualTo(testCase.expectedErrorMessage); } + @Test + public void config_extendErrors(@TestParameter ConfigExtendErrorTestCase testCase) + throws Exception { + CelPolicyConfig policyConfig = POLICY_CONFIG_PARSER.parse(testCase.yamlConfig); + + CelPolicyValidationException e = + assertThrows( + CelPolicyValidationException.class, + () -> policyConfig.extend(CEL_WITH_MESSAGE_TYPES, CelOptions.DEFAULT)); + assertThat(e).hasMessageThat().isEqualTo(testCase.expectedErrorMessage); + } + // Note: dangling comments in expressions below is to retain the newlines by preventing auto // formatter from compressing them in a single line. private enum ConfigParseErrorTestcase { @@ -440,4 +465,76 @@ private enum ConfigParseErrorTestcase { this.expectedErrorMessage = expectedErrorMessage; } } + + private enum ConfigExtendErrorTestCase { + BAD_EXTENSION("extensions:\n" + " - name: 'bad_name'", "Unrecognized extension: bad_name"), + BAD_TYPE( + "variables:\n" + "- name: 'bad_type'\n" + " type:\n" + " type_name: 'strings'", + "Undefined type name: strings"), + BAD_LIST( + "variables:\n" + " - name: 'bad_list'\n" + " type:\n" + " type_name: 'list'", + "List type has unexpected param count: 0"), + BAD_MAP( + "variables:\n" + + " - name: 'bad_map'\n" + + " type:\n" + + " type_name: 'map'\n" + + " params:\n" + + " - type_name: 'string'", + "Map type has unexpected param count: 1"), + BAD_LIST_TYPE_PARAM( + "variables:\n" + + " - name: 'bad_list_type_param'\n" + + " type:\n" + + " type_name: 'list'\n" + + " params:\n" + + " - type_name: 'number'", + "Undefined type name: number"), + BAD_MAP_TYPE_PARAM( + "variables:\n" + + " - name: 'bad_map_type_param'\n" + + " type:\n" + + " type_name: 'map'\n" + + " params:\n" + + " - type_name: 'string'\n" + + " - type_name: 'optional'", + "Undefined type name: optional"), + BAD_RETURN( + "functions:\n" + + " - name: 'bad_return'\n" + + " overloads:\n" + + " - id: 'zero_arity'\n" + + " return:\n" + + " type_name: 'mystery'", + "Undefined type name: mystery"), + BAD_OVERLOAD_TARGET( + "functions:\n" + + " - name: 'bad_target'\n" + + " overloads:\n" + + " - id: 'unary_member'\n" + + " target:\n" + + " type_name: 'unknown'\n" + + " return:\n" + + " type_name: 'null_type'", + "Undefined type name: unknown"), + BAD_OVERLOAD_ARG( + "functions:\n" + + " - name: 'bad_arg'\n" + + " overloads:\n" + + " - id: 'unary_global'\n" + + " args:\n" + + " - type_name: 'unknown'\n" + + " return:\n" + + " type_name: 'null_type'", + "Undefined type name: unknown"), + ; + + private final String yamlConfig; + private final String expectedErrorMessage; + + ConfigExtendErrorTestCase(String yamlConfig, String expectedErrorMessage) { + this.yamlConfig = yamlConfig; + this.expectedErrorMessage = expectedErrorMessage; + } + } } From b9fe54ded9d718019824852e77d0796884c716f5 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Tue, 2 Jul 2024 13:20:26 -0700 Subject: [PATCH 141/486] Add YAML policy test cases PiperOrigin-RevId: 648822357 --- policy/src/test/resources/BUILD.bazel | 14 +++ policy/src/test/resources/errors/config.yaml | 52 ++++++++ policy/src/test/resources/errors/policy.yaml | 34 +++++ .../test/resources/nested_rule/config.yaml | 22 ++++ .../test/resources/nested_rule/policy.yaml | 38 ++++++ .../src/test/resources/nested_rule/tests.yaml | 38 ++++++ .../resources/required_labels/config.yaml | 32 +++++ .../resources/required_labels/policy.yaml | 32 +++++ .../test/resources/required_labels/tests.yaml | 79 ++++++++++++ .../restricted_destinations/config.yaml | 52 ++++++++ .../restricted_destinations/policy.yaml | 42 +++++++ .../restricted_destinations/tests.yaml | 118 ++++++++++++++++++ 12 files changed, 553 insertions(+) create mode 100644 policy/src/test/resources/BUILD.bazel create mode 100644 policy/src/test/resources/errors/config.yaml create mode 100644 policy/src/test/resources/errors/policy.yaml create mode 100644 policy/src/test/resources/nested_rule/config.yaml create mode 100644 policy/src/test/resources/nested_rule/policy.yaml create mode 100644 policy/src/test/resources/nested_rule/tests.yaml create mode 100644 policy/src/test/resources/required_labels/config.yaml create mode 100644 policy/src/test/resources/required_labels/policy.yaml create mode 100644 policy/src/test/resources/required_labels/tests.yaml create mode 100644 policy/src/test/resources/restricted_destinations/config.yaml create mode 100644 policy/src/test/resources/restricted_destinations/policy.yaml create mode 100644 policy/src/test/resources/restricted_destinations/tests.yaml diff --git a/policy/src/test/resources/BUILD.bazel b/policy/src/test/resources/BUILD.bazel new file mode 100644 index 000000000..71285b61a --- /dev/null +++ b/policy/src/test/resources/BUILD.bazel @@ -0,0 +1,14 @@ +package( + default_applicable_licenses = [ + "//:license", + ], + default_testonly = True, + default_visibility = [ + "//policy:__subpackages__", + ], +) + +filegroup( + name = "policy_yaml_files", + srcs = glob(["**/*.yaml"]), +) diff --git a/policy/src/test/resources/errors/config.yaml b/policy/src/test/resources/errors/config.yaml new file mode 100644 index 000000000..b9c8f9750 --- /dev/null +++ b/policy/src/test/resources/errors/config.yaml @@ -0,0 +1,52 @@ +# Copyright 2024 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. + +name: "labels" +extensions: + - name: "sets" +variables: + - name: "destination.ip" + type: + type_name: "string" + - name: "origin.ip" + type: + type_name: "string" + - name: "spec.restricted_destinations" + type: + type_name: "list" + params: + - type_name: "string" + - name: "spec.origin" + type: + type_name: "string" + - name: "request" + type: + type_name: "map" + params: + - type_name: "string" + - type_name: "dyn" + - name: "resource" + type: + type_name: "map" + params: + - type_name: "string" + - type_name: "dyn" +functions: + - name: "locationCode" + overloads: + - id: "locationCode_string" + args: + - type_name: "string" + return: + type_name: "string" diff --git a/policy/src/test/resources/errors/policy.yaml b/policy/src/test/resources/errors/policy.yaml new file mode 100644 index 000000000..338ba3995 --- /dev/null +++ b/policy/src/test/resources/errors/policy.yaml @@ -0,0 +1,34 @@ +# Copyright 2024 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. + +name: "errors" +rule: + variables: + - name: want + expression: spec.labels + - name: missing + expression: variables.want.filter(l, !(lin resource.labels)) + - name: bad_data + expression: "{1:305 2:569}" + - name: invalid + expression: > + resource.labels.filter(l, + l in variables.want && variables.want[l] != resource.labels[l]) + match: + - condition: variables.missing.size() > 0 + output: | + "missing one or more required labels: %s".format(variables.missing]) + - condition: variables.invalid.size() > 0 + output: | + "invalid values provided on one or more labels: %s".format([variables.invalid]) diff --git a/policy/src/test/resources/nested_rule/config.yaml b/policy/src/test/resources/nested_rule/config.yaml new file mode 100644 index 000000000..bfd94b33c --- /dev/null +++ b/policy/src/test/resources/nested_rule/config.yaml @@ -0,0 +1,22 @@ +# Copyright 2024 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. + +name: "nested_rule" +variables: + - name: "resource" + type: + type_name: "map" + params: + - type_name: "string" + - type_name: "dyn" diff --git a/policy/src/test/resources/nested_rule/policy.yaml b/policy/src/test/resources/nested_rule/policy.yaml new file mode 100644 index 000000000..bbbfe0fc1 --- /dev/null +++ b/policy/src/test/resources/nested_rule/policy.yaml @@ -0,0 +1,38 @@ +# Copyright 2024 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. + +name: nested_rule +rule: + variables: + - name: "permitted_regions" + expression: "['us', 'uk', 'es']" + match: + - rule: + id: "banned regions" + description: > + determine whether the resource origin is in the banned + list. If the region is also in the permitted list, the + ban has no effect. + variables: + - name: "banned_regions" + expression: "{'us': false, 'ru': false, 'ir': false}" + match: + - condition: | + resource.origin in variables.banned_regions && + !(resource.origin in variables.permitted_regions) + output: "{'banned': true}" + - condition: resource.origin in variables.permitted_regions + output: "{'banned': false}" + - output: "{'banned': true}" + diff --git a/policy/src/test/resources/nested_rule/tests.yaml b/policy/src/test/resources/nested_rule/tests.yaml new file mode 100644 index 000000000..a9807c376 --- /dev/null +++ b/policy/src/test/resources/nested_rule/tests.yaml @@ -0,0 +1,38 @@ +# Copyright 2024 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. + +description: Nested rule conformance tests +section: + - name: "banned" + tests: + - name: "restricted_origin" + input: + resource: + value: + origin: "ir" + output: "{'banned': true}" + - name: "by_default" + input: + resource: + value: + origin: "de" + output: "{'banned': true}" + - name: "permitted" + tests: + - name: "valid_origin" + input: + resource: + value: + origin: "uk" + output: "{'banned': false}" diff --git a/policy/src/test/resources/required_labels/config.yaml b/policy/src/test/resources/required_labels/config.yaml new file mode 100644 index 000000000..14311d763 --- /dev/null +++ b/policy/src/test/resources/required_labels/config.yaml @@ -0,0 +1,32 @@ +# Copyright 2024 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. + +name: "labels" +extensions: + - name: "bindings" + - name: "strings" + version: 2 +variables: + - name: "spec" + type: + type_name: "map" + params: + - type_name: "string" + - type_name: "dyn" + - name: "resource" + type: + type_name: "map" + params: + - type_name: "string" + - type_name: "dyn" diff --git a/policy/src/test/resources/required_labels/policy.yaml b/policy/src/test/resources/required_labels/policy.yaml new file mode 100644 index 000000000..aca75290f --- /dev/null +++ b/policy/src/test/resources/required_labels/policy.yaml @@ -0,0 +1,32 @@ +# Copyright 2024 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. + +name: "required_labels" +rule: + variables: + - name: want + expression: spec.labels + - name: missing + expression: variables.want.filter(l, !(l in resource.labels)) + - name: invalid + expression: > + resource.labels.filter(l, + l in variables.want && variables.want[l] != resource.labels[l]) + match: + - condition: variables.missing.size() > 0 + output: | + "missing one or more required labels: [\"" + variables.missing.join(',') + "\"]" + - condition: variables.invalid.size() > 0 + output: | + "invalid values provided on one or more labels: [\"" + variables.invalid.join(',') + "\"]" diff --git a/policy/src/test/resources/required_labels/tests.yaml b/policy/src/test/resources/required_labels/tests.yaml new file mode 100644 index 000000000..67681ef46 --- /dev/null +++ b/policy/src/test/resources/required_labels/tests.yaml @@ -0,0 +1,79 @@ +# Copyright 2024 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. + +description: "Required labels conformance tests" +section: + - name: "valid" + tests: + - name: "matching" + input: + spec: + value: + labels: + env: prod + experiment: "group b" + resource: + value: + labels: + env: prod + experiment: "group b" + release: "v0.1.0" + output: "optional.none()" + - name: "missing" + tests: + - name: "env" + input: + spec: + value: + labels: + env: prod + experiment: "group b" + resource: + value: + labels: + experiment: "group b" + release: "v0.1.0" + output: > + "missing one or more required labels: [\"env\"]" + - name: "experiment" + input: + spec: + value: + labels: + env: prod + experiment: "group b" + resource: + value: + labels: + env: staging + release: "v0.1.0" + output: > + "missing one or more required labels: [\"experiment\"]" + - name: "invalid" + tests: + - name: "env" + input: + spec: + value: + labels: + env: prod + experiment: "group b" + resource: + value: + labels: + env: staging + experiment: "group b" + release: "v0.1.0" + output: > + "invalid values provided on one or more labels: [\"env\"]" diff --git a/policy/src/test/resources/restricted_destinations/config.yaml b/policy/src/test/resources/restricted_destinations/config.yaml new file mode 100644 index 000000000..b9c8f9750 --- /dev/null +++ b/policy/src/test/resources/restricted_destinations/config.yaml @@ -0,0 +1,52 @@ +# Copyright 2024 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. + +name: "labels" +extensions: + - name: "sets" +variables: + - name: "destination.ip" + type: + type_name: "string" + - name: "origin.ip" + type: + type_name: "string" + - name: "spec.restricted_destinations" + type: + type_name: "list" + params: + - type_name: "string" + - name: "spec.origin" + type: + type_name: "string" + - name: "request" + type: + type_name: "map" + params: + - type_name: "string" + - type_name: "dyn" + - name: "resource" + type: + type_name: "map" + params: + - type_name: "string" + - type_name: "dyn" +functions: + - name: "locationCode" + overloads: + - id: "locationCode_string" + args: + - type_name: "string" + return: + type_name: "string" diff --git a/policy/src/test/resources/restricted_destinations/policy.yaml b/policy/src/test/resources/restricted_destinations/policy.yaml new file mode 100644 index 000000000..95fb454d7 --- /dev/null +++ b/policy/src/test/resources/restricted_destinations/policy.yaml @@ -0,0 +1,42 @@ +# Copyright 2024 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. + +name: "restricted_destinations" +rule: + variables: + - name: matches_origin_ip + expression: > + locationCode(origin.ip) == spec.origin + - name: has_nationality + expression: > + has(request.auth.claims.nationality) + - name: matches_nationality + expression: > + variables.has_nationality && request.auth.claims.nationality == spec.origin + - name: matches_dest_ip + expression: > + locationCode(destination.ip) in spec.restricted_destinations + - name: matches_dest_label + expression: > + resource.labels.location in spec.restricted_destinations + - name: matches_dest + expression: > + variables.matches_dest_ip || variables.matches_dest_label + match: + - condition: variables.matches_nationality && variables.matches_dest + output: "true" + - condition: > + !variables.has_nationality && variables.matches_origin_ip && variables.matches_dest + output: "true" + - output: "false" diff --git a/policy/src/test/resources/restricted_destinations/tests.yaml b/policy/src/test/resources/restricted_destinations/tests.yaml new file mode 100644 index 000000000..c0feeb202 --- /dev/null +++ b/policy/src/test/resources/restricted_destinations/tests.yaml @@ -0,0 +1,118 @@ +# Copyright 2024 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. + +description: Restricted destinations conformance tests. +section: + - name: "valid" + tests: + - name: "ip_allowed" + input: + "spec.origin": + value: "us" + "spec.restricted_destinations": + value: + - "cu" + - "ir" + - "kp" + - "sd" + - "sy" + "destination.ip": + value: "10.0.0.1" + "origin.ip": + value: "10.0.0.1" + request: + value: + auth: + claims: {} + resource: + value: + name: "/company/acme/secrets/doomsday-device" + labels: + location: "us" + output: "false" # false means unrestricted + - name: "nationality_allowed" + input: + "spec.origin": + value: "us" + "spec.restricted_destinations": + value: + - "cu" + - "ir" + - "kp" + - "sd" + - "sy" + "destination.ip": + value: "10.0.0.1" + request: + value: + auth: + claims: + nationality: "us" + resource: + value: + name: "/company/acme/secrets/doomsday-device" + labels: + location: "us" + output: "false" + - name: "invalid" + tests: + - name: "destination_ip_prohibited" + input: + "spec.origin": + value: "us" + "spec.restricted_destinations": + value: + - "cu" + - "ir" + - "kp" + - "sd" + - "sy" + "destination.ip": + value: "123.123.123.123" + "origin.ip": + value: "10.0.0.1" + request: + value: + auth: + claims: {} + resource: + value: + name: "/company/acme/secrets/doomsday-device" + labels: + location: "us" + output: "true" # true means restricted + - name: "resource_nationality_prohibited" + input: + "spec.origin": + value: "us" + "spec.restricted_destinations": + value: + - "cu" + - "ir" + - "kp" + - "sd" + - "sy" + "destination.ip": + value: "10.0.0.1" + request: + value: + auth: + claims: + nationality: "us" + resource: + value: + name: "/company/acme/secrets/doomsday-device" + labels: + location: "cu" + output: "true" From d63a63bb70f110f93022ee715a654365bb641077 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Tue, 2 Jul 2024 14:06:54 -0700 Subject: [PATCH 142/486] Implement YAML parser for policies PiperOrigin-RevId: 648836979 --- common/BUILD.bazel | 10 +- .../src/main/java/dev/cel/common/BUILD.bazel | 28 +- .../main/java/dev/cel/common/CelSource.java | 6 +- .../src/main/java/dev/cel/common/Source.java | 6 + policy/BUILD.bazel | 16 + .../src/main/java/dev/cel/policy/BUILD.bazel | 58 ++++ .../main/java/dev/cel/policy/CelPolicy.java | 214 +++++++++++++ .../java/dev/cel/policy/CelPolicyConfig.java | 2 +- .../java/dev/cel/policy/CelPolicyParser.java | 87 ++++++ .../cel/policy/CelPolicyParserBuilder.java | 35 +++ .../java/dev/cel/policy/CelPolicySource.java | 10 +- .../cel/policy/CelPolicyYamlConfigParser.java | 10 +- .../dev/cel/policy/CelPolicyYamlParser.java | 288 ++++++++++++++++++ .../java/dev/cel/policy/ParserContext.java | 3 + .../dev/cel/policy/YamlParserContextImpl.java | 6 + .../src/test/java/dev/cel/policy/BUILD.bazel | 6 + .../cel/policy/CelPolicyYamlParserTest.java | 202 ++++++++++++ .../java/dev/cel/policy/PolicyTestHelper.java | 105 +++++++ 18 files changed, 1082 insertions(+), 10 deletions(-) create mode 100644 policy/src/main/java/dev/cel/policy/CelPolicy.java create mode 100644 policy/src/main/java/dev/cel/policy/CelPolicyParser.java create mode 100644 policy/src/main/java/dev/cel/policy/CelPolicyParserBuilder.java create mode 100644 policy/src/main/java/dev/cel/policy/CelPolicyYamlParser.java create mode 100644 policy/src/test/java/dev/cel/policy/CelPolicyYamlParserTest.java create mode 100644 policy/src/test/java/dev/cel/policy/PolicyTestHelper.java diff --git a/common/BUILD.bazel b/common/BUILD.bazel index e3d61aad9..3af0c0c66 100644 --- a/common/BUILD.bazel +++ b/common/BUILD.bazel @@ -5,7 +5,10 @@ package( java_library( name = "common", - exports = ["//common/src/main/java/dev/cel/common"], + exports = [ + "//common/src/main/java/dev/cel/common", + "//common/src/main/java/dev/cel/common:source_location", # TODO: Split callers + ], ) java_library( @@ -65,3 +68,8 @@ java_library( visibility = ["//visibility:public"], exports = ["//common/src/main/java/dev/cel/common:source"], ) + +java_library( + name = "source_location", + exports = ["//common/src/main/java/dev/cel/common:source_location"], +) diff --git a/common/src/main/java/dev/cel/common/BUILD.bazel b/common/src/main/java/dev/cel/common/BUILD.bazel index 8036dafba..82e74bf1d 100644 --- a/common/src/main/java/dev/cel/common/BUILD.bazel +++ b/common/src/main/java/dev/cel/common/BUILD.bazel @@ -14,7 +14,6 @@ COMMON_SOURCES = [ "CelException.java", "CelProtoAbstractSyntaxTree.java", # TODO Split target after migrating callers "CelSource.java", - "CelSourceLocation.java", ] # keep sorted @@ -27,6 +26,12 @@ COMPILER_COMMON_SOURCES = [ "CelVarDecl.java", ] +# keep sorted +SOURCE_SOURCES = [ + "CelSourceHelper.java", + "Source.java", +] + # keep sorted PROTO_V1ALPHA1_AST_SOURCE = [ "CelProtoV1Alpha1AbstractSyntaxTree.java", @@ -40,6 +45,7 @@ java_library( deps = [ ":error_codes", ":source", + ":source_location", "//:auto_value", "//common/annotations", "//common/ast", @@ -64,6 +70,7 @@ java_library( deps = [ ":common", ":source", + ":source_location", "//:auto_value", "//common/annotations", "//common/internal:safe_string_formatter", @@ -179,11 +186,22 @@ java_library( ) java_library( - name = "source", - srcs = [ - "CelSourceHelper.java", - "Source.java", + name = "source_location", + srcs = ["CelSourceLocation.java"], + tags = [ + "alt_dep=//common:source_location", + "avoid_dep", + ], + deps = [ + "//:auto_value", + "@maven//:com_google_errorprone_error_prone_annotations", + "@maven//:com_google_guava_guava", ], +) + +java_library( + name = "source", + srcs = SOURCE_SOURCES, deps = [ "//common/annotations", "//common/internal", diff --git a/common/src/main/java/dev/cel/common/CelSource.java b/common/src/main/java/dev/cel/common/CelSource.java index b8ffe2598..574946fd3 100644 --- a/common/src/main/java/dev/cel/common/CelSource.java +++ b/common/src/main/java/dev/cel/common/CelSource.java @@ -64,6 +64,7 @@ public String getDescription() { return description; } + @Override public ImmutableMap getPositionsMap() { return positions; } @@ -170,7 +171,10 @@ public static Builder newBuilder() { } public static Builder newBuilder(String text) { - CelCodePointArray codePointArray = CelCodePointArray.fromString(text); + return newBuilder(CelCodePointArray.fromString(text)); + } + + public static Builder newBuilder(CelCodePointArray codePointArray) { return new Builder(codePointArray, codePointArray.lineOffsets()); } diff --git a/common/src/main/java/dev/cel/common/Source.java b/common/src/main/java/dev/cel/common/Source.java index 33a9927a6..2d43a9581 100644 --- a/common/src/main/java/dev/cel/common/Source.java +++ b/common/src/main/java/dev/cel/common/Source.java @@ -14,6 +14,7 @@ package dev.cel.common; +import com.google.common.collect.ImmutableMap; import dev.cel.common.annotations.Internal; import dev.cel.common.internal.CelCodePointArray; import java.util.Optional; @@ -36,6 +37,11 @@ public interface Source { */ String getDescription(); + /** + * Gets the map of each parsed node ID (ex: expression ID, policy ID) to their source positions. + */ + ImmutableMap getPositionsMap(); + /** * Get the text from the source text that corresponds to {@code line}. Snippets are split based on * the newline ('\n'). diff --git a/policy/BUILD.bazel b/policy/BUILD.bazel index 487bce068..8e65f4229 100644 --- a/policy/BUILD.bazel +++ b/policy/BUILD.bazel @@ -3,6 +3,11 @@ package( default_visibility = ["//visibility:public"], # TODO: Expose to public ) +java_library( + name = "policy", + exports = ["//policy/src/main/java/dev/cel/policy"], +) + java_library( name = "source", exports = ["//policy/src/main/java/dev/cel/policy:source"], @@ -23,6 +28,17 @@ java_library( exports = ["//policy/src/main/java/dev/cel/policy:config_parser"], ) +java_library( + name = "parser", + exports = ["//policy/src/main/java/dev/cel/policy:parser"], +) + +java_library( + name = "yaml_parser", + visibility = ["//visibility:public"], + exports = ["//policy/src/main/java/dev/cel/policy:yaml_parser"], +) + java_library( name = "yaml_config_parser", visibility = ["//visibility:public"], diff --git a/policy/src/main/java/dev/cel/policy/BUILD.bazel b/policy/src/main/java/dev/cel/policy/BUILD.bazel index 03fc041b6..ed152b9f2 100644 --- a/policy/src/main/java/dev/cel/policy/BUILD.bazel +++ b/policy/src/main/java/dev/cel/policy/BUILD.bazel @@ -5,6 +5,21 @@ package( ], ) +java_library( + name = "policy", + srcs = [ + "CelPolicy.java", + ], + deps = [ + ":required_fields_checker", + ":source", + ":value_string", + "//:auto_value", + "@maven//:com_google_errorprone_error_prone_annotations", + "@maven//:com_google_guava_guava", + ], +) + java_library( name = "source", srcs = [ @@ -67,6 +82,49 @@ java_library( ], ) +java_library( + name = "yaml_parser", + srcs = [ + "CelPolicyYamlParser.java", + ], + deps = [ + ":parser", + ":parser_context", + ":policy", + ":policy_common_internal", + ":policy_parser_builder", + ":source", + ":validation_exception", + ":value_string", + "//common/internal", + "@maven//:com_google_guava_guava", + "@maven//:org_yaml_snakeyaml", + ], +) + +java_library( + name = "parser", + srcs = [ + "CelPolicyParser.java", + ], + deps = [ + ":parser_context", + ":policy", + ":validation_exception", + ], +) + +java_library( + name = "policy_parser_builder", + srcs = [ + "CelPolicyParserBuilder.java", + ], + deps = [ + ":parser", + "@maven//:com_google_errorprone_error_prone_annotations", + ], +) + java_library( name = "yaml_config_parser", srcs = [ diff --git a/policy/src/main/java/dev/cel/policy/CelPolicy.java b/policy/src/main/java/dev/cel/policy/CelPolicy.java new file mode 100644 index 000000000..f64d8cc58 --- /dev/null +++ b/policy/src/main/java/dev/cel/policy/CelPolicy.java @@ -0,0 +1,214 @@ +// Copyright 2024 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.policy; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.auto.value.AutoOneOf; +import com.google.auto.value.AutoValue; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import com.google.errorprone.annotations.CanIgnoreReturnValue; +import java.util.Arrays; +import java.util.Optional; + +/** + * Abstract representation of a policy. It declares a name, rule, and evaluation semantic for a + * given expression graph. + */ +@AutoValue +public abstract class CelPolicy { + + public abstract ValueString name(); + + public abstract Rule rule(); + + public abstract CelPolicySource policySource(); + + /** Creates a new builder to construct a {@link CelPolicy} instance. */ + public static Builder newBuilder() { + return new AutoValue_CelPolicy.Builder() + .setName(ValueString.of(0, "")) + .setRule(Rule.newBuilder().build()); + } + + /** Builder for {@link CelPolicy}. */ + @AutoValue.Builder + public abstract static class Builder { + public abstract CelPolicySource policySource(); + + public abstract Builder setName(ValueString name); + + public abstract Builder setRule(Rule rule); + + public abstract Builder setPolicySource(CelPolicySource policySource); + + public abstract CelPolicy build(); + } + + /** + * Rule declares a rule identifier, description, along with a set of variables and match + * statements. + */ + @AutoValue + public abstract static class Rule { + + public abstract Optional id(); + + public abstract Optional description(); + + public abstract ImmutableSet variables(); + + public abstract ImmutableSet matches(); + + /** Builder for {@link Rule}. */ + public static Builder newBuilder() { + return new AutoValue_CelPolicy_Rule.Builder() + .setVariables(ImmutableSet.of()) + .setMatches(ImmutableSet.of()); + } + + /** Creates a new builder to construct a {@link Rule} instance. */ + @AutoValue.Builder + public abstract static class Builder { + + public abstract Rule.Builder setId(ValueString id); + + public abstract Rule.Builder setDescription(ValueString description); + + abstract ImmutableSet variables(); + + abstract ImmutableSet.Builder variablesBuilder(); + + abstract ImmutableSet matches(); + + abstract ImmutableSet.Builder matchesBuilder(); + + @CanIgnoreReturnValue + public Builder addVariables(Variable... variables) { + return addVariables(Arrays.asList(variables)); + } + + @CanIgnoreReturnValue + public Builder addVariables(Iterable variables) { + this.variablesBuilder().addAll(checkNotNull(variables)); + return this; + } + + @CanIgnoreReturnValue + public Builder addMatches(Match... matches) { + return addMatches(Arrays.asList(matches)); + } + + @CanIgnoreReturnValue + public Builder addMatches(Iterable matches) { + this.matchesBuilder().addAll(checkNotNull(matches)); + return this; + } + + abstract Rule.Builder setVariables(ImmutableSet variables); + + abstract Rule.Builder setMatches(ImmutableSet matches); + + public abstract Rule build(); + } + } + + /** + * Match declares a condition (defaults to true) as well as an output or a rule. Either the output + * or the rule field may be set, but not both. + */ + @AutoValue + public abstract static class Match { + + public abstract ValueString condition(); + + public abstract Result result(); + + /** Encapsulates the result of this match when condition is met. (either an output or a rule) */ + @AutoOneOf(Match.Result.Kind.class) + public abstract static class Result { + public abstract ValueString output(); + + public abstract Rule rule(); + + public abstract Kind kind(); + + public static Result ofOutput(ValueString value) { + return AutoOneOf_CelPolicy_Match_Result.output(value); + } + + public static Result ofRule(Rule value) { + return AutoOneOf_CelPolicy_Match_Result.rule(value); + } + + /** Kind for {@link Result}. */ + public enum Kind { + OUTPUT, + RULE + } + } + + /** Builder for {@link Match}. */ + @AutoValue.Builder + public abstract static class Builder implements RequiredFieldsChecker { + + public abstract Builder setCondition(ValueString condition); + + public abstract Builder setResult(Result result); + + abstract Optional result(); + + @Override + public ImmutableList requiredFields() { + return ImmutableList.of(RequiredField.of("output or a rule", this::result)); + } + + public abstract Match build(); + } + + /** Creates a new builder to construct a {@link Match} instance. */ + public static Builder newBuilder() { + return new AutoValue_CelPolicy_Match.Builder(); + } + } + + /** Variable is a named expression which may be referenced in subsequent expressions. */ + @AutoValue + public abstract static class Variable { + + public abstract ValueString name(); + + public abstract ValueString expression(); + + /** Builder for {@link Variable}. */ + @AutoValue.Builder + public abstract static class Builder { + + public abstract Builder setName(ValueString name); + + public abstract Builder setExpression(ValueString expression); + + public abstract Variable build(); + } + + /** Creates a new builder to construct a {@link Variable} instance. */ + public static Builder newBuilder() { + return new AutoValue_CelPolicy_Variable.Builder() + .setName(ValueString.newBuilder().build()) + .setExpression(ValueString.newBuilder().build()); + } + } +} diff --git a/policy/src/main/java/dev/cel/policy/CelPolicyConfig.java b/policy/src/main/java/dev/cel/policy/CelPolicyConfig.java index 13f2bad66..c5acc43f5 100644 --- a/policy/src/main/java/dev/cel/policy/CelPolicyConfig.java +++ b/policy/src/main/java/dev/cel/policy/CelPolicyConfig.java @@ -267,7 +267,7 @@ public CelFunctionDecl toCelFunctionDecl(CelTypeProvider celTypeProvider) { } } - /** Represents an overload declaraion on a policy function. */ + /** Represents an overload declaration on a policy function. */ @AutoValue public abstract static class OverloadDecl { diff --git a/policy/src/main/java/dev/cel/policy/CelPolicyParser.java b/policy/src/main/java/dev/cel/policy/CelPolicyParser.java new file mode 100644 index 000000000..315ece06c --- /dev/null +++ b/policy/src/main/java/dev/cel/policy/CelPolicyParser.java @@ -0,0 +1,87 @@ +// Copyright 2024 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.policy; + +/** CelPolicyParser is the interface for parsing policies into a canonical Policy representation. */ +public interface CelPolicyParser { + + /** Parses the input {@code policySource} and returns a {@link CelPolicy}. */ + CelPolicy parse(String policySource) throws CelPolicyValidationException; + + /** + * Parses the input {@code policySource} and returns a {@link CelPolicy}. + * + *

The {@code description} may be used to help tailor error messages for the location where the + * {@code policySource} originates, e.g. a file name or form UI element. + */ + CelPolicy parse(String policySource, String description) throws CelPolicyValidationException; + + /** + * TagVisitor declares a set of interfaces for handling custom tags which would otherwise be + * unsupported within the policy, rule, match, or variable objects. + * + * @param Type of the node (ex: YAML). + */ + interface TagVisitor { + + /** + * visitPolicyTag accepts a parser context, field id, tag name, yaml node, and parent Policy to + * allow for continued parsing within a custom tag. + */ + default void visitPolicyTag( + ParserContext ctx, long id, String fieldName, T node, CelPolicy.Builder policyBuilder) { + ctx.reportError(id, String.format("Unsupported policy tag: %s", fieldName)); + } + + /** + * visitRuleTag accepts a parser context, field id, tag name, yaml node, as well as the parent + * policy and current rule to allow for continued parsing within custom tags. + */ + default void visitRuleTag( + ParserContext ctx, + long id, + String fieldName, + T node, + CelPolicy.Rule.Builder ruleBuilder) { + ctx.reportError(id, String.format("Unsupported rule tag: %s", fieldName)); + } + + /** + * visitMatchTag accepts a parser context, field id, tag name, yaml node, as well as the parent + * policy and current match to allow for continued parsing within custom tags. + */ + default void visitMatchTag( + ParserContext ctx, + long id, + String fieldName, + T node, + CelPolicy.Match.Builder matchBuilder) { + ctx.reportError(id, String.format("Unsupported match tag: %s", fieldName)); + } + + /** + * visitVariableTag accepts a parser context, field id, tag name, yaml node, as well as the + * parent policy and current variable to allow for continued parsing within custom tags. + */ + default void visitVariableTag( + ParserContext ctx, + long id, + String fieldName, + T node, + CelPolicy.Variable.Builder variableBuilder) { + ctx.reportError(id, String.format("Unsupported variable tag: %s", fieldName)); + } + } +} diff --git a/policy/src/main/java/dev/cel/policy/CelPolicyParserBuilder.java b/policy/src/main/java/dev/cel/policy/CelPolicyParserBuilder.java new file mode 100644 index 000000000..ba34a1a60 --- /dev/null +++ b/policy/src/main/java/dev/cel/policy/CelPolicyParserBuilder.java @@ -0,0 +1,35 @@ +// Copyright 2024 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.policy; + +import com.google.errorprone.annotations.CanIgnoreReturnValue; +import com.google.errorprone.annotations.CheckReturnValue; +import dev.cel.policy.CelPolicyParser.TagVisitor; + +/** + * Interface for building an instance of {@link CelPolicyParser}. + * + * @param Type of the node (Ex: YAML). + */ +public interface CelPolicyParserBuilder { + + /** Adds a custom tag visitor to allow for handling of custom tags. */ + @CanIgnoreReturnValue + CelPolicyParserBuilder addTagVisitor(TagVisitor tagVisitor); + + /** Builds a new instance of {@link CelPolicyParser}. */ + @CheckReturnValue + CelPolicyParser build(); +} diff --git a/policy/src/main/java/dev/cel/policy/CelPolicySource.java b/policy/src/main/java/dev/cel/policy/CelPolicySource.java index 75565b563..c690652d9 100644 --- a/policy/src/main/java/dev/cel/policy/CelPolicySource.java +++ b/policy/src/main/java/dev/cel/policy/CelPolicySource.java @@ -15,10 +15,12 @@ package dev.cel.policy; import com.google.auto.value.AutoValue; +import com.google.common.collect.ImmutableMap; import com.google.errorprone.annotations.CheckReturnValue; import dev.cel.common.CelSourceHelper; import dev.cel.common.Source; import dev.cel.common.internal.CelCodePointArray; +import java.util.Map; import java.util.Optional; /** CelPolicySource represents the source content of a policy and its related metadata. */ @@ -31,6 +33,9 @@ public abstract class CelPolicySource implements Source { @Override public abstract String getDescription(); + @Override + public abstract ImmutableMap getPositionsMap(); + @Override public Optional getSnippet(int line) { return CelSourceHelper.getSnippet(getContent(), line); @@ -44,6 +49,8 @@ public abstract static class Builder { public abstract Builder setDescription(String description); + public abstract Builder setPositionsMap(Map value); + @CheckReturnValue public abstract CelPolicySource build(); } @@ -53,6 +60,7 @@ public abstract static class Builder { public static Builder newBuilder(CelCodePointArray celCodePointArray) { return new AutoValue_CelPolicySource.Builder() .setDescription("") - .setContent(celCodePointArray); + .setContent(celCodePointArray) + .setPositionsMap(ImmutableMap.of()); } } diff --git a/policy/src/main/java/dev/cel/policy/CelPolicyYamlConfigParser.java b/policy/src/main/java/dev/cel/policy/CelPolicyYamlConfigParser.java index 0cc348cc5..01dfc77b6 100644 --- a/policy/src/main/java/dev/cel/policy/CelPolicyYamlConfigParser.java +++ b/policy/src/main/java/dev/cel/policy/CelPolicyYamlConfigParser.java @@ -334,10 +334,15 @@ private CelPolicyConfig parseYaml(String source, String description) ParserContext ctx = YamlParserContextImpl.newInstance(configCodePointArray); CelPolicyConfig.Builder policyConfig = parseConfig(ctx, node); CelPolicySource configSource = - CelPolicySource.newBuilder(configCodePointArray).setDescription(description).build(); + CelPolicySource.newBuilder(configCodePointArray) + .setDescription(description) + .setPositionsMap(ctx.getIdToOffsetMap()) + .build(); + if (ctx.hasError()) { throw new CelPolicyValidationException(ctx.getIssueString(configSource)); } + return policyConfig.setConfigSource(configSource).build(); } @@ -347,6 +352,7 @@ private CelPolicyConfig.Builder parseConfig(ParserContext ctx, Node node) if (!assertYamlType(ctx, id, node, YamlNodeType.MAP)) { return builder; } + MappingNode rootNode = (MappingNode) node; for (NodeTuple nodeTuple : rootNode.getValue()) { Node keyNode = nodeTuple.getKeyNode(); @@ -354,6 +360,7 @@ private CelPolicyConfig.Builder parseConfig(ParserContext ctx, Node node) if (!assertYamlType(ctx, keyId, keyNode, YamlNodeType.STRING, YamlNodeType.TEXT)) { continue; } + Node valueNode = nodeTuple.getValueNode(); String fieldName = ((ScalarNode) keyNode).getValue(); switch (fieldName) { @@ -380,6 +387,7 @@ private CelPolicyConfig.Builder parseConfig(ParserContext ctx, Node node) // continue handling the rest of the nodes } } + return builder; } } diff --git a/policy/src/main/java/dev/cel/policy/CelPolicyYamlParser.java b/policy/src/main/java/dev/cel/policy/CelPolicyYamlParser.java new file mode 100644 index 000000000..64921bee9 --- /dev/null +++ b/policy/src/main/java/dev/cel/policy/CelPolicyYamlParser.java @@ -0,0 +1,288 @@ +// Copyright 2024 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.policy; + +import static com.google.common.base.Preconditions.checkNotNull; +import static dev.cel.policy.YamlHelper.assertRequiredFields; +import static dev.cel.policy.YamlHelper.assertYamlType; +import static dev.cel.policy.YamlHelper.newValueString; + +import com.google.common.collect.ImmutableSet; +import dev.cel.common.internal.CelCodePointArray; +import dev.cel.policy.CelPolicy.Match; +import dev.cel.policy.CelPolicy.Variable; +import dev.cel.policy.YamlHelper.YamlNodeType; +import java.util.Optional; +import org.yaml.snakeyaml.nodes.MappingNode; +import org.yaml.snakeyaml.nodes.Node; +import org.yaml.snakeyaml.nodes.NodeTuple; +import org.yaml.snakeyaml.nodes.ScalarNode; +import org.yaml.snakeyaml.nodes.SequenceNode; + +final class CelPolicyYamlParser implements CelPolicyParser { + + private final TagVisitor tagVisitor; + + @Override + public CelPolicy parse(String policySource) throws CelPolicyValidationException { + return parse(policySource, ""); + } + + @Override + public CelPolicy parse(String policySource, String description) + throws CelPolicyValidationException { + ParserImpl parser = new ParserImpl(tagVisitor); + return parser.parseYaml(policySource, description); + } + + private static class ParserImpl { + + private final TagVisitor tagVisitor; + + private CelPolicy parseYaml(String policySource, String description) + throws CelPolicyValidationException { + Node node; + try { + node = YamlHelper.parseYamlSource(policySource); + } catch (RuntimeException e) { + throw new CelPolicyValidationException("YAML document is malformed: " + e.getMessage(), e); + } + + CelCodePointArray policyCodePoints = CelCodePointArray.fromString(policySource); + ParserContext ctx = YamlParserContextImpl.newInstance(policyCodePoints); + + CelPolicy.Builder policyBuilder = parsePolicy(ctx, node); + CelPolicySource celPolicySource = + CelPolicySource.newBuilder(policyCodePoints) + .setDescription(description) + .setPositionsMap(ctx.getIdToOffsetMap()) + .build(); + + if (ctx.hasError()) { + throw new CelPolicyValidationException(ctx.getIssueString(celPolicySource)); + } + + return policyBuilder.setPolicySource(celPolicySource).build(); + } + + private CelPolicy.Builder parsePolicy(ParserContext ctx, Node node) { + CelPolicy.Builder policyBuilder = CelPolicy.newBuilder(); + long id = ctx.collectMetadata(node); + if (!assertYamlType(ctx, id, node, YamlNodeType.MAP)) { + return policyBuilder; + } + + MappingNode rootNode = (MappingNode) node; + for (NodeTuple nodeTuple : rootNode.getValue()) { + Node keyNode = nodeTuple.getKeyNode(); + long keyId = ctx.collectMetadata(keyNode); + if (!assertYamlType(ctx, keyId, keyNode, YamlNodeType.STRING, YamlNodeType.TEXT)) { + continue; + } + + Node valueNode = nodeTuple.getValueNode(); + String fieldName = ((ScalarNode) keyNode).getValue(); + switch (fieldName) { + case "name": + policyBuilder.setName(newValueString(ctx, valueNode)); + break; + case "rule": + policyBuilder.setRule(parseRule(ctx, valueNode)); + break; + default: + tagVisitor.visitPolicyTag(ctx, keyId, fieldName, valueNode, policyBuilder); + break; + } + } + + return policyBuilder; + } + + private CelPolicy.Rule parseRule(ParserContext ctx, Node node) { + long valueId = ctx.collectMetadata(node); + CelPolicy.Rule.Builder ruleBuilder = CelPolicy.Rule.newBuilder(); + if (!assertYamlType(ctx, valueId, node, YamlNodeType.MAP)) { + return ruleBuilder.build(); + } + + for (NodeTuple nodeTuple : ((MappingNode) node).getValue()) { + Node key = nodeTuple.getKeyNode(); + long tagId = ctx.collectMetadata(key); + if (!assertYamlType(ctx, tagId, key, YamlNodeType.STRING, YamlNodeType.TEXT)) { + continue; + } + String fieldName = ((ScalarNode) key).getValue(); + Node value = nodeTuple.getValueNode(); + switch (fieldName) { + case "id": + ruleBuilder.setId(newValueString(ctx, value)); + break; + case "description": + ruleBuilder.setDescription(newValueString(ctx, value)); + break; + case "variables": + ruleBuilder.addVariables(parseVariables(ctx, value)); + break; + case "match": + ruleBuilder.addMatches(parseMatches(ctx, value)); + break; + default: + tagVisitor.visitRuleTag(ctx, tagId, fieldName, value, ruleBuilder); + break; + } + } + return ruleBuilder.build(); + } + + private ImmutableSet parseMatches(ParserContext ctx, Node node) { + long valueId = ctx.collectMetadata(node); + ImmutableSet.Builder matchesBuilder = ImmutableSet.builder(); + if (!assertYamlType(ctx, valueId, node, YamlNodeType.LIST)) { + return matchesBuilder.build(); + } + + SequenceNode matchListNode = (SequenceNode) node; + for (Node elementNode : matchListNode.getValue()) { + parseMatch(ctx, elementNode).ifPresent(matchesBuilder::add); + } + + return matchesBuilder.build(); + } + + private Optional parseMatch(ParserContext ctx, Node node) { + long nodeId = ctx.collectMetadata(node); + if (!assertYamlType(ctx, nodeId, node, YamlNodeType.MAP)) { + return Optional.empty(); + } + MappingNode matchNode = (MappingNode) node; + CelPolicy.Match.Builder matchBuilder = + CelPolicy.Match.newBuilder().setCondition(ValueString.of(ctx.nextId(), "true")); + for (NodeTuple nodeTuple : matchNode.getValue()) { + Node key = nodeTuple.getKeyNode(); + long tagId = ctx.collectMetadata(key); + if (!assertYamlType(ctx, tagId, key, YamlNodeType.STRING, YamlNodeType.TEXT)) { + continue; + } + String fieldName = ((ScalarNode) key).getValue(); + Node value = nodeTuple.getValueNode(); + switch (fieldName) { + case "condition": + matchBuilder.setCondition(newValueString(ctx, value)); + break; + case "output": + matchBuilder + .result() + .filter(result -> result.kind().equals(Match.Result.Kind.RULE)) + .ifPresent( + result -> ctx.reportError(tagId, "Only the rule or the output may be set")); + matchBuilder.setResult(Match.Result.ofOutput(newValueString(ctx, value))); + break; + case "rule": + matchBuilder + .result() + .filter(result -> result.kind().equals(Match.Result.Kind.OUTPUT)) + .ifPresent( + result -> ctx.reportError(tagId, "Only the rule or the output may be set")); + matchBuilder.setResult(Match.Result.ofRule(parseRule(ctx, value))); + break; + default: + tagVisitor.visitMatchTag(ctx, tagId, fieldName, value, matchBuilder); + break; + } + } + + if (!assertRequiredFields(ctx, nodeId, matchBuilder.getMissingRequiredFieldNames())) { + return Optional.empty(); + } + + return Optional.of(matchBuilder.build()); + } + + private ImmutableSet parseVariables(ParserContext ctx, Node node) { + long valueId = ctx.collectMetadata(node); + ImmutableSet.Builder variableBuilder = ImmutableSet.builder(); + if (!assertYamlType(ctx, valueId, node, YamlNodeType.LIST)) { + return variableBuilder.build(); + } + + SequenceNode variableListNode = (SequenceNode) node; + for (Node elementNode : variableListNode.getValue()) { + long id = ctx.collectMetadata(elementNode); + if (!assertYamlType(ctx, id, elementNode, YamlNodeType.MAP)) { + continue; + } + variableBuilder.add(parseVariable(ctx, (MappingNode) elementNode)); + } + + return variableBuilder.build(); + } + + private CelPolicy.Variable parseVariable(ParserContext ctx, MappingNode variableMap) { + Variable.Builder builder = Variable.newBuilder(); + + for (NodeTuple nodeTuple : variableMap.getValue()) { + Node keyNode = nodeTuple.getKeyNode(); + long keyId = ctx.collectMetadata(keyNode); + Node valueNode = nodeTuple.getValueNode(); + String keyName = ((ScalarNode) keyNode).getValue(); + switch (keyName) { + case "name": + builder.setName(newValueString(ctx, valueNode)); + break; + case "expression": + builder.setExpression(newValueString(ctx, valueNode)); + break; + default: + tagVisitor.visitVariableTag(ctx, keyId, keyName, valueNode, builder); + break; + } + } + + return builder.build(); + } + + private ParserImpl(TagVisitor tagVisitor) { + this.tagVisitor = tagVisitor; + } + } + + static final class Builder implements CelPolicyParserBuilder { + + private TagVisitor tagVisitor; + + private Builder() { + this.tagVisitor = new TagVisitor() {}; + } + + @Override + public CelPolicyParserBuilder addTagVisitor(TagVisitor tagVisitor) { + this.tagVisitor = tagVisitor; + return this; + } + + @Override + public CelPolicyParser build() { + return new CelPolicyYamlParser(tagVisitor); + } + } + + static Builder newBuilder() { + return new Builder(); + } + + private CelPolicyYamlParser(TagVisitor tagVisitor) { + this.tagVisitor = checkNotNull(tagVisitor); + } +} diff --git a/policy/src/main/java/dev/cel/policy/ParserContext.java b/policy/src/main/java/dev/cel/policy/ParserContext.java index ec4c72f20..3b68f82a5 100644 --- a/policy/src/main/java/dev/cel/policy/ParserContext.java +++ b/policy/src/main/java/dev/cel/policy/ParserContext.java @@ -15,6 +15,7 @@ package dev.cel.policy; import dev.cel.common.Source; +import java.util.Map; /** * ParserContext declares a set of interfaces for creating and managing metadata for parsed @@ -30,4 +31,6 @@ public interface ParserContext { String getIssueString(Source source); boolean hasError(); + + Map getIdToOffsetMap(); } diff --git a/policy/src/main/java/dev/cel/policy/YamlParserContextImpl.java b/policy/src/main/java/dev/cel/policy/YamlParserContextImpl.java index 34f70db6c..31438fd98 100644 --- a/policy/src/main/java/dev/cel/policy/YamlParserContextImpl.java +++ b/policy/src/main/java/dev/cel/policy/YamlParserContextImpl.java @@ -23,6 +23,7 @@ import dev.cel.common.internal.CelCodePointArray; import java.util.ArrayList; import java.util.HashMap; +import java.util.Map; import org.yaml.snakeyaml.DumperOptions; import org.yaml.snakeyaml.nodes.Node; import org.yaml.snakeyaml.nodes.ScalarNode; @@ -54,6 +55,11 @@ public boolean hasError() { return !issues.isEmpty(); } + @Override + public Map getIdToOffsetMap() { + return idToOffsetMap; + } + @Override public long collectMetadata(Node node) { long id = nextId(); diff --git a/policy/src/test/java/dev/cel/policy/BUILD.bazel b/policy/src/test/java/dev/cel/policy/BUILD.bazel index b4844833a..38e88e5f4 100644 --- a/policy/src/test/java/dev/cel/policy/BUILD.bazel +++ b/policy/src/test/java/dev/cel/policy/BUILD.bazel @@ -6,16 +6,22 @@ java_library( name = "tests", testonly = True, srcs = glob(["*.java"]), + resources = [ + "//policy/src/test/resources:policy_yaml_files", + ], deps = [ "//:java_truth", "//bundle:cel", "//common:options", "//common/internal", + "//policy", "//policy:config", "//policy:config_parser", + "//policy:parser", "//policy:source", "//policy:validation_exception", "//policy:yaml_config_parser", + "//policy:yaml_parser", "@maven//:com_google_api_grpc_proto_google_common_protos", "@maven//:com_google_guava_guava", "@maven//:com_google_testparameterinjector_test_parameter_injector", diff --git a/policy/src/test/java/dev/cel/policy/CelPolicyYamlParserTest.java b/policy/src/test/java/dev/cel/policy/CelPolicyYamlParserTest.java new file mode 100644 index 000000000..fc19d8f0c --- /dev/null +++ b/policy/src/test/java/dev/cel/policy/CelPolicyYamlParserTest.java @@ -0,0 +1,202 @@ +// Copyright 2024 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.policy; + +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertThrows; + +import com.google.testing.junit.testparameterinjector.TestParameter; +import com.google.testing.junit.testparameterinjector.TestParameterInjector; +import dev.cel.policy.PolicyTestHelper.TestYamlPolicy; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(TestParameterInjector.class) +public final class CelPolicyYamlParserTest { + + private static final CelPolicyParser POLICY_PARSER = CelPolicyYamlParser.newBuilder().build(); + + @Test + public void parseYamlPolicy_success(@TestParameter TestYamlPolicy yamlPolicy) throws Exception { + String policySource = yamlPolicy.readPolicyYamlContent(); + String description = yamlPolicy.getPolicyName(); + + CelPolicy policy = POLICY_PARSER.parse(policySource, description); + + assertThat(policy.name().value()).isEqualTo(yamlPolicy.getPolicyName()); + assertThat(policy.policySource().getContent().toString()).isEqualTo(policySource); + assertThat(policy.policySource().getDescription()).isEqualTo(description); + } + + @Test + public void parseYamlPolicy_errors(@TestParameter PolicyParseErrorTestCase testCase) { + CelPolicyValidationException e = + assertThrows( + CelPolicyValidationException.class, () -> POLICY_PARSER.parse(testCase.yamlPolicy)); + assertThat(e).hasMessageThat().isEqualTo(testCase.expectedErrorMessage); + } + + private enum PolicyParseErrorTestCase { + MALFORMED_YAML_DOCUMENT( + "a:\na", + "YAML document is malformed: while scanning a simple key\n" + + " in 'reader', line 2, column 1:\n" + + " a\n" + + " ^\n" + + "could not find expected ':'\n" + + " in 'reader', line 2, column 2:\n" + + " a\n" + + " ^\n"), + ILLEGAL_YAML_TYPE_POLICY_KEY( + "1: test", + "ERROR: :1:1: Got yaml node type tag:yaml.org,2002:int, wanted type(s)" + + " [tag:yaml.org,2002:str !txt]\n" + + " | 1: test\n" + + " | ^"), + ILLEGAL_YAML_TYPE_ON_NAME_VALUE( + "name: \n" + " illegal: yaml-type", + "ERROR: :2:3: Got yaml node type tag:yaml.org,2002:map, wanted type(s)" + + " [tag:yaml.org,2002:str !txt]\n" + + " | illegal: yaml-type\n" + + " | ..^"), + ILLEGAL_YAML_TYPE_ON_RULE_VALUE( + "rule: illegal", + "ERROR: :1:7: Got yaml node type tag:yaml.org,2002:str, wanted type(s)" + + " [tag:yaml.org,2002:map]\n" + + " | rule: illegal\n" + + " | ......^"), + ILLEGAL_YAML_TYPE_ON_RULE_MAP_KEY( + "rule: \n" + " 1: foo", + "ERROR: :2:3: Got yaml node type tag:yaml.org,2002:int, wanted type(s)" + + " [tag:yaml.org,2002:str !txt]\n" + + " | 1: foo\n" + + " | ..^"), + ILLEGAL_YAML_TYPE_ON_MATCHES_VALUE( + "rule:\n" + " match: illegal\n", + "ERROR: :2:10: Got yaml node type tag:yaml.org,2002:str, wanted type(s)" + + " [tag:yaml.org,2002:seq]\n" + + " | match: illegal\n" + + " | .........^"), + ILLEGAL_YAML_TYPE_ON_MATCHES_LIST( + "rule:\n" + " match:\n" + " - illegal", + "ERROR: :3:7: Got yaml node type tag:yaml.org,2002:str, wanted type(s)" + + " [tag:yaml.org,2002:map]\n" + + " | - illegal\n" + + " | ......^"), + ILLEGAL_YAML_TYPE_ON_MATCH_MAP_KEY( + "rule:\n" + " match:\n" + " - 1 : foo\n" + " output: 'hi'", + "ERROR: :3:7: Got yaml node type tag:yaml.org,2002:int, wanted type(s)" + + " [tag:yaml.org,2002:str !txt]\n" + + " | - 1 : foo\n" + + " | ......^"), + ILLEGAL_YAML_TYPE_ON_VARIABLE_VALUE( + "rule:\n" + " variables: illegal\n", + "ERROR: :2:14: Got yaml node type tag:yaml.org,2002:str, wanted type(s)" + + " [tag:yaml.org,2002:seq]\n" + + " | variables: illegal\n" + + " | .............^"), + ILLEGAL_YAML_TYPE_ON_VARIABLE_MAP_KEY( + "rule:\n" + " variables:\n" + " - illegal", + "ERROR: :3:7: Got yaml node type tag:yaml.org,2002:str, wanted type(s)" + + " [tag:yaml.org,2002:map]\n" + + " | - illegal\n" + + " | ......^"), + MULTIPLE_YAML_DOCS( + "name: foo\n" + "---\n" + "name: bar", + "YAML document is malformed: expected a single document in the stream\n" + + " in 'reader', line 1, column 1:\n" + + " name: foo\n" + + " ^\n" + + "but found another document\n" + + " in 'reader', line 2, column 1:\n" + + " ---\n" + + " ^\n"), + UNSUPPORTED_RULE_TAG( + "rule:\n" + " custom: yaml-type", + "ERROR: :2:3: Unsupported rule tag: custom\n" + + " | custom: yaml-type\n" + + " | ..^"), + UNSUPPORTED_POLICY_TAG( + "inputs:\n" + " - name: a\n" + " - name: b", + "ERROR: :1:1: Unsupported policy tag: inputs\n" + " | inputs:\n" + " | ^"), + UNSUPPORTED_VARIABLE_TAG( + "rule:\n" + " variables:\n" + " - name: 'true'\n" + " alt_name: 'bool_true'", + "ERROR: :4:7: Unsupported variable tag: alt_name\n" + + " | alt_name: 'bool_true'\n" + + " | ......^"), + UNSUPPORTED_MATCH_TAG( + "rule:\n" + + " match:\n" + + " - name: 'true'\n" + + " output: 'hi'\n" + + " alt_name: 'bool_true'", + "ERROR: :3:7: Unsupported match tag: name\n" + + " | - name: 'true'\n" + + " | ......^\n" + + "ERROR: :5:7: Unsupported match tag: alt_name\n" + + " | alt_name: 'bool_true'\n" + + " | ......^"), + MATCH_MISSING_OUTPUT_AND_RULE( + "rule:\n" // + + " match:\n" // + + " - condition: 'true'", + "ERROR: :3:7: Missing required attribute(s): output or a rule\n" + + " | - condition: 'true'\n" + + " | ......^"), + MATCH_OUTPUT_SET_THEN_RULE( + "rule:\n" + + " match:\n" + + " - condition: \"true\"\n" + + " output: \"world\"\n" + + " rule:\n" + + " match:\n" + + " - output: \"hello\"", + "ERROR: :5:7: Only the rule or the output may be set\n" + + " | rule:\n" + + " | ......^"), + MATCH_RULE_SET_THEN_OUTPUT( + "rule:\n" + + " match:\n" + + " - condition: \"true\"\n" + + " rule:\n" + + " match:\n" + + " - output: \"hello\"\n" + + " output: \"world\"", + "ERROR: :7:7: Only the rule or the output may be set\n" + + " | output: \"world\"\n" + + " | ......^"), + INVALID_ROOT_NODE_TYPE( + "- rule:\n" + " id: a", + "ERROR: :1:1: Got yaml node type tag:yaml.org,2002:seq, wanted type(s)" + + " [tag:yaml.org,2002:map]\n" + + " | - rule:\n" + + " | ^"), + ILLEGAL_RULE_DESCRIPTION_TYPE( + "rule:\n" + " description: 1", + "ERROR: :2:16: Got yaml node type tag:yaml.org,2002:int, wanted type(s)" + + " [tag:yaml.org,2002:str !txt]\n" + + " | description: 1\n" + + " | ...............^"), + ; + + private final String yamlPolicy; + private final String expectedErrorMessage; + + PolicyParseErrorTestCase(String yamlPolicy, String expectedErrorMessage) { + this.yamlPolicy = yamlPolicy; + this.expectedErrorMessage = expectedErrorMessage; + } + } +} diff --git a/policy/src/test/java/dev/cel/policy/PolicyTestHelper.java b/policy/src/test/java/dev/cel/policy/PolicyTestHelper.java new file mode 100644 index 000000000..c04d15440 --- /dev/null +++ b/policy/src/test/java/dev/cel/policy/PolicyTestHelper.java @@ -0,0 +1,105 @@ +// Copyright 2024 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.policy; + +import static java.nio.charset.StandardCharsets.UTF_8; + +import com.google.common.base.Ascii; +import com.google.common.io.Resources; +import java.io.IOException; +import java.net.URL; + +/** Package-private class to assist with policy testing. */ +final class PolicyTestHelper { + + enum TestYamlPolicy { + NESTED_RULE( + "nested_rule", + true, + "cel.bind(variables.permitted_regions, [\"us\", \"uk\", \"es\"]," + + " cel.bind(variables.banned_regions, {\"us\": false, \"ru\": false, \"ir\": false}," + + " (resource.origin in variables.banned_regions && " + + "!(resource.origin in variables.permitted_regions)) " + + "? optional.of({\"banned\": true}) : optional.none()).or(" + + "optional.of((resource.origin in variables.permitted_regions)" + + " ? {\"banned\": false} : {\"banned\": true})))"), + REQUIRED_LABELS( + "required_labels", + true, + "" + + "cel.bind(variables.want, spec.labels, cel.bind(variables.missing, " + + "variables.want.filter(l, !(l in resource.labels)), cel.bind(variables.invalid, " + + "resource.labels.filter(l, l in variables.want && variables.want[l] != " + + "resource.labels[l]), (variables.missing.size() > 0) ? " + + "optional.of(\"missing one or more required labels: [\"\" + " + + "variables.missing.join(\",\") + \"\"]\") : ((variables.invalid.size() > 0) ? " + + "optional.of(\"invalid values provided on one or more labels: [\"\" + " + + "variables.invalid.join(\",\") + \"\"]\") : optional.none()))))"), + RESTRICTED_DESTINATIONS( + "restricted_destinations", + false, + "cel.bind(variables.matches_origin_ip, locationCode(origin.ip) == spec.origin," + + " cel.bind(variables.has_nationality, has(request.auth.claims.nationality)," + + " cel.bind(variables.matches_nationality, variables.has_nationality &&" + + " request.auth.claims.nationality == spec.origin, cel.bind(variables.matches_dest_ip," + + " locationCode(destination.ip) in spec.restricted_destinations," + + " cel.bind(variables.matches_dest_label, resource.labels.location in" + + " spec.restricted_destinations, cel.bind(variables.matches_dest," + + " variables.matches_dest_ip || variables.matches_dest_label," + + " (variables.matches_nationality && variables.matches_dest) ? true :" + + " ((!variables.has_nationality && variables.matches_origin_ip &&" + + " variables.matches_dest) ? true : false)))))))"); + + private final String name; + private final boolean producesOptionalResult; + private final String unparsed; + + TestYamlPolicy(String name, boolean producesOptionalResult, String unparsed) { + this.name = name; + this.producesOptionalResult = producesOptionalResult; + this.unparsed = unparsed; + } + + String getPolicyName() { + return name; + } + + boolean producesOptionalResult() { + return this.producesOptionalResult; + } + + String getUnparsed() { + return unparsed; + } + + String readPolicyYamlContent() throws IOException { + return readFromYaml(String.format("%s/policy.yaml", name)); + } + } + + static String readFromYaml(String yamlPath) throws IOException { + return readFile(yamlPath); + } + + private static URL getResource(String path) { + return Resources.getResource(Ascii.toLowerCase(path)); + } + + private static String readFile(String path) throws IOException { + return Resources.toString(getResource(path), UTF_8); + } + + private PolicyTestHelper() {} +} From 3d2aadabf890fbf2a09d4f697850b0dc7e24e1c7 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Tue, 2 Jul 2024 15:55:09 -0700 Subject: [PATCH 143/486] Move computing offset location into CelSourceHelper for reuse PiperOrigin-RevId: 648869686 --- .../src/main/java/dev/cel/common/BUILD.bazel | 1 + .../main/java/dev/cel/common/CelSource.java | 39 +------------------ .../java/dev/cel/common/CelSourceHelper.java | 34 ++++++++++++++++ .../src/main/java/dev/cel/policy/BUILD.bazel | 1 + .../java/dev/cel/policy/CelPolicySource.java | 8 ++++ 5 files changed, 46 insertions(+), 37 deletions(-) diff --git a/common/src/main/java/dev/cel/common/BUILD.bazel b/common/src/main/java/dev/cel/common/BUILD.bazel index 82e74bf1d..dbb8890d5 100644 --- a/common/src/main/java/dev/cel/common/BUILD.bazel +++ b/common/src/main/java/dev/cel/common/BUILD.bazel @@ -203,6 +203,7 @@ java_library( name = "source", srcs = SOURCE_SOURCES, deps = [ + ":source_location", "//common/annotations", "//common/internal", "@maven//:com_google_guava_guava", diff --git a/common/src/main/java/dev/cel/common/CelSource.java b/common/src/main/java/dev/cel/common/CelSource.java index 574946fd3..cc9244e30 100644 --- a/common/src/main/java/dev/cel/common/CelSource.java +++ b/common/src/main/java/dev/cel/common/CelSource.java @@ -108,7 +108,7 @@ public Optional getLocationOffset(int line, int column) { * Get the line and column in the source expression text for the given code point {@code offset}. */ public Optional getOffsetLocation(int offset) { - return getOffsetLocationImpl(lineOffsets, offset); + return CelSourceHelper.getOffsetLocation(codePoints, offset); } @Override @@ -134,30 +134,6 @@ private static Optional getLocationOffsetImpl( return Optional.of(offset + column); } - /** - * Get the line and column in the source expression text for the given code point {@code offset}. - */ - public static Optional getOffsetLocationImpl( - List lineOffsets, int offset) { - checkArgument(offset >= 0); - LineAndOffset lineAndOffset = findLine(lineOffsets, offset); - return Optional.of(CelSourceLocation.of(lineAndOffset.line, offset - lineAndOffset.offset)); - } - - private static LineAndOffset findLine(List lineOffsets, int offset) { - int line = 1; - for (int index = 0; index < lineOffsets.size(); index++) { - if (lineOffsets.get(index) > offset) { - break; - } - line++; - } - if (line == 1) { - return new LineAndOffset(line, 0); - } - return new LineAndOffset(line, lineOffsets.get(line - 2)); - } - public Builder toBuilder() { return new Builder(codePoints, lineOffsets) .setDescription(description) @@ -311,7 +287,7 @@ public Optional getLocationOffset(int line, int column) { * offset}. */ public Optional getOffsetLocation(int offset) { - return getOffsetLocationImpl(lineOffsets, offset); + return CelSourceHelper.getOffsetLocation(codePoints, offset); } @CheckReturnValue @@ -335,17 +311,6 @@ public CelSource build() { } } - private static final class LineAndOffset { - - private LineAndOffset(int line, int offset) { - this.line = line; - this.offset = offset; - } - - private final int line; - private final int offset; - } - /** * Tag for an extension that were used while parsing or type checking the source expression. For * example, optimizations that require special runtime support may be specified. These are used to diff --git a/common/src/main/java/dev/cel/common/CelSourceHelper.java b/common/src/main/java/dev/cel/common/CelSourceHelper.java index 4fde5db7b..13168edbe 100644 --- a/common/src/main/java/dev/cel/common/CelSourceHelper.java +++ b/common/src/main/java/dev/cel/common/CelSourceHelper.java @@ -47,6 +47,40 @@ public static Optional getSnippet(CelCodePointArray content, int line) { return Optional.of(end != start ? content.slice(start, end).toString() : ""); } + /** + * Get the line and column in the source expression text for the given code point {@code offset}. + */ + public static Optional getOffsetLocation( + CelCodePointArray content, int offset) { + checkArgument(offset >= 0); + LineAndOffset lineAndOffset = findLine(content.lineOffsets(), offset); + return Optional.of(CelSourceLocation.of(lineAndOffset.line, offset - lineAndOffset.offset)); + } + + private static LineAndOffset findLine(List lineOffsets, int offset) { + int line = 1; + for (Integer lineOffset : lineOffsets) { + if (lineOffset > offset) { + break; + } + line++; + } + if (line == 1) { + return new LineAndOffset(line, 0); + } + return new LineAndOffset(line, lineOffsets.get(line - 2)); + } + + private static final class LineAndOffset { + private LineAndOffset(int line, int offset) { + this.line = line; + this.offset = offset; + } + + private final int line; + private final int offset; + } + static int findLineOffset(List lineOffsets, int line) { if (line == 1) { return 0; diff --git a/policy/src/main/java/dev/cel/policy/BUILD.bazel b/policy/src/main/java/dev/cel/policy/BUILD.bazel index ed152b9f2..0c718d727 100644 --- a/policy/src/main/java/dev/cel/policy/BUILD.bazel +++ b/policy/src/main/java/dev/cel/policy/BUILD.bazel @@ -30,6 +30,7 @@ java_library( deps = [ "//:auto_value", "//common:source", + "//common:source_location", "//common/internal", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", diff --git a/policy/src/main/java/dev/cel/policy/CelPolicySource.java b/policy/src/main/java/dev/cel/policy/CelPolicySource.java index c690652d9..7918be872 100644 --- a/policy/src/main/java/dev/cel/policy/CelPolicySource.java +++ b/policy/src/main/java/dev/cel/policy/CelPolicySource.java @@ -18,6 +18,7 @@ import com.google.common.collect.ImmutableMap; import com.google.errorprone.annotations.CheckReturnValue; import dev.cel.common.CelSourceHelper; +import dev.cel.common.CelSourceLocation; import dev.cel.common.Source; import dev.cel.common.internal.CelCodePointArray; import java.util.Map; @@ -41,6 +42,13 @@ public Optional getSnippet(int line) { return CelSourceHelper.getSnippet(getContent(), line); } + /** + * Get the line and column in the source expression text for the given code point {@code offset}. + */ + public Optional getOffsetLocation(int offset) { + return CelSourceHelper.getOffsetLocation(getContent(), offset); + } + /** Builder for {@link CelPolicySource}. */ @AutoValue.Builder public abstract static class Builder { From 6399ae54370a08b68f11be861dd6cad2f265f092 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Tue, 2 Jul 2024 17:06:57 -0700 Subject: [PATCH 144/486] Add AstMutator methods to construct cel.bind macro with varInit containing macros PiperOrigin-RevId: 648887898 --- .../java/dev/cel/optimizer/AstMutator.java | 32 ++++++-- .../dev/cel/optimizer/AstMutatorTest.java | 75 +++++++++++++++++++ 2 files changed, 102 insertions(+), 5 deletions(-) diff --git a/optimizer/src/main/java/dev/cel/optimizer/AstMutator.java b/optimizer/src/main/java/dev/cel/optimizer/AstMutator.java index 8d35efc2c..dfcdb1a05 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/AstMutator.java +++ b/optimizer/src/main/java/dev/cel/optimizer/AstMutator.java @@ -111,16 +111,17 @@ public CelMutableAst wrapAstWithNewCelBlock( public CelMutableAst replaceSubtreeWithNewBindMacro( CelMutableAst ast, String varName, - CelMutableExpr varInit, + CelMutableAst varInit, CelMutableExpr resultExpr, long exprIdToReplace, boolean populateMacroSource) { - // Copy the incoming expressions to prevent modifying the root - long maxId = max(getMaxId(varInit), getMaxId(ast)); + // Stabilize incoming varInit AST to avoid collision with the main AST + long maxId = getMaxId(ast); + varInit = stabilizeAst(varInit, maxId); StableIdGenerator stableIdGenerator = CelExprIdGeneratorFactory.newStableIdGenerator(maxId); CelMutableExpr newBindMacroExpr = newBindMacroExpr( - varName, varInit, CelMutableExpr.newInstance(resultExpr), stableIdGenerator); + varName, varInit.expr(), CelMutableExpr.newInstance(resultExpr), stableIdGenerator); CelMutableSource celSource = CelMutableSource.newInstance(); if (populateMacroSource) { CelMutableExpr newBindMacroSourceExpr = @@ -128,9 +129,10 @@ public CelMutableAst replaceSubtreeWithNewBindMacro( // In situations where the existing AST already contains a macro call (ex: nested cel.binds), // its macro source must be normalized to make it consistent with the newly generated bind // macro. + celSource = combine(ast.source(), varInit.source()); celSource = normalizeMacroSource( - ast.source(), + celSource, -1, // Do not replace any of the subexpr in the macro map. newBindMacroSourceExpr, stableIdGenerator::renumberId); @@ -142,6 +144,26 @@ public CelMutableAst replaceSubtreeWithNewBindMacro( return replaceSubtree(ast, newBindAst, exprIdToReplace); } + /** + * See {@link #replaceSubtreeWithNewBindMacro(CelMutableAst, String, CelMutableAst, + * CelMutableExpr, long, boolean)}. + */ + public CelMutableAst replaceSubtreeWithNewBindMacro( + CelMutableAst ast, + String varName, + CelMutableExpr varInit, + CelMutableExpr resultExpr, + long exprIdToReplace, + boolean populateMacroSource) { + return replaceSubtreeWithNewBindMacro( + ast, + varName, + CelMutableAst.of(varInit, CelMutableSource.newInstance()), + resultExpr, + exprIdToReplace, + populateMacroSource); + } + /** Renumbers all the expr IDs in the given AST in a consecutive manner starting from 1. */ public CelMutableAst renumberIdsConsecutively(CelMutableAst mutableAst) { StableIdGenerator stableIdGenerator = CelExprIdGeneratorFactory.newStableIdGenerator(0); diff --git a/optimizer/src/test/java/dev/cel/optimizer/AstMutatorTest.java b/optimizer/src/test/java/dev/cel/optimizer/AstMutatorTest.java index 8d56c2a3a..d9d9a969e 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/AstMutatorTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/AstMutatorTest.java @@ -446,6 +446,81 @@ public void replaceSubtreeWithNewBindMacro_replaceRootWithNestedBindMacro() thro assertConsistentMacroCalls(mutatedAst); } + @Test + public void replaceSubtreeWithNewBindMacro_varInitContainsMacro_replaceRoot() throws Exception { + // Arrange + CelAbstractSyntaxTree ast = CEL.compile("true && true").getAst(); + CelMutableAst mutableAst = CelMutableAst.fromCelAst(ast); + CelMutableAst varInitAst = CelMutableAst.fromCelAst(CEL.compile("[].exists(x, x)").getAst()); + String variableName = "@r0"; + CelMutableExpr resultExpr = + CelMutableExpr.ofCall( + CelMutableCall.create( + Operator.LOGICAL_AND.getFunction(), + CelMutableExpr.ofIdent(variableName), + CelMutableExpr.ofIdent(variableName))); + + // Act + // Perform the initial replacement. (true && true) -> cel.bind(@r0, [].exists(x, x), @r0 && @r0) + mutableAst = + AST_MUTATOR.replaceSubtreeWithNewBindMacro( + mutableAst, + variableName, + varInitAst, + resultExpr, + ast.getExpr().id(), + true); // Replace && + + CelAbstractSyntaxTree mutatedAst = mutableAst.toParsedAst(); + assertThat(mutatedAst.getSource().getMacroCalls()).hasSize(2); + assertThat(CEL.createProgram(CEL.check(mutatedAst).getAst()).eval()).isEqualTo(false); + assertThat(CEL_UNPARSER.unparse(mutatedAst)) + .isEqualTo("cel.bind(@r0, [].exists(x, x), @r0 && @r0)"); + assertConsistentMacroCalls(mutatedAst); + } + + @Test + public void replaceSubtreeWithNewBindMacro_astAndVarInitContainsMacro_replaceRhs() + throws Exception { + // Arrange + CelAbstractSyntaxTree ast = CEL.compile("[true].exists(y,y) && false").getAst(); + CelMutableAst mutableAst = CelMutableAst.fromCelAst(ast); + CelMutableAst varInitAst = CelMutableAst.fromCelAst(CEL.compile("[].exists(x, x)").getAst()); + String variableName = "@r0"; + CelMutableExpr resultExpr = CelMutableExpr.ofIdent(variableName); + long falseExprId = + CelNavigableAst.fromAst(ast) + .getRoot() + .children() + .map(CelNavigableExpr::expr) + .filter( + x -> + x.getKind().equals(Kind.CONSTANT) + && x.constant().getKind().equals(CelConstant.Kind.BOOLEAN_VALUE)) + .filter(x -> !x.constant().booleanValue()) + .findAny() + .get() + .id(); + + // Act + // Perform the initial replacement. (true && true) -> cel.bind(@r0, [].exists(x, x), @r0 && @r0) + mutableAst = + AST_MUTATOR.replaceSubtreeWithNewBindMacro( + mutableAst, + variableName, + varInitAst, + resultExpr, + falseExprId, // Replace false + true); + + CelAbstractSyntaxTree mutatedAst = mutableAst.toParsedAst(); + assertThat(mutatedAst.getSource().getMacroCalls()).hasSize(3); + assertThat(CEL.createProgram(CEL.check(mutatedAst).getAst()).eval()).isEqualTo(false); + assertThat(CEL_UNPARSER.unparse(mutatedAst)) + .isEqualTo("[true].exists(y, y) && cel.bind(@r0, [].exists(x, x), @r0)"); + assertConsistentMacroCalls(mutatedAst); + } + @Test public void replaceSubtree_macroReplacedWithConstExpr_macroCallCleared() throws Exception { CelAbstractSyntaxTree ast = From cc70add6424ea1d06c6e76e3e9a123ea44ca530b Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Tue, 2 Jul 2024 17:17:45 -0700 Subject: [PATCH 145/486] Add AstMutator methods to construct function calls PiperOrigin-RevId: 648890320 --- .../java/dev/cel/optimizer/AstMutator.java | 66 +++++++++++++++++++ .../dev/cel/optimizer/AstMutatorTest.java | 23 +++++++ 2 files changed, 89 insertions(+) diff --git a/optimizer/src/main/java/dev/cel/optimizer/AstMutator.java b/optimizer/src/main/java/dev/cel/optimizer/AstMutator.java index dfcdb1a05..f9c9db9c6 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/AstMutator.java +++ b/optimizer/src/main/java/dev/cel/optimizer/AstMutator.java @@ -40,6 +40,8 @@ import dev.cel.common.navigation.TraversalOrder; import dev.cel.common.types.CelType; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; @@ -95,6 +97,70 @@ public CelMutableAst wrapAstWithNewCelBlock( return CelMutableAst.of(blockExpr, ast.source()); } + /** + * Constructs a new global call wrapped in an AST with the provided ASTs as its argument. This + * will preserve all macro source information contained within the arguments. + */ + public CelMutableAst newGlobalCall(String function, Collection args) { + return newCallAst(Optional.empty(), function, args); + } + + /** + * Constructs a new global call wrapped in an AST with the provided ASTs as its argument. This + * will preserve all macro source information contained within the arguments. + */ + public CelMutableAst newGlobalCall(String function, CelMutableAst... args) { + return newGlobalCall(function, Arrays.asList(args)); + } + + /** + * Constructs a new member call wrapped in an AST the provided ASTs as its arguments. This will + * preserve all macro source information contained within the arguments. + */ + public CelMutableAst newMemberCall(CelMutableAst target, String function, CelMutableAst... args) { + return newMemberCall(target, function, Arrays.asList(args)); + } + + /** + * Constructs a new member call wrapped in an AST the provided ASTs as its arguments. This will + * preserve all macro source information contained within the arguments. + */ + public CelMutableAst newMemberCall( + CelMutableAst target, String function, Collection args) { + return newCallAst(Optional.of(target), function, args); + } + + private CelMutableAst newCallAst( + Optional target, String function, Collection args) { + long maxId = 1; + CelMutableSource combinedSource = CelMutableSource.newInstance(); + for (CelMutableAst arg : args) { + CelMutableAst stableArg = stabilizeAst(arg, maxId); + maxId = getMaxId(stableArg); + combinedSource = combine(combinedSource, stableArg.source()); + } + + Optional maybeTarget = Optional.empty(); + if (target.isPresent()) { + CelMutableAst stableTarget = stabilizeAst(target.get(), maxId); + combinedSource = combine(combinedSource, stableTarget.source()); + maxId = getMaxId(stableTarget); + + maybeTarget = Optional.of(stableTarget); + } + + List exprArgs = + args.stream().map(CelMutableAst::expr).collect(toCollection(ArrayList::new)); + CelMutableCall newCall = + maybeTarget + .map(celMutableAst -> CelMutableCall.create(celMutableAst.expr(), function, exprArgs)) + .orElseGet(() -> CelMutableCall.create(function, exprArgs)); + + CelMutableExpr newCallExpr = CelMutableExpr.ofCall(++maxId, newCall); + + return CelMutableAst.of(newCallExpr, combinedSource); + } + /** * Generates a new bind macro using the provided initialization and result expression, then * replaces the subtree using the new bind expr at the designated expr ID. diff --git a/optimizer/src/test/java/dev/cel/optimizer/AstMutatorTest.java b/optimizer/src/test/java/dev/cel/optimizer/AstMutatorTest.java index d9d9a969e..cdfa1cb00 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/AstMutatorTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/AstMutatorTest.java @@ -1109,6 +1109,29 @@ public void replaceSubtree_iterationLimitReached_throws() throws Exception { assertThat(e).hasMessageThat().isEqualTo("Max iteration count reached."); } + @Test + public void newGlobalCallAst_success() throws Exception { + CelMutableAst argAst1 = CelMutableAst.fromCelAst(CEL.compile("[1].exists(x, x >= 1)").getAst()); + CelMutableAst argAst2 = CelMutableAst.fromCelAst(CEL.compile("'hello'").getAst()); + + CelMutableAst callAst = AST_MUTATOR.newGlobalCall("func", argAst1, argAst2); + + assertThat(CEL_UNPARSER.unparse(callAst.toParsedAst())) + .isEqualTo("func([1].exists(x, x >= 1), \"hello\")"); + } + + @Test + public void newMemberCallAst_success() throws Exception { + CelMutableAst targetAst = CelMutableAst.fromCelAst(CEL.compile("'hello'").getAst()); + CelMutableAst argAst1 = CelMutableAst.fromCelAst(CEL.compile("[1].exists(x, x >= 1)").getAst()); + CelMutableAst argAst2 = CelMutableAst.fromCelAst(CEL.compile("'world'").getAst()); + + CelMutableAst callAst = AST_MUTATOR.newMemberCall(targetAst, "func", argAst1, argAst2); + + assertThat(CEL_UNPARSER.unparse(callAst.toParsedAst())) + .isEqualTo("\"hello\".func([1].exists(x, x >= 1), \"world\")"); + } + /** * Asserts that the expressions that appears in source_info's macro calls are consistent with the * actual expr nodes in the AST. From 9fa219d072d2de7875555c46b8cf098c76484580 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Wed, 3 Jul 2024 13:13:11 -0700 Subject: [PATCH 146/486] Add Policy Compiler PiperOrigin-RevId: 649176985 --- .../java/dev/cel/optimizer/AstMutator.java | 2 +- policy/BUILD.bazel | 6 + .../src/main/java/dev/cel/policy/BUILD.bazel | 96 ++++++- .../java/dev/cel/policy/CelCompiledRule.java | 83 ++++++ .../dev/cel/policy/CelPolicyCompiler.java | 27 ++ .../cel/policy/CelPolicyCompilerBuilder.java | 28 +++ .../dev/cel/policy/CelPolicyCompilerImpl.java | 215 ++++++++++++++++ .../java/dev/cel/policy/RuleComposer.java | 135 ++++++++++ .../src/test/java/dev/cel/policy/BUILD.bazel | 7 + .../cel/policy/CelPolicyCompilerImplTest.java | 237 ++++++++++++++++++ .../java/dev/cel/policy/PolicyTestHelper.java | 120 +++++++++ policy/src/test/resources/errors/policy.yaml | 3 + 12 files changed, 951 insertions(+), 8 deletions(-) create mode 100644 policy/src/main/java/dev/cel/policy/CelCompiledRule.java create mode 100644 policy/src/main/java/dev/cel/policy/CelPolicyCompiler.java create mode 100644 policy/src/main/java/dev/cel/policy/CelPolicyCompilerBuilder.java create mode 100644 policy/src/main/java/dev/cel/policy/CelPolicyCompilerImpl.java create mode 100644 policy/src/main/java/dev/cel/policy/RuleComposer.java create mode 100644 policy/src/test/java/dev/cel/policy/CelPolicyCompilerImplTest.java diff --git a/optimizer/src/main/java/dev/cel/optimizer/AstMutator.java b/optimizer/src/main/java/dev/cel/optimizer/AstMutator.java index f9c9db9c6..aa90f1528 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/AstMutator.java +++ b/optimizer/src/main/java/dev/cel/optimizer/AstMutator.java @@ -132,7 +132,7 @@ public CelMutableAst newMemberCall( private CelMutableAst newCallAst( Optional target, String function, Collection args) { - long maxId = 1; + long maxId = 0; CelMutableSource combinedSource = CelMutableSource.newInstance(); for (CelMutableAst arg : args) { CelMutableAst stableArg = stabilizeAst(arg, maxId); diff --git a/policy/BUILD.bazel b/policy/BUILD.bazel index 8e65f4229..2781b5663 100644 --- a/policy/BUILD.bazel +++ b/policy/BUILD.bazel @@ -33,6 +33,12 @@ java_library( exports = ["//policy/src/main/java/dev/cel/policy:parser"], ) +java_library( + name = "compiler_impl", + visibility = ["//visibility:public"], + exports = ["//policy/src/main/java/dev/cel/policy:compiler_impl"], +) + java_library( name = "yaml_parser", visibility = ["//visibility:public"], diff --git a/policy/src/main/java/dev/cel/policy/BUILD.bazel b/policy/src/main/java/dev/cel/policy/BUILD.bazel index 0c718d727..bf755f2e9 100644 --- a/policy/src/main/java/dev/cel/policy/BUILD.bazel +++ b/policy/src/main/java/dev/cel/policy/BUILD.bazel @@ -89,11 +89,11 @@ java_library( "CelPolicyYamlParser.java", ], deps = [ + ":common_internal", ":parser", + ":parser_builder", ":parser_context", ":policy", - ":policy_common_internal", - ":policy_parser_builder", ":source", ":validation_exception", ":value_string", @@ -116,7 +116,7 @@ java_library( ) java_library( - name = "policy_parser_builder", + name = "parser_builder", srcs = [ "CelPolicyParserBuilder.java", ], @@ -126,18 +126,67 @@ java_library( ], ) +java_library( + name = "compiler", + srcs = [ + "CelPolicyCompiler.java", + ], + deps = [ + ":policy", + ":validation_exception", + "//common", + ], +) + +java_library( + name = "compiler_builder", + srcs = [ + "CelPolicyCompilerBuilder.java", + ], + deps = [ + ":compiler", + "@maven//:com_google_errorprone_error_prone_annotations", + ], +) + +java_library( + name = "compiler_impl", + srcs = [ + "CelPolicyCompilerImpl.java", + ], + deps = [ + ":compiled_rule", + ":compiler", + ":compiler_builder", + ":policy", + ":rule_composer", + ":source", + ":validation_exception", + ":value_string", + "//bundle:cel", + "//common", + "//common:compiler_common", + "//common/ast", + "//common/types", + "//common/types:type_providers", + "//optimizer", + "//optimizer:optimization_exception", + "//optimizer:optimizer_builder", + "@maven//:com_google_errorprone_error_prone_annotations", + "@maven//:com_google_guava_guava", + ], +) + java_library( name = "yaml_config_parser", srcs = [ "CelPolicyYamlConfigParser.java", ], - tags = [ - ], deps = [ + ":common_internal", ":config", ":config_parser", ":parser_context", - ":policy_common_internal", ":source", ":validation_exception", "//common/internal", @@ -169,6 +218,18 @@ java_library( ], ) +java_library( + name = "compiled_rule", + srcs = ["CelCompiledRule.java"], + deps = [ + "//:auto_value", + "//bundle:cel", + "//common", + "@maven//:com_google_errorprone_error_prone_annotations", + "@maven//:com_google_guava_guava", + ], +) + java_library( name = "parser_context", srcs = [ @@ -181,7 +242,28 @@ java_library( ) java_library( - name = "policy_common_internal", + name = "rule_composer", + srcs = ["RuleComposer.java"], + visibility = ["//visibility:private"], + deps = [ + ":compiled_rule", + "//:auto_value", + "//bundle:cel", + "//common", + "//common:compiler_common", + "//common:mutable_ast", + "//common/ast", + "//extensions:optional_library", + "//optimizer:ast_optimizer", + "//optimizer:mutable_ast", + "//parser:operator", + "@maven//:com_google_errorprone_error_prone_annotations", + "@maven//:com_google_guava_guava", + ], +) + +java_library( + name = "common_internal", srcs = [ "YamlHelper.java", "YamlParserContextImpl.java", diff --git a/policy/src/main/java/dev/cel/policy/CelCompiledRule.java b/policy/src/main/java/dev/cel/policy/CelCompiledRule.java new file mode 100644 index 000000000..f7ee8340d --- /dev/null +++ b/policy/src/main/java/dev/cel/policy/CelCompiledRule.java @@ -0,0 +1,83 @@ +// Copyright 2024 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.policy; + +import com.google.auto.value.AutoOneOf; +import com.google.auto.value.AutoValue; +import com.google.common.collect.ImmutableList; +import dev.cel.bundle.Cel; +import dev.cel.common.CelAbstractSyntaxTree; + +/** Abstract representation of a compiled rule. */ +@AutoValue +abstract class CelCompiledRule { + abstract ImmutableList variables(); + + abstract ImmutableList matches(); + + abstract Cel cel(); + + @AutoValue + abstract static class CelCompiledVariable { + abstract String name(); + + abstract CelAbstractSyntaxTree ast(); + + static CelCompiledVariable create(String name, CelAbstractSyntaxTree ast) { + return new AutoValue_CelCompiledRule_CelCompiledVariable(name, ast); + } + } + + @AutoValue + abstract static class CelCompiledMatch { + abstract CelAbstractSyntaxTree condition(); + + abstract Result result(); + + @AutoOneOf(CelCompiledMatch.Result.Kind.class) + abstract static class Result { + abstract CelAbstractSyntaxTree output(); + + abstract CelCompiledRule rule(); + + abstract Kind kind(); + + static Result ofOutput(CelAbstractSyntaxTree value) { + return AutoOneOf_CelCompiledRule_CelCompiledMatch_Result.output(value); + } + + static Result ofRule(CelCompiledRule value) { + return AutoOneOf_CelCompiledRule_CelCompiledMatch_Result.rule(value); + } + + enum Kind { + OUTPUT, + RULE + } + } + + static CelCompiledMatch create( + CelAbstractSyntaxTree condition, CelCompiledMatch.Result result) { + return new AutoValue_CelCompiledRule_CelCompiledMatch(condition, result); + } + } + + static CelCompiledRule create( + ImmutableList variables, + ImmutableList matches, + Cel cel) { + return new AutoValue_CelCompiledRule(variables, matches, cel); + } +} diff --git a/policy/src/main/java/dev/cel/policy/CelPolicyCompiler.java b/policy/src/main/java/dev/cel/policy/CelPolicyCompiler.java new file mode 100644 index 000000000..6a63f0389 --- /dev/null +++ b/policy/src/main/java/dev/cel/policy/CelPolicyCompiler.java @@ -0,0 +1,27 @@ +// Copyright 2024 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.policy; + +import dev.cel.common.CelAbstractSyntaxTree; + +/** Public interface for compiling CEL policies. */ +public interface CelPolicyCompiler { + + /** + * Generates a single CEL AST from a collection of policy expressions associated with a CEL + * environment. + */ + CelAbstractSyntaxTree compile(CelPolicy policy) throws CelPolicyValidationException; +} diff --git a/policy/src/main/java/dev/cel/policy/CelPolicyCompilerBuilder.java b/policy/src/main/java/dev/cel/policy/CelPolicyCompilerBuilder.java new file mode 100644 index 000000000..a56054e03 --- /dev/null +++ b/policy/src/main/java/dev/cel/policy/CelPolicyCompilerBuilder.java @@ -0,0 +1,28 @@ +// Copyright 2024 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.policy; + +import com.google.errorprone.annotations.CanIgnoreReturnValue; +import com.google.errorprone.annotations.CheckReturnValue; + +/** Interface for building an instance of {@link CelPolicyCompiler} */ +public interface CelPolicyCompilerBuilder { + + @CanIgnoreReturnValue + CelPolicyCompilerBuilder setVariablesPrefix(String prefix); + + @CheckReturnValue + CelPolicyCompiler build(); +} diff --git a/policy/src/main/java/dev/cel/policy/CelPolicyCompilerImpl.java b/policy/src/main/java/dev/cel/policy/CelPolicyCompilerImpl.java new file mode 100644 index 000000000..4fb81f42b --- /dev/null +++ b/policy/src/main/java/dev/cel/policy/CelPolicyCompilerImpl.java @@ -0,0 +1,215 @@ +// Copyright 2024 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.policy; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.collect.ImmutableList.toImmutableList; + +import com.google.common.base.Joiner; +import com.google.common.collect.ImmutableList; +import com.google.errorprone.annotations.CanIgnoreReturnValue; +import dev.cel.bundle.Cel; +import dev.cel.common.CelAbstractSyntaxTree; +import dev.cel.common.CelIssue; +import dev.cel.common.CelSource; +import dev.cel.common.CelSourceLocation; +import dev.cel.common.CelValidationException; +import dev.cel.common.CelVarDecl; +import dev.cel.common.ast.CelConstant; +import dev.cel.common.ast.CelExpr; +import dev.cel.common.types.CelType; +import dev.cel.common.types.SimpleType; +import dev.cel.optimizer.CelOptimizationException; +import dev.cel.optimizer.CelOptimizer; +import dev.cel.optimizer.CelOptimizerFactory; +import dev.cel.policy.CelCompiledRule.CelCompiledMatch; +import dev.cel.policy.CelCompiledRule.CelCompiledMatch.Result; +import dev.cel.policy.CelCompiledRule.CelCompiledVariable; +import dev.cel.policy.CelPolicy.Match; +import dev.cel.policy.CelPolicy.Variable; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +/** Package-private implementation for policy compiler. */ +final class CelPolicyCompilerImpl implements CelPolicyCompiler { + private static final String DEFAULT_VARIABLE_PREFIX = "variables."; + private final Cel cel; + private final String variablesPrefix; + + @Override + public CelAbstractSyntaxTree compile(CelPolicy policy) throws CelPolicyValidationException { + CompilerContext compilerContext = new CompilerContext(policy.policySource()); + CelCompiledRule compiledRule = compileRule(policy.rule(), cel, compilerContext); + if (compilerContext.hasError()) { + throw new CelPolicyValidationException(compilerContext.getIssueString()); + } + + CelOptimizer optimizer = + CelOptimizerFactory.standardCelOptimizerBuilder(compiledRule.cel()) + .addAstOptimizers( + RuleComposer.newInstance( + compiledRule, compilerContext.newVariableDeclarations, variablesPrefix)) + .build(); + + CelAbstractSyntaxTree ast; + + try { + // This is a minimal expression used as a basis of stitching together all the rules into a + // single graph. + ast = cel.compile("true").getAst(); + ast = optimizer.optimize(ast); + } catch (CelValidationException | CelOptimizationException e) { + // TODO: Surface these errors better + throw new CelPolicyValidationException("Failed composing the rules", e); + } + + return ast; + } + + private CelCompiledRule compileRule( + CelPolicy.Rule rule, Cel ruleCel, CompilerContext compilerContext) { + ImmutableList.Builder variableBuilder = ImmutableList.builder(); + for (Variable variable : rule.variables()) { + ValueString expression = variable.expression(); + CelAbstractSyntaxTree varAst; + CelType outputType = SimpleType.DYN; + try { + varAst = ruleCel.compile(expression.value()).getAst(); + outputType = varAst.getResultType(); + } catch (CelValidationException e) { + compilerContext.addIssue(expression.id(), e.getErrors()); + // A sentinel AST representing an error is created to allow compiler checks to continue + varAst = newErrorAst(); + } + String variableName = variable.name().value(); + CelVarDecl newVariable = + CelVarDecl.newVarDeclaration(variablesPrefix + variableName, outputType); + compilerContext.addNewVarDecl(newVariable); + ruleCel = ruleCel.toCelBuilder().addVarDeclarations(newVariable).build(); + variableBuilder.add(CelCompiledVariable.create(variableName, varAst)); + } + + ImmutableList.Builder matchBuilder = ImmutableList.builder(); + for (Match match : rule.matches()) { + CelAbstractSyntaxTree conditionAst; + try { + conditionAst = ruleCel.compile(match.condition().value()).getAst(); + } catch (CelValidationException e) { + compilerContext.addIssue(match.condition().id(), e.getErrors()); + continue; + } + + Result matchResult; + switch (match.result().kind()) { + case OUTPUT: + CelAbstractSyntaxTree outputAst; + try { + outputAst = ruleCel.compile(match.result().output().value()).getAst(); + } catch (CelValidationException e) { + compilerContext.addIssue(match.result().output().id(), e.getErrors()); + continue; + } + + matchResult = Result.ofOutput(outputAst); + break; + case RULE: + CelCompiledRule nestedRule = compileRule(match.result().rule(), ruleCel, compilerContext); + matchResult = Result.ofRule(nestedRule); + break; + default: + throw new IllegalArgumentException("Unexpected kind: " + match.result().kind()); + } + + matchBuilder.add(CelCompiledMatch.create(conditionAst, matchResult)); + } + + return CelCompiledRule.create(variableBuilder.build(), matchBuilder.build(), cel); + } + + private static CelAbstractSyntaxTree newErrorAst() { + return CelAbstractSyntaxTree.newParsedAst( + CelExpr.ofConstant(0, CelConstant.ofValue("*error*")), CelSource.newBuilder().build()); + } + + private static final class CompilerContext { + private static final Joiner JOINER = Joiner.on('\n'); + private final ArrayList issues; + private final ArrayList newVariableDeclarations; + private final CelPolicySource celPolicySource; + + private void addIssue(long id, List issues) { + for (CelIssue issue : issues) { + // Compute relative source and add them into the issues set + int position = Optional.ofNullable(celPolicySource.getPositionsMap().get(id)).orElse(-1); + position += issue.getSourceLocation().getColumn(); + CelSourceLocation loc = + celPolicySource.getOffsetLocation(position).orElse(CelSourceLocation.NONE); + this.issues.add(CelIssue.formatError(loc, issue.getMessage())); + } + } + + private void addNewVarDecl(CelVarDecl newVarDecl) { + newVariableDeclarations.add(newVarDecl); + } + + private boolean hasError() { + return !issues.isEmpty(); + } + + private String getIssueString() { + return JOINER.join( + issues.stream() + .map(iss -> iss.toDisplayString(celPolicySource)) + .collect(toImmutableList())); + } + + private CompilerContext(CelPolicySource celPolicySource) { + this.issues = new ArrayList<>(); + this.newVariableDeclarations = new ArrayList<>(); + this.celPolicySource = celPolicySource; + } + } + + static final class Builder implements CelPolicyCompilerBuilder { + private final Cel cel; + private String variablesPrefix; + + private Builder(Cel cel) { + this.cel = cel; + } + + @Override + @CanIgnoreReturnValue + public Builder setVariablesPrefix(String prefix) { + this.variablesPrefix = checkNotNull(prefix); + return this; + } + + @Override + public CelPolicyCompiler build() { + return new CelPolicyCompilerImpl(cel, this.variablesPrefix); + } + } + + static Builder newBuilder(Cel cel) { + return new Builder(cel).setVariablesPrefix(DEFAULT_VARIABLE_PREFIX); + } + + private CelPolicyCompilerImpl(Cel cel, String variablesPrefix) { + this.cel = checkNotNull(cel); + this.variablesPrefix = checkNotNull(variablesPrefix); + } +} diff --git a/policy/src/main/java/dev/cel/policy/RuleComposer.java b/policy/src/main/java/dev/cel/policy/RuleComposer.java new file mode 100644 index 000000000..9650b04a7 --- /dev/null +++ b/policy/src/main/java/dev/cel/policy/RuleComposer.java @@ -0,0 +1,135 @@ +// Copyright 2024 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.policy; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.auto.value.AutoValue; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; +import dev.cel.bundle.Cel; +import dev.cel.common.CelAbstractSyntaxTree; +import dev.cel.common.CelMutableAst; +import dev.cel.common.CelVarDecl; +import dev.cel.common.ast.CelConstant.Kind; +import dev.cel.extensions.CelOptionalLibrary.Function; +import dev.cel.optimizer.AstMutator; +import dev.cel.optimizer.CelAstOptimizer; +import dev.cel.parser.Operator; +import dev.cel.policy.CelCompiledRule.CelCompiledMatch; +import dev.cel.policy.CelCompiledRule.CelCompiledVariable; +import java.util.List; + +/** Package-private class for composing various rules into a single expression using optimizer. */ +final class RuleComposer implements CelAstOptimizer { + private static final int AST_MUTATOR_ITERATION_LIMIT = 1000; + private final CelCompiledRule compiledRule; + private final ImmutableList newVarDecls; + private final String variablePrefix; + private final AstMutator astMutator; + + @Override + public OptimizationResult optimize(CelAbstractSyntaxTree ast, Cel cel) { + RuleOptimizationResult result = optimizeRule(compiledRule); + return OptimizationResult.create(result.ast().toParsedAst(), newVarDecls, ImmutableList.of()); + } + + @AutoValue + abstract static class RuleOptimizationResult { + abstract CelMutableAst ast(); + + abstract Boolean isOptionalResult(); + + static RuleOptimizationResult create(CelMutableAst ast, boolean isOptionalResult) { + return new AutoValue_RuleComposer_RuleOptimizationResult(ast, isOptionalResult); + } + } + + private RuleOptimizationResult optimizeRule(CelCompiledRule compiledRule) { + CelMutableAst matchAst = astMutator.newGlobalCall(Function.OPTIONAL_NONE.getFunction()); + boolean isOptionalResult = true; + for (CelCompiledMatch match : Lists.reverse(compiledRule.matches())) { + CelAbstractSyntaxTree conditionAst = match.condition(); + boolean isTriviallyTrue = + conditionAst.getExpr().constantOrDefault().getKind().equals(Kind.BOOLEAN_VALUE) + && conditionAst.getExpr().constant().booleanValue(); + switch (match.result().kind()) { + case OUTPUT: + CelMutableAst outAst = CelMutableAst.fromCelAst(match.result().output()); + if (isTriviallyTrue) { + matchAst = outAst; + isOptionalResult = false; + continue; + } + if (isOptionalResult) { + outAst = astMutator.newGlobalCall(Function.OPTIONAL_OF.getFunction(), outAst); + } + + matchAst = + astMutator.newGlobalCall( + Operator.CONDITIONAL.getFunction(), + CelMutableAst.fromCelAst(conditionAst), + outAst, + matchAst); + continue; + case RULE: + RuleOptimizationResult nestedRule = optimizeRule(match.result().rule()); + CelMutableAst nestedRuleAst = nestedRule.ast(); + if (isOptionalResult && !nestedRule.isOptionalResult()) { + nestedRuleAst = + astMutator.newGlobalCall(Function.OPTIONAL_OF.getFunction(), nestedRuleAst); + } + if (!isOptionalResult && nestedRule.isOptionalResult()) { + matchAst = astMutator.newGlobalCall(Function.OPTIONAL_OF.getFunction(), matchAst); + isOptionalResult = true; + } + if (!isOptionalResult && !nestedRule.isOptionalResult()) { + throw new IllegalArgumentException("Subrule early terminates policy"); + } + matchAst = astMutator.newMemberCall(nestedRuleAst, Function.OR.getFunction(), matchAst); + break; + } + } + + CelMutableAst result = matchAst; + for (CelCompiledVariable variable : Lists.reverse(compiledRule.variables())) { + result = + astMutator.replaceSubtreeWithNewBindMacro( + result, + variablePrefix + variable.name(), + CelMutableAst.fromCelAst(variable.ast()), + result.expr(), + result.expr().id(), + true); + } + + result = astMutator.renumberIdsConsecutively(result); + + return RuleOptimizationResult.create(result, isOptionalResult); + } + + static RuleComposer newInstance( + CelCompiledRule compiledRule, List newVarDecls, String variablePrefix) { + return new RuleComposer(compiledRule, newVarDecls, variablePrefix); + } + + private RuleComposer( + CelCompiledRule compiledRule, List newVarDecls, String variablePrefix) { + this.compiledRule = checkNotNull(compiledRule); + this.newVarDecls = ImmutableList.copyOf(checkNotNull(newVarDecls)); + this.variablePrefix = variablePrefix; + this.astMutator = AstMutator.newInstance(AST_MUTATOR_ITERATION_LIMIT); + } +} diff --git a/policy/src/test/java/dev/cel/policy/BUILD.bazel b/policy/src/test/java/dev/cel/policy/BUILD.bazel index 38e88e5f4..1d863c77e 100644 --- a/policy/src/test/java/dev/cel/policy/BUILD.bazel +++ b/policy/src/test/java/dev/cel/policy/BUILD.bazel @@ -12,9 +12,14 @@ java_library( deps = [ "//:java_truth", "//bundle:cel", + "//common", "//common:options", "//common/internal", + "//extensions:optional_library", + "//parser:macro", + "//parser:unparser", "//policy", + "//policy:compiler_impl", "//policy:config", "//policy:config_parser", "//policy:parser", @@ -22,10 +27,12 @@ java_library( "//policy:validation_exception", "//policy:yaml_config_parser", "//policy:yaml_parser", + "//runtime", "@maven//:com_google_api_grpc_proto_google_common_protos", "@maven//:com_google_guava_guava", "@maven//:com_google_testparameterinjector_test_parameter_injector", "@maven//:junit_junit", + "@maven//:org_yaml_snakeyaml", ], ) diff --git a/policy/src/test/java/dev/cel/policy/CelPolicyCompilerImplTest.java b/policy/src/test/java/dev/cel/policy/CelPolicyCompilerImplTest.java new file mode 100644 index 000000000..f835e90fe --- /dev/null +++ b/policy/src/test/java/dev/cel/policy/CelPolicyCompilerImplTest.java @@ -0,0 +1,237 @@ +// Copyright 2024 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.policy; + +import static com.google.common.collect.ImmutableMap.toImmutableMap; +import static com.google.common.truth.Truth.assertThat; +import static dev.cel.policy.PolicyTestHelper.readFromYaml; +import static org.junit.Assert.assertThrows; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.testing.junit.testparameterinjector.TestParameter; +import com.google.testing.junit.testparameterinjector.TestParameterInjector; +import com.google.testing.junit.testparameterinjector.TestParameterValue; +import com.google.testing.junit.testparameterinjector.TestParameterValuesProvider; +import dev.cel.bundle.Cel; +import dev.cel.bundle.CelFactory; +import dev.cel.common.CelAbstractSyntaxTree; +import dev.cel.common.CelOptions; +import dev.cel.extensions.CelOptionalLibrary; +import dev.cel.parser.CelStandardMacro; +import dev.cel.parser.CelUnparserFactory; +import dev.cel.policy.PolicyTestHelper.PolicyTestSuite; +import dev.cel.policy.PolicyTestHelper.PolicyTestSuite.PolicyTestSection; +import dev.cel.policy.PolicyTestHelper.PolicyTestSuite.PolicyTestSection.PolicyTestCase; +import dev.cel.policy.PolicyTestHelper.TestYamlPolicy; +import dev.cel.runtime.CelRuntime.CelFunctionBinding; +import java.util.Map.Entry; +import java.util.Optional; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(TestParameterInjector.class) +public final class CelPolicyCompilerImplTest { + + private static final CelPolicyParser POLICY_PARSER = CelPolicyYamlParser.newBuilder().build(); + private static final CelPolicyConfigParser POLICY_CONFIG_PARSER = + CelPolicyYamlConfigParser.newInstance(); + + private static final CelOptions CEL_OPTIONS = + CelOptions.current().populateMacroCalls(true).build(); + + @Test + public void compileYamlPolicy_success(@TestParameter TestYamlPolicy yamlPolicy) throws Exception { + // Read config and produce an environment to compile policies + String configSource = yamlPolicy.readConfigYamlContent(); + CelPolicyConfig policyConfig = POLICY_CONFIG_PARSER.parse(configSource); + Cel cel = policyConfig.extend(newCel(), CEL_OPTIONS); + // Read the policy source + String policySource = yamlPolicy.readPolicyYamlContent(); + CelPolicy policy = POLICY_PARSER.parse(policySource); + + CelAbstractSyntaxTree ast = CelPolicyCompilerImpl.newBuilder(cel).build().compile(policy); + + assertThat(CelUnparserFactory.newUnparser().unparse(ast)).isEqualTo(yamlPolicy.getUnparsed()); + } + + @Test + public void compileYamlPolicy_containsError_throws() throws Exception { + // Read config and produce an environment to compile policies + String configSource = readFromYaml("errors/config.yaml"); + CelPolicyConfig policyConfig = POLICY_CONFIG_PARSER.parse(configSource); + Cel cel = policyConfig.extend(newCel(), CEL_OPTIONS); + // Read the policy source + String policyFilePath = "errors/policy.yaml"; + String policySource = readFromYaml(policyFilePath); + CelPolicy policy = POLICY_PARSER.parse(policySource, policyFilePath); + + CelPolicyValidationException e = + assertThrows( + CelPolicyValidationException.class, + () -> CelPolicyCompilerImpl.newBuilder(cel).build().compile(policy)); + + assertThat(e) + .hasMessageThat() + .isEqualTo( + "ERROR: errors/policy.yaml:19:19: undeclared reference to 'spec' (in container '')\n" + + " | expression: spec.labels\n" + + " | ..................^\n" + + "ERROR: errors/policy.yaml:21:50: mismatched input 'resource' expecting {'=='," + + " '!=', 'in', '<', '<=', '>=', '>', '&&', '||', '[', '(', ')', '.', '-', '?'," + + " '+', '*', '/', '%%'}\n" + + " | expression: variables.want.filter(l, !(lin resource.labels))\n" + + " | .................................................^\n" + + "ERROR: errors/policy.yaml:21:66: extraneous input ')' expecting \n" + + " | expression: variables.want.filter(l, !(lin resource.labels))\n" + + " | .................................................................^\n" + + "ERROR: errors/policy.yaml:23:27: mismatched input '2' expecting {'}', ','}\n" + + " | expression: \"{1:305 2:569}\"\n" + + " | ..........................^\n" + + "ERROR: errors/policy.yaml:31:65: extraneous input ']' expecting ')'\n" + + " | \"missing one or more required labels:" + + " %s\".format(variables.missing])\n" + + " | ................................................................^\n" + + "ERROR: errors/policy.yaml:34:57: undeclared reference to 'format' (in container" + + " '')\n" + + " | \"invalid values provided on one or more labels:" + + " %s\".format([variables.invalid])\n" + + " | ........................................................^\n" + + "ERROR: errors/policy.yaml:35:24: found no matching overload for '_==_' applied" + + " to '(bool, string)' (candidates: (%A0, %A0))\n" + + " | - condition: false == \"0\"\n" + + " | .......................^"); + } + + @Test + @SuppressWarnings("unchecked") + public void evaluateYamlPolicy_withCanonicalTestData( + @TestParameter(valuesProvider = EvaluablePolicyTestDataProvider.class) + EvaluablePolicyTestData testData) + throws Exception { + // Setup + // Read config and produce an environment to compile policies + String configSource = testData.yamlPolicy.readConfigYamlContent(); + CelPolicyConfig policyConfig = POLICY_CONFIG_PARSER.parse(configSource); + Cel cel = policyConfig.extend(newCel(), CEL_OPTIONS); + // Read the policy source + String policySource = testData.yamlPolicy.readPolicyYamlContent(); + CelPolicy policy = POLICY_PARSER.parse(policySource); + CelAbstractSyntaxTree expectedOutputAst = cel.compile(testData.testCase.getOutput()).getAst(); + Object expectedOutput = cel.createProgram(expectedOutputAst).eval(); + + // Act + // Compile then evaluate the policy + CelAbstractSyntaxTree compiledPolicyAst = + CelPolicyCompilerImpl.newBuilder(cel).build().compile(policy); + ImmutableMap input = + testData.testCase.getInput().entrySet().stream() + .collect(toImmutableMap(Entry::getKey, e -> e.getValue().getValue())); + Object evalResult = cel.createProgram(compiledPolicyAst).eval(input); + + // Assert + // Note that policies may either produce an optional or a non-optional result, + // if all the rules included nested ones can always produce a default result when none of the + // condition matches + if (testData.yamlPolicy.producesOptionalResult()) { + Optional policyOutput = (Optional) evalResult; + if (policyOutput.isPresent()) { + assertThat(policyOutput).hasValue(expectedOutput); + } else { + assertThat(policyOutput).isEmpty(); + } + } else { + assertThat(evalResult).isEqualTo(expectedOutput); + } + } + + @Test + @SuppressWarnings("unchecked") + public void evaluateYamlPolicy_nestedRuleProducesOptionalOutput() throws Exception { + Cel cel = newCel(); + String policySource = + "name: nested_rule_with_optional_result\n" + + "rule:\n" + + " match:\n" + + " - rule:\n" + + " match:\n" + + " - condition: 'true'\n" + + " output: 'optional.of(true)'\n"; + CelPolicy policy = POLICY_PARSER.parse(policySource); + CelAbstractSyntaxTree compiledPolicyAst = + CelPolicyCompilerImpl.newBuilder(cel).build().compile(policy); + + Optional evalResult = (Optional) cel.createProgram(compiledPolicyAst).eval(); + + // Result is Optional> + assertThat(evalResult).hasValue(Optional.of(true)); + } + + private static final class EvaluablePolicyTestData { + private final TestYamlPolicy yamlPolicy; + private final PolicyTestCase testCase; + + private EvaluablePolicyTestData(TestYamlPolicy yamlPolicy, PolicyTestCase testCase) { + this.yamlPolicy = yamlPolicy; + this.testCase = testCase; + } + } + + private static final class EvaluablePolicyTestDataProvider extends TestParameterValuesProvider { + + @Override + protected ImmutableList provideValues(Context context) throws Exception { + ImmutableList.Builder builder = ImmutableList.builder(); + for (TestYamlPolicy yamlPolicy : TestYamlPolicy.values()) { + PolicyTestSuite testSuite = yamlPolicy.readTestYamlContent(); + for (PolicyTestSection testSection : testSuite.getSection()) { + for (PolicyTestCase testCase : testSection.getTests()) { + String testName = + String.format( + "%s %s %s", + yamlPolicy.getPolicyName(), testSection.getName(), testCase.getName()); + builder.add( + value(new EvaluablePolicyTestData(yamlPolicy, testCase)).withName(testName)); + } + } + } + + return builder.build(); + } + } + + private static Cel newCel() { + return CelFactory.standardCelBuilder() + .setStandardMacros(CelStandardMacro.STANDARD_MACROS) + .addCompilerLibraries(CelOptionalLibrary.INSTANCE) + .addRuntimeLibraries(CelOptionalLibrary.INSTANCE) + .setOptions(CEL_OPTIONS) + .addFunctionBindings( + CelFunctionBinding.from( + "locationCode_string", + String.class, + (ip) -> { + switch (ip) { + case "10.0.0.1": + return "us"; + case "10.0.0.2": + return "de"; + default: + return "ir"; + } + })) + .build(); + } +} diff --git a/policy/src/test/java/dev/cel/policy/PolicyTestHelper.java b/policy/src/test/java/dev/cel/policy/PolicyTestHelper.java index c04d15440..ed1b94a66 100644 --- a/policy/src/test/java/dev/cel/policy/PolicyTestHelper.java +++ b/policy/src/test/java/dev/cel/policy/PolicyTestHelper.java @@ -16,10 +16,16 @@ import static java.nio.charset.StandardCharsets.UTF_8; +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Ascii; import com.google.common.io.Resources; import java.io.IOException; import java.net.URL; +import java.util.List; +import java.util.Map; +import org.yaml.snakeyaml.LoaderOptions; +import org.yaml.snakeyaml.Yaml; +import org.yaml.snakeyaml.constructor.Constructor; /** Package-private class to assist with policy testing. */ final class PolicyTestHelper { @@ -87,12 +93,126 @@ String getUnparsed() { String readPolicyYamlContent() throws IOException { return readFromYaml(String.format("%s/policy.yaml", name)); } + + String readConfigYamlContent() throws IOException { + return readFromYaml(String.format("%s/config.yaml", name)); + } + + PolicyTestSuite readTestYamlContent() throws IOException { + Yaml yaml = new Yaml(new Constructor(PolicyTestSuite.class, new LoaderOptions())); + String testContent = readFile(String.format("%s/tests.yaml", name)); + + return yaml.load(testContent); + } } static String readFromYaml(String yamlPath) throws IOException { return readFile(yamlPath); } + /** + * TestSuite describes a set of tests divided by section. + * + *

Visibility must be public for YAML deserialization to work. This is effectively + * package-private since the outer class is. + */ + @VisibleForTesting + public static final class PolicyTestSuite { + private String description; + private List section; + + public void setDescription(String description) { + this.description = description; + } + + public void setSection(List section) { + this.section = section; + } + + public String getDescription() { + return description; + } + + public List getSection() { + return section; + } + + @VisibleForTesting + public static final class PolicyTestSection { + private String name; + private List tests; + + public void setName(String name) { + this.name = name; + } + + public void setTests(List tests) { + this.tests = tests; + } + + public String getName() { + return name; + } + + public List getTests() { + return tests; + } + + @VisibleForTesting + public static final class PolicyTestCase { + private String name; + private Map input; + private String output; + + public void setName(String name) { + this.name = name; + } + + public void setInput(Map input) { + this.input = input; + } + + public void setOutput(String output) { + this.output = output; + } + + public String getName() { + return name; + } + + public Map getInput() { + return input; + } + + public String getOutput() { + return output; + } + + @VisibleForTesting + public static final class PolicyTestInput { + private Object value; + private String expr; + + public Object getValue() { + return value; + } + + public void setValue(Object value) { + this.value = value; + } + + public String getExpr() { + return expr; + } + + public void setExpr(String expr) { + this.expr = expr; + } + } + } + } + } + private static URL getResource(String path) { return Resources.getResource(Ascii.toLowerCase(path)); } diff --git a/policy/src/test/resources/errors/policy.yaml b/policy/src/test/resources/errors/policy.yaml index 338ba3995..e322e8a83 100644 --- a/policy/src/test/resources/errors/policy.yaml +++ b/policy/src/test/resources/errors/policy.yaml @@ -32,3 +32,6 @@ rule: - condition: variables.invalid.size() > 0 output: | "invalid values provided on one or more labels: %s".format([variables.invalid]) + - condition: false == "0" + output: | + "wrong type" From 29f344b4348c6611ce7aa8a1976d0800649693fe Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Wed, 3 Jul 2024 13:27:05 -0700 Subject: [PATCH 147/486] Add factories for policy parser and policy compiler PiperOrigin-RevId: 649181111 --- policy/BUILD.bazel | 16 ++----- .../src/main/java/dev/cel/policy/BUILD.bazel | 27 +++++++++++ .../cel/policy/CelPolicyCompilerFactory.java | 46 ++++++++++++++++++ .../cel/policy/CelPolicyParserFactory.java | 39 +++++++++++++++ .../src/test/java/dev/cel/policy/BUILD.bazel | 7 +-- .../policy/CelPolicyCompilerFactoryTest.java | 47 +++++++++++++++++++ .../cel/policy/CelPolicyCompilerImplTest.java | 15 +++--- .../policy/CelPolicyYamlConfigParserTest.java | 2 +- .../cel/policy/CelPolicyYamlParserTest.java | 3 +- 9 files changed, 178 insertions(+), 24 deletions(-) create mode 100644 policy/src/main/java/dev/cel/policy/CelPolicyCompilerFactory.java create mode 100644 policy/src/main/java/dev/cel/policy/CelPolicyParserFactory.java create mode 100644 policy/src/test/java/dev/cel/policy/CelPolicyCompilerFactoryTest.java diff --git a/policy/BUILD.bazel b/policy/BUILD.bazel index 2781b5663..ab45214bf 100644 --- a/policy/BUILD.bazel +++ b/policy/BUILD.bazel @@ -34,19 +34,11 @@ java_library( ) java_library( - name = "compiler_impl", - visibility = ["//visibility:public"], - exports = ["//policy/src/main/java/dev/cel/policy:compiler_impl"], + name = "parser_factory", + exports = ["//policy/src/main/java/dev/cel/policy:parser_factory"], ) java_library( - name = "yaml_parser", - visibility = ["//visibility:public"], - exports = ["//policy/src/main/java/dev/cel/policy:yaml_parser"], -) - -java_library( - name = "yaml_config_parser", - visibility = ["//visibility:public"], - exports = ["//policy/src/main/java/dev/cel/policy:yaml_config_parser"], + name = "compiler_factory", + exports = ["//policy/src/main/java/dev/cel/policy:compiler_factory"], ) diff --git a/policy/src/main/java/dev/cel/policy/BUILD.bazel b/policy/src/main/java/dev/cel/policy/BUILD.bazel index bf755f2e9..3ac84d7e4 100644 --- a/policy/src/main/java/dev/cel/policy/BUILD.bazel +++ b/policy/src/main/java/dev/cel/policy/BUILD.bazel @@ -83,6 +83,18 @@ java_library( ], ) +java_library( + name = "parser_factory", + srcs = ["CelPolicyParserFactory.java"], + deps = [ + ":config_parser", + ":parser_builder", + ":yaml_config_parser", + ":yaml_parser", + "@maven//:org_yaml_snakeyaml", + ], +) + java_library( name = "yaml_parser", srcs = [ @@ -177,6 +189,21 @@ java_library( ], ) +java_library( + name = "compiler_factory", + srcs = ["CelPolicyCompilerFactory.java"], + deps = [ + ":compiler_builder", + ":compiler_impl", + "//bundle:cel", + "//checker:checker_builder", + "//compiler", + "//compiler:compiler_builder", + "//parser:parser_builder", + "//runtime", + ], +) + java_library( name = "yaml_config_parser", srcs = [ diff --git a/policy/src/main/java/dev/cel/policy/CelPolicyCompilerFactory.java b/policy/src/main/java/dev/cel/policy/CelPolicyCompilerFactory.java new file mode 100644 index 000000000..8641e5bb7 --- /dev/null +++ b/policy/src/main/java/dev/cel/policy/CelPolicyCompilerFactory.java @@ -0,0 +1,46 @@ +// Copyright 2024 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.policy; + +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 producing policy compilers. */ +public final class CelPolicyCompilerFactory { + + /** Create a builder for constructing a {@link CelPolicyCompiler} instance. */ + public static CelPolicyCompilerBuilder newPolicyCompiler(Cel cel) { + return CelPolicyCompilerImpl.newBuilder(cel); + } + + /** Create a builder for constructing a {@link CelPolicyCompiler} instance. */ + public static CelPolicyCompilerBuilder newPolicyCompiler( + CelCompiler celCompiler, CelRuntime celRuntime) { + return newPolicyCompiler(CelFactory.combine(celCompiler, celRuntime)); + } + + /** Create a builder for constructing a {@link CelPolicyCompiler} instance. */ + public static CelPolicyCompilerBuilder newPolicyCompiler( + CelParser celParser, CelChecker celChecker, CelRuntime celRuntime) { + return newPolicyCompiler(CelCompilerFactory.combine(celParser, celChecker), celRuntime); + } + + private CelPolicyCompilerFactory() {} +} diff --git a/policy/src/main/java/dev/cel/policy/CelPolicyParserFactory.java b/policy/src/main/java/dev/cel/policy/CelPolicyParserFactory.java new file mode 100644 index 000000000..3897bef41 --- /dev/null +++ b/policy/src/main/java/dev/cel/policy/CelPolicyParserFactory.java @@ -0,0 +1,39 @@ +// Copyright 2024 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.policy; + +import org.yaml.snakeyaml.nodes.Node; + +/** Factory class for producing policy parser and policy config parsers. */ +public final class CelPolicyParserFactory { + + /** + * Configure a builder to construct a {@link CelPolicyParser} instance that takes in a YAML + * document. + */ + public static CelPolicyParserBuilder newYamlParserBuilder() { + return CelPolicyYamlParser.newBuilder(); + } + + /** + * Configure a builder to construct a {@link CelPolicyConfigParser} instance that takes in a YAML + * document. + */ + public static CelPolicyConfigParser newYamlConfigParser() { + return CelPolicyYamlConfigParser.newInstance(); + } + + private CelPolicyParserFactory() {} +} diff --git a/policy/src/test/java/dev/cel/policy/BUILD.bazel b/policy/src/test/java/dev/cel/policy/BUILD.bazel index 1d863c77e..05154b7e6 100644 --- a/policy/src/test/java/dev/cel/policy/BUILD.bazel +++ b/policy/src/test/java/dev/cel/policy/BUILD.bazel @@ -15,18 +15,19 @@ java_library( "//common", "//common:options", "//common/internal", + "//compiler", "//extensions:optional_library", + "//parser", "//parser:macro", "//parser:unparser", "//policy", - "//policy:compiler_impl", + "//policy:compiler_factory", "//policy:config", "//policy:config_parser", "//policy:parser", + "//policy:parser_factory", "//policy:source", "//policy:validation_exception", - "//policy:yaml_config_parser", - "//policy:yaml_parser", "//runtime", "@maven//:com_google_api_grpc_proto_google_common_protos", "@maven//:com_google_guava_guava", diff --git a/policy/src/test/java/dev/cel/policy/CelPolicyCompilerFactoryTest.java b/policy/src/test/java/dev/cel/policy/CelPolicyCompilerFactoryTest.java new file mode 100644 index 000000000..1f323256b --- /dev/null +++ b/policy/src/test/java/dev/cel/policy/CelPolicyCompilerFactoryTest.java @@ -0,0 +1,47 @@ +// Copyright 2024 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.policy; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.testing.junit.testparameterinjector.TestParameterInjector; +import dev.cel.compiler.CelCompilerFactory; +import dev.cel.parser.CelParserFactory; +import dev.cel.runtime.CelRuntimeFactory; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(TestParameterInjector.class) +public final class CelPolicyCompilerFactoryTest { + + @Test + public void newPolicyCompiler_compilerRuntimeCombined() { + assertThat( + CelPolicyCompilerFactory.newPolicyCompiler( + CelCompilerFactory.standardCelCompilerBuilder().build(), + CelRuntimeFactory.standardCelRuntimeBuilder().build())) + .isNotNull(); + } + + @Test + public void newPolicyCompiler_parserCheckerRuntimeCombined() { + assertThat( + CelPolicyCompilerFactory.newPolicyCompiler( + CelParserFactory.standardCelParserBuilder().build(), + CelCompilerFactory.standardCelCheckerBuilder().build(), + CelRuntimeFactory.standardCelRuntimeBuilder().build())) + .isNotNull(); + } +} diff --git a/policy/src/test/java/dev/cel/policy/CelPolicyCompilerImplTest.java b/policy/src/test/java/dev/cel/policy/CelPolicyCompilerImplTest.java index f835e90fe..41cefcae1 100644 --- a/policy/src/test/java/dev/cel/policy/CelPolicyCompilerImplTest.java +++ b/policy/src/test/java/dev/cel/policy/CelPolicyCompilerImplTest.java @@ -45,10 +45,10 @@ @RunWith(TestParameterInjector.class) public final class CelPolicyCompilerImplTest { - private static final CelPolicyParser POLICY_PARSER = CelPolicyYamlParser.newBuilder().build(); + private static final CelPolicyParser POLICY_PARSER = + CelPolicyParserFactory.newYamlParserBuilder().build(); private static final CelPolicyConfigParser POLICY_CONFIG_PARSER = - CelPolicyYamlConfigParser.newInstance(); - + CelPolicyParserFactory.newYamlConfigParser(); private static final CelOptions CEL_OPTIONS = CelOptions.current().populateMacroCalls(true).build(); @@ -62,7 +62,8 @@ public void compileYamlPolicy_success(@TestParameter TestYamlPolicy yamlPolicy) String policySource = yamlPolicy.readPolicyYamlContent(); CelPolicy policy = POLICY_PARSER.parse(policySource); - CelAbstractSyntaxTree ast = CelPolicyCompilerImpl.newBuilder(cel).build().compile(policy); + CelAbstractSyntaxTree ast = + CelPolicyCompilerFactory.newPolicyCompiler(cel).build().compile(policy); assertThat(CelUnparserFactory.newUnparser().unparse(ast)).isEqualTo(yamlPolicy.getUnparsed()); } @@ -81,7 +82,7 @@ public void compileYamlPolicy_containsError_throws() throws Exception { CelPolicyValidationException e = assertThrows( CelPolicyValidationException.class, - () -> CelPolicyCompilerImpl.newBuilder(cel).build().compile(policy)); + () -> CelPolicyCompilerFactory.newPolicyCompiler(cel).build().compile(policy)); assertThat(e) .hasMessageThat() @@ -135,7 +136,7 @@ public void evaluateYamlPolicy_withCanonicalTestData( // Act // Compile then evaluate the policy CelAbstractSyntaxTree compiledPolicyAst = - CelPolicyCompilerImpl.newBuilder(cel).build().compile(policy); + CelPolicyCompilerFactory.newPolicyCompiler(cel).build().compile(policy); ImmutableMap input = testData.testCase.getInput().entrySet().stream() .collect(toImmutableMap(Entry::getKey, e -> e.getValue().getValue())); @@ -171,7 +172,7 @@ public void evaluateYamlPolicy_nestedRuleProducesOptionalOutput() throws Excepti + " output: 'optional.of(true)'\n"; CelPolicy policy = POLICY_PARSER.parse(policySource); CelAbstractSyntaxTree compiledPolicyAst = - CelPolicyCompilerImpl.newBuilder(cel).build().compile(policy); + CelPolicyCompilerFactory.newPolicyCompiler(cel).build().compile(policy); Optional evalResult = (Optional) cel.createProgram(compiledPolicyAst).eval(); diff --git a/policy/src/test/java/dev/cel/policy/CelPolicyYamlConfigParserTest.java b/policy/src/test/java/dev/cel/policy/CelPolicyYamlConfigParserTest.java index 235126270..6da658729 100644 --- a/policy/src/test/java/dev/cel/policy/CelPolicyYamlConfigParserTest.java +++ b/policy/src/test/java/dev/cel/policy/CelPolicyYamlConfigParserTest.java @@ -41,7 +41,7 @@ public final class CelPolicyYamlConfigParserTest { .build(); private static final CelPolicyConfigParser POLICY_CONFIG_PARSER = - CelPolicyYamlConfigParser.newInstance(); + CelPolicyParserFactory.newYamlConfigParser(); @Test public void config_setBasicProperties() throws Exception { diff --git a/policy/src/test/java/dev/cel/policy/CelPolicyYamlParserTest.java b/policy/src/test/java/dev/cel/policy/CelPolicyYamlParserTest.java index fc19d8f0c..6a7cfc800 100644 --- a/policy/src/test/java/dev/cel/policy/CelPolicyYamlParserTest.java +++ b/policy/src/test/java/dev/cel/policy/CelPolicyYamlParserTest.java @@ -26,7 +26,8 @@ @RunWith(TestParameterInjector.class) public final class CelPolicyYamlParserTest { - private static final CelPolicyParser POLICY_PARSER = CelPolicyYamlParser.newBuilder().build(); + private static final CelPolicyParser POLICY_PARSER = + CelPolicyParserFactory.newYamlParserBuilder().build(); @Test public void parseYamlPolicy_success(@TestParameter TestYamlPolicy yamlPolicy) throws Exception { From 20c1933c7deb061b949536d48cd7911a54e6cc69 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Wed, 3 Jul 2024 13:36:37 -0700 Subject: [PATCH 148/486] Add capability to visit custom tags PiperOrigin-RevId: 649184086 --- policy/BUILD.bazel | 10 ++ .../src/main/java/dev/cel/policy/BUILD.bazel | 5 +- .../main/java/dev/cel/policy/CelPolicy.java | 24 ++- .../java/dev/cel/policy/CelPolicyParser.java | 31 ++-- .../dev/cel/policy/CelPolicyYamlParser.java | 160 ++++++++++++------ .../java/dev/cel/policy/ParserContext.java | 33 +++- .../main/java/dev/cel/policy/ValueString.java | 10 +- .../main/java/dev/cel/policy/YamlHelper.java | 14 +- .../dev/cel/policy/YamlParserContextImpl.java | 16 ++ .../src/test/java/dev/cel/policy/BUILD.bazel | 2 + .../cel/policy/CelPolicyCompilerImplTest.java | 3 +- .../cel/policy/CelPolicyYamlParserTest.java | 3 +- .../java/dev/cel/policy/PolicyTestHelper.java | 120 ++++++++++++- policy/src/test/resources/k8s/config.yaml | 33 ++++ policy/src/test/resources/k8s/policy.yaml | 36 ++++ policy/src/test/resources/k8s/tests.yaml | 31 ++++ 16 files changed, 443 insertions(+), 88 deletions(-) create mode 100644 policy/src/test/resources/k8s/config.yaml create mode 100644 policy/src/test/resources/k8s/policy.yaml create mode 100644 policy/src/test/resources/k8s/tests.yaml diff --git a/policy/BUILD.bazel b/policy/BUILD.bazel index ab45214bf..222619d9f 100644 --- a/policy/BUILD.bazel +++ b/policy/BUILD.bazel @@ -8,6 +8,11 @@ java_library( exports = ["//policy/src/main/java/dev/cel/policy"], ) +java_library( + name = "value_string", + exports = ["//policy/src/main/java/dev/cel/policy:value_string"], +) + java_library( name = "source", exports = ["//policy/src/main/java/dev/cel/policy:source"], @@ -33,6 +38,11 @@ java_library( exports = ["//policy/src/main/java/dev/cel/policy:parser"], ) +java_library( + name = "parser_context", + exports = ["//policy/src/main/java/dev/cel/policy:parser_context"], +) + java_library( name = "parser_factory", exports = ["//policy/src/main/java/dev/cel/policy:parser_factory"], diff --git a/policy/src/main/java/dev/cel/policy/BUILD.bazel b/policy/src/main/java/dev/cel/policy/BUILD.bazel index 3ac84d7e4..407ce2f4e 100644 --- a/policy/src/main/java/dev/cel/policy/BUILD.bazel +++ b/policy/src/main/java/dev/cel/policy/BUILD.bazel @@ -109,6 +109,7 @@ java_library( ":source", ":validation_exception", ":value_string", + "//common:source", "//common/internal", "@maven//:com_google_guava_guava", "@maven//:org_yaml_snakeyaml", @@ -227,7 +228,6 @@ java_library( srcs = [ "ValueString.java", ], - visibility = ["//visibility:private"], deps = [ "//:auto_value", ], @@ -262,8 +262,9 @@ java_library( srcs = [ "ParserContext.java", ], - visibility = ["//visibility:private"], deps = [ + ":policy", + ":value_string", "//common:source", ], ) diff --git a/policy/src/main/java/dev/cel/policy/CelPolicy.java b/policy/src/main/java/dev/cel/policy/CelPolicy.java index f64d8cc58..0c14b745f 100644 --- a/policy/src/main/java/dev/cel/policy/CelPolicy.java +++ b/policy/src/main/java/dev/cel/policy/CelPolicy.java @@ -19,9 +19,11 @@ import com.google.auto.value.AutoOneOf; import com.google.auto.value.AutoValue; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.errorprone.annotations.CanIgnoreReturnValue; import java.util.Arrays; +import java.util.Map; import java.util.Optional; /** @@ -37,11 +39,14 @@ public abstract class CelPolicy { public abstract CelPolicySource policySource(); + public abstract ImmutableMap metadata(); + /** Creates a new builder to construct a {@link CelPolicy} instance. */ public static Builder newBuilder() { return new AutoValue_CelPolicy.Builder() .setName(ValueString.of(0, "")) - .setRule(Rule.newBuilder().build()); + .setRule(Rule.newBuilder().build()) + .setMetadata(ImmutableMap.of()); } /** Builder for {@link CelPolicy}. */ @@ -55,6 +60,23 @@ public abstract static class Builder { public abstract Builder setPolicySource(CelPolicySource policySource); + // This should stay package-private to encourage add/set methods to be used instead. + abstract ImmutableMap.Builder metadataBuilder(); + + public abstract Builder setMetadata(ImmutableMap value); + + @CanIgnoreReturnValue + public Builder putMetadata(String key, Object value) { + metadataBuilder().put(key, value); + return this; + } + + @CanIgnoreReturnValue + public Builder putMetadata(Map map) { + metadataBuilder().putAll(map); + return this; + } + public abstract CelPolicy build(); } diff --git a/policy/src/main/java/dev/cel/policy/CelPolicyParser.java b/policy/src/main/java/dev/cel/policy/CelPolicyParser.java index 315ece06c..cfeceb89b 100644 --- a/policy/src/main/java/dev/cel/policy/CelPolicyParser.java +++ b/policy/src/main/java/dev/cel/policy/CelPolicyParser.java @@ -14,6 +14,8 @@ package dev.cel.policy; +import dev.cel.policy.ParserContext.PolicyParserContext; + /** CelPolicyParser is the interface for parsing policies into a canonical Policy representation. */ public interface CelPolicyParser { @@ -41,8 +43,12 @@ interface TagVisitor { * allow for continued parsing within a custom tag. */ default void visitPolicyTag( - ParserContext ctx, long id, String fieldName, T node, CelPolicy.Builder policyBuilder) { - ctx.reportError(id, String.format("Unsupported policy tag: %s", fieldName)); + PolicyParserContext ctx, + long id, + String tagName, + T node, + CelPolicy.Builder policyBuilder) { + ctx.reportError(id, String.format("Unsupported policy tag: %s", tagName)); } /** @@ -50,12 +56,13 @@ default void visitPolicyTag( * policy and current rule to allow for continued parsing within custom tags. */ default void visitRuleTag( - ParserContext ctx, + PolicyParserContext ctx, long id, - String fieldName, + String tagName, T node, + CelPolicy.Builder policyBuilder, CelPolicy.Rule.Builder ruleBuilder) { - ctx.reportError(id, String.format("Unsupported rule tag: %s", fieldName)); + ctx.reportError(id, String.format("Unsupported rule tag: %s", tagName)); } /** @@ -63,12 +70,13 @@ default void visitRuleTag( * policy and current match to allow for continued parsing within custom tags. */ default void visitMatchTag( - ParserContext ctx, + PolicyParserContext ctx, long id, - String fieldName, + String tagName, T node, + CelPolicy.Builder policyBuilder, CelPolicy.Match.Builder matchBuilder) { - ctx.reportError(id, String.format("Unsupported match tag: %s", fieldName)); + ctx.reportError(id, String.format("Unsupported match tag: %s", tagName)); } /** @@ -76,12 +84,13 @@ default void visitMatchTag( * parent policy and current variable to allow for continued parsing within custom tags. */ default void visitVariableTag( - ParserContext ctx, + PolicyParserContext ctx, long id, - String fieldName, + String tagName, T node, + CelPolicy.Builder policyBuilder, CelPolicy.Variable.Builder variableBuilder) { - ctx.reportError(id, String.format("Unsupported variable tag: %s", fieldName)); + ctx.reportError(id, String.format("Unsupported variable tag: %s", tagName)); } } } diff --git a/policy/src/main/java/dev/cel/policy/CelPolicyYamlParser.java b/policy/src/main/java/dev/cel/policy/CelPolicyYamlParser.java index 64921bee9..5d36185ab 100644 --- a/policy/src/main/java/dev/cel/policy/CelPolicyYamlParser.java +++ b/policy/src/main/java/dev/cel/policy/CelPolicyYamlParser.java @@ -15,16 +15,19 @@ package dev.cel.policy; import static com.google.common.base.Preconditions.checkNotNull; +import static dev.cel.policy.YamlHelper.ERROR; import static dev.cel.policy.YamlHelper.assertRequiredFields; import static dev.cel.policy.YamlHelper.assertYamlType; -import static dev.cel.policy.YamlHelper.newValueString; import com.google.common.collect.ImmutableSet; +import dev.cel.common.Source; import dev.cel.common.internal.CelCodePointArray; import dev.cel.policy.CelPolicy.Match; +import dev.cel.policy.CelPolicy.Match.Result; import dev.cel.policy.CelPolicy.Variable; +import dev.cel.policy.ParserContext.PolicyParserContext; import dev.cel.policy.YamlHelper.YamlNodeType; -import java.util.Optional; +import java.util.Map; import org.yaml.snakeyaml.nodes.MappingNode; import org.yaml.snakeyaml.nodes.Node; import org.yaml.snakeyaml.nodes.NodeTuple; @@ -33,6 +36,15 @@ final class CelPolicyYamlParser implements CelPolicyParser { + // Sentinel values for parsing errors + private static final Match ERROR_MATCH = + Match.newBuilder() + .setCondition(ValueString.newBuilder().setValue(ERROR).build()) + .setResult(Result.ofOutput(ValueString.newBuilder().setValue(ERROR).build())) + .build(); + private static final Variable ERROR_VARIABLE = + Variable.newBuilder().setName(ValueString.newBuilder().setValue(ERROR).build()).build(); + private final TagVisitor tagVisitor; @Override @@ -43,45 +55,42 @@ public CelPolicy parse(String policySource) throws CelPolicyValidationException @Override public CelPolicy parse(String policySource, String description) throws CelPolicyValidationException { - ParserImpl parser = new ParserImpl(tagVisitor); - return parser.parseYaml(policySource, description); + ParserImpl parser = new ParserImpl(tagVisitor, policySource, description); + return parser.parseYaml(); } - private static class ParserImpl { + private static class ParserImpl implements PolicyParserContext { private final TagVisitor tagVisitor; + private final CelCodePointArray policySource; + private final String description; + private final ParserContext ctx; - private CelPolicy parseYaml(String policySource, String description) - throws CelPolicyValidationException { + private CelPolicy parseYaml() throws CelPolicyValidationException { Node node; try { - node = YamlHelper.parseYamlSource(policySource); + node = YamlHelper.parseYamlSource(policySource.toString()); } catch (RuntimeException e) { throw new CelPolicyValidationException("YAML document is malformed: " + e.getMessage(), e); } - CelCodePointArray policyCodePoints = CelCodePointArray.fromString(policySource); - ParserContext ctx = YamlParserContextImpl.newInstance(policyCodePoints); - - CelPolicy.Builder policyBuilder = parsePolicy(ctx, node); - CelPolicySource celPolicySource = - CelPolicySource.newBuilder(policyCodePoints) - .setDescription(description) - .setPositionsMap(ctx.getIdToOffsetMap()) - .build(); + CelPolicy celPolicy = parsePolicy(this, node); if (ctx.hasError()) { - throw new CelPolicyValidationException(ctx.getIssueString(celPolicySource)); + throw new CelPolicyValidationException(ctx.getIssueString(celPolicy.policySource())); } - return policyBuilder.setPolicySource(celPolicySource).build(); + return celPolicy; } - private CelPolicy.Builder parsePolicy(ParserContext ctx, Node node) { + @Override + public CelPolicy parsePolicy(PolicyParserContext ctx, Node node) { CelPolicy.Builder policyBuilder = CelPolicy.newBuilder(); + CelPolicySource.Builder sourceBuilder = + CelPolicySource.newBuilder(policySource).setDescription(description); long id = ctx.collectMetadata(node); if (!assertYamlType(ctx, id, node, YamlNodeType.MAP)) { - return policyBuilder; + return policyBuilder.setPolicySource(sourceBuilder.build()).build(); } MappingNode rootNode = (MappingNode) node; @@ -96,10 +105,10 @@ private CelPolicy.Builder parsePolicy(ParserContext ctx, Node node) { String fieldName = ((ScalarNode) keyNode).getValue(); switch (fieldName) { case "name": - policyBuilder.setName(newValueString(ctx, valueNode)); + policyBuilder.setName(ctx.newValueString(valueNode)); break; case "rule": - policyBuilder.setRule(parseRule(ctx, valueNode)); + policyBuilder.setRule(parseRule(ctx, policyBuilder, valueNode)); break; default: tagVisitor.visitPolicyTag(ctx, keyId, fieldName, valueNode, policyBuilder); @@ -107,10 +116,14 @@ private CelPolicy.Builder parsePolicy(ParserContext ctx, Node node) { } } - return policyBuilder; + return policyBuilder + .setPolicySource(sourceBuilder.setPositionsMap(ctx.getIdToOffsetMap()).build()) + .build(); } - private CelPolicy.Rule parseRule(ParserContext ctx, Node node) { + @Override + public CelPolicy.Rule parseRule( + PolicyParserContext ctx, CelPolicy.Builder policyBuilder, Node node) { long valueId = ctx.collectMetadata(node); CelPolicy.Rule.Builder ruleBuilder = CelPolicy.Rule.newBuilder(); if (!assertYamlType(ctx, valueId, node, YamlNodeType.MAP)) { @@ -127,26 +140,27 @@ private CelPolicy.Rule parseRule(ParserContext ctx, Node node) { Node value = nodeTuple.getValueNode(); switch (fieldName) { case "id": - ruleBuilder.setId(newValueString(ctx, value)); + ruleBuilder.setId(ctx.newValueString(value)); break; case "description": - ruleBuilder.setDescription(newValueString(ctx, value)); + ruleBuilder.setDescription(ctx.newValueString(value)); break; case "variables": - ruleBuilder.addVariables(parseVariables(ctx, value)); + ruleBuilder.addVariables(parseVariables(ctx, policyBuilder, value)); break; case "match": - ruleBuilder.addMatches(parseMatches(ctx, value)); + ruleBuilder.addMatches(parseMatches(ctx, policyBuilder, value)); break; default: - tagVisitor.visitRuleTag(ctx, tagId, fieldName, value, ruleBuilder); + tagVisitor.visitRuleTag(ctx, tagId, fieldName, value, policyBuilder, ruleBuilder); break; } } return ruleBuilder.build(); } - private ImmutableSet parseMatches(ParserContext ctx, Node node) { + private ImmutableSet parseMatches( + PolicyParserContext ctx, CelPolicy.Builder policyBuilder, Node node) { long valueId = ctx.collectMetadata(node); ImmutableSet.Builder matchesBuilder = ImmutableSet.builder(); if (!assertYamlType(ctx, valueId, node, YamlNodeType.LIST)) { @@ -155,16 +169,18 @@ private ImmutableSet parseMatches(ParserContext ctx, Node SequenceNode matchListNode = (SequenceNode) node; for (Node elementNode : matchListNode.getValue()) { - parseMatch(ctx, elementNode).ifPresent(matchesBuilder::add); + matchesBuilder.add(parseMatch(ctx, policyBuilder, elementNode)); } return matchesBuilder.build(); } - private Optional parseMatch(ParserContext ctx, Node node) { + @Override + public CelPolicy.Match parseMatch( + PolicyParserContext ctx, CelPolicy.Builder policyBuilder, Node node) { long nodeId = ctx.collectMetadata(node); if (!assertYamlType(ctx, nodeId, node, YamlNodeType.MAP)) { - return Optional.empty(); + return ERROR_MATCH; } MappingNode matchNode = (MappingNode) node; CelPolicy.Match.Builder matchBuilder = @@ -179,7 +195,7 @@ private Optional parseMatch(ParserContext ctx, Node node) Node value = nodeTuple.getValueNode(); switch (fieldName) { case "condition": - matchBuilder.setCondition(newValueString(ctx, value)); + matchBuilder.setCondition(ctx.newValueString(value)); break; case "output": matchBuilder @@ -187,7 +203,7 @@ private Optional parseMatch(ParserContext ctx, Node node) .filter(result -> result.kind().equals(Match.Result.Kind.RULE)) .ifPresent( result -> ctx.reportError(tagId, "Only the rule or the output may be set")); - matchBuilder.setResult(Match.Result.ofOutput(newValueString(ctx, value))); + matchBuilder.setResult(Match.Result.ofOutput(ctx.newValueString(value))); break; case "rule": matchBuilder @@ -195,22 +211,23 @@ private Optional parseMatch(ParserContext ctx, Node node) .filter(result -> result.kind().equals(Match.Result.Kind.OUTPUT)) .ifPresent( result -> ctx.reportError(tagId, "Only the rule or the output may be set")); - matchBuilder.setResult(Match.Result.ofRule(parseRule(ctx, value))); + matchBuilder.setResult(Match.Result.ofRule(parseRule(ctx, policyBuilder, value))); break; default: - tagVisitor.visitMatchTag(ctx, tagId, fieldName, value, matchBuilder); + tagVisitor.visitMatchTag(ctx, tagId, fieldName, value, policyBuilder, matchBuilder); break; } } if (!assertRequiredFields(ctx, nodeId, matchBuilder.getMissingRequiredFieldNames())) { - return Optional.empty(); + return ERROR_MATCH; } - return Optional.of(matchBuilder.build()); + return matchBuilder.build(); } - private ImmutableSet parseVariables(ParserContext ctx, Node node) { + private ImmutableSet parseVariables( + PolicyParserContext ctx, CelPolicy.Builder policyBuilder, Node node) { long valueId = ctx.collectMetadata(node); ImmutableSet.Builder variableBuilder = ImmutableSet.builder(); if (!assertYamlType(ctx, valueId, node, YamlNodeType.LIST)) { @@ -219,17 +236,20 @@ private ImmutableSet parseVariables(ParserContext ctx, SequenceNode variableListNode = (SequenceNode) node; for (Node elementNode : variableListNode.getValue()) { - long id = ctx.collectMetadata(elementNode); - if (!assertYamlType(ctx, id, elementNode, YamlNodeType.MAP)) { - continue; - } - variableBuilder.add(parseVariable(ctx, (MappingNode) elementNode)); + variableBuilder.add(parseVariable(ctx, policyBuilder, elementNode)); } return variableBuilder.build(); } - private CelPolicy.Variable parseVariable(ParserContext ctx, MappingNode variableMap) { + @Override + public CelPolicy.Variable parseVariable( + PolicyParserContext ctx, CelPolicy.Builder policyBuilder, Node node) { + long id = ctx.collectMetadata(node); + if (!assertYamlType(ctx, id, node, YamlNodeType.MAP)) { + return ERROR_VARIABLE; + } + MappingNode variableMap = (MappingNode) node; Variable.Builder builder = Variable.newBuilder(); for (NodeTuple nodeTuple : variableMap.getValue()) { @@ -239,13 +259,13 @@ private CelPolicy.Variable parseVariable(ParserContext ctx, MappingNode va String keyName = ((ScalarNode) keyNode).getValue(); switch (keyName) { case "name": - builder.setName(newValueString(ctx, valueNode)); + builder.setName(ctx.newValueString(valueNode)); break; case "expression": - builder.setExpression(newValueString(ctx, valueNode)); + builder.setExpression(ctx.newValueString(valueNode)); break; default: - tagVisitor.visitVariableTag(ctx, keyId, keyName, valueNode, builder); + tagVisitor.visitVariableTag(ctx, keyId, keyName, valueNode, policyBuilder, builder); break; } } @@ -253,8 +273,46 @@ private CelPolicy.Variable parseVariable(ParserContext ctx, MappingNode va return builder.build(); } - private ParserImpl(TagVisitor tagVisitor) { + private ParserImpl(TagVisitor tagVisitor, String source, String description) { this.tagVisitor = tagVisitor; + this.policySource = CelCodePointArray.fromString(source); + this.description = description; + this.ctx = YamlParserContextImpl.newInstance(policySource); + } + + @Override + public long nextId() { + return ctx.nextId(); + } + + @Override + public long collectMetadata(Node node) { + return ctx.collectMetadata(node); + } + + @Override + public void reportError(long id, String message) { + ctx.reportError(id, message); + } + + @Override + public String getIssueString(Source source) { + return ctx.getIssueString(source); + } + + @Override + public boolean hasError() { + return ctx.hasError(); + } + + @Override + public Map getIdToOffsetMap() { + return ctx.getIdToOffsetMap(); + } + + @Override + public ValueString newValueString(Node node) { + return ctx.newValueString(node); } } diff --git a/policy/src/main/java/dev/cel/policy/ParserContext.java b/policy/src/main/java/dev/cel/policy/ParserContext.java index 3b68f82a5..385a022c3 100644 --- a/policy/src/main/java/dev/cel/policy/ParserContext.java +++ b/policy/src/main/java/dev/cel/policy/ParserContext.java @@ -15,15 +15,27 @@ package dev.cel.policy; import dev.cel.common.Source; +import dev.cel.policy.CelPolicy.Match; +import dev.cel.policy.CelPolicy.Rule; +import dev.cel.policy.CelPolicy.Variable; import java.util.Map; /** - * ParserContext declares a set of interfaces for creating and managing metadata for parsed - * policies. + * ParserContext declares a set of interfaces for managing metadata, such as node IDs, parsing + * errors and source offsets. */ public interface ParserContext { + + /** + * NextID returns a monotonically increasing identifier for a source fragment. This ID is + * implicitly created and tracked within the CollectMetadata method. + */ long nextId(); + /** + * CollectMetadata records the source position information of a given node, and returns the id + * associated with the source metadata which is returned in the Policy SourceInfo object. + */ long collectMetadata(T node); void reportError(long id, String message); @@ -33,4 +45,21 @@ public interface ParserContext { boolean hasError(); Map getIdToOffsetMap(); + + /** NewString creates a new ValueString from the YAML node. */ + ValueString newValueString(T node); + + /** + * PolicyParserContext declares a set of interfaces for creating and managing metadata + * specifically for {@link CelPolicy}. + */ + interface PolicyParserContext extends ParserContext { + CelPolicy parsePolicy(PolicyParserContext ctx, T node); + + Rule parseRule(PolicyParserContext ctx, CelPolicy.Builder policyBuilder, T node); + + Match parseMatch(PolicyParserContext ctx, CelPolicy.Builder policyBuilder, T node); + + Variable parseVariable(PolicyParserContext ctx, CelPolicy.Builder policyBuilder, T node); + } } diff --git a/policy/src/main/java/dev/cel/policy/ValueString.java b/policy/src/main/java/dev/cel/policy/ValueString.java index b1de15be5..24c56f4ee 100644 --- a/policy/src/main/java/dev/cel/policy/ValueString.java +++ b/policy/src/main/java/dev/cel/policy/ValueString.java @@ -21,9 +21,9 @@ public abstract class ValueString { /** A unique identifier. This is populated by the parser. */ - abstract long id(); + public abstract long id(); - abstract String value(); + public abstract String value(); @AutoValue.Builder abstract static class Builder { @@ -35,13 +35,15 @@ abstract static class Builder { abstract ValueString build(); } + public abstract Builder toBuilder(); + /** Builder for {@link ValueString}. */ - static Builder newBuilder() { + public static Builder newBuilder() { return new AutoValue_ValueString.Builder().setId(0).setValue(""); } /** Creates a new {@link ValueString} instance with the specified ID and string value. */ - static ValueString of(long id, String value) { + public static ValueString of(long id, String value) { return newBuilder().setId(id).setValue(value).build(); } } diff --git a/policy/src/main/java/dev/cel/policy/YamlHelper.java b/policy/src/main/java/dev/cel/policy/YamlHelper.java index a29e8c73b..d340ce329 100644 --- a/policy/src/main/java/dev/cel/policy/YamlHelper.java +++ b/policy/src/main/java/dev/cel/policy/YamlHelper.java @@ -104,19 +104,7 @@ static boolean newBoolean(ParserContext ctx, Node node) { } static String newString(ParserContext ctx, Node node) { - return YamlHelper.newValueString(ctx, node).value(); - } - - static ValueString newValueString(ParserContext ctx, Node node) { - long id = ctx.collectMetadata(node); - if (!assertYamlType(ctx, id, node, YamlNodeType.STRING, YamlNodeType.TEXT)) { - return ValueString.of(id, ERROR); - } - - ScalarNode scalarNode = (ScalarNode) node; - - // TODO: Compute relative source for multiline strings - return ValueString.of(id, scalarNode.getValue()); + return ctx.newValueString(node).value(); } private YamlHelper() {} diff --git a/policy/src/main/java/dev/cel/policy/YamlParserContextImpl.java b/policy/src/main/java/dev/cel/policy/YamlParserContextImpl.java index 31438fd98..613aca537 100644 --- a/policy/src/main/java/dev/cel/policy/YamlParserContextImpl.java +++ b/policy/src/main/java/dev/cel/policy/YamlParserContextImpl.java @@ -15,12 +15,15 @@ package dev.cel.policy; import static com.google.common.collect.ImmutableList.toImmutableList; +import static dev.cel.policy.YamlHelper.ERROR; +import static dev.cel.policy.YamlHelper.assertYamlType; import com.google.common.base.Joiner; import dev.cel.common.CelIssue; import dev.cel.common.CelSourceLocation; import dev.cel.common.Source; import dev.cel.common.internal.CelCodePointArray; +import dev.cel.policy.YamlHelper.YamlNodeType; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; @@ -60,6 +63,19 @@ public Map getIdToOffsetMap() { return idToOffsetMap; } + @Override + public ValueString newValueString(Node node) { + long id = collectMetadata(node); + if (!assertYamlType(this, id, node, YamlNodeType.STRING, YamlNodeType.TEXT)) { + return ValueString.of(id, ERROR); + } + + ScalarNode scalarNode = (ScalarNode) node; + + // TODO: Compute relative source for multiline strings + return ValueString.of(id, scalarNode.getValue()); + } + @Override public long collectMetadata(Node node) { long id = nextId(); diff --git a/policy/src/test/java/dev/cel/policy/BUILD.bazel b/policy/src/test/java/dev/cel/policy/BUILD.bazel index 05154b7e6..a77a76e6b 100644 --- a/policy/src/test/java/dev/cel/policy/BUILD.bazel +++ b/policy/src/test/java/dev/cel/policy/BUILD.bazel @@ -25,9 +25,11 @@ java_library( "//policy:config", "//policy:config_parser", "//policy:parser", + "//policy:parser_context", "//policy:parser_factory", "//policy:source", "//policy:validation_exception", + "//policy:value_string", "//runtime", "@maven//:com_google_api_grpc_proto_google_common_protos", "@maven//:com_google_guava_guava", diff --git a/policy/src/test/java/dev/cel/policy/CelPolicyCompilerImplTest.java b/policy/src/test/java/dev/cel/policy/CelPolicyCompilerImplTest.java index 41cefcae1..562044ca3 100644 --- a/policy/src/test/java/dev/cel/policy/CelPolicyCompilerImplTest.java +++ b/policy/src/test/java/dev/cel/policy/CelPolicyCompilerImplTest.java @@ -32,6 +32,7 @@ import dev.cel.extensions.CelOptionalLibrary; import dev.cel.parser.CelStandardMacro; import dev.cel.parser.CelUnparserFactory; +import dev.cel.policy.PolicyTestHelper.K8sTagHandler; import dev.cel.policy.PolicyTestHelper.PolicyTestSuite; import dev.cel.policy.PolicyTestHelper.PolicyTestSuite.PolicyTestSection; import dev.cel.policy.PolicyTestHelper.PolicyTestSuite.PolicyTestSection.PolicyTestCase; @@ -46,7 +47,7 @@ public final class CelPolicyCompilerImplTest { private static final CelPolicyParser POLICY_PARSER = - CelPolicyParserFactory.newYamlParserBuilder().build(); + CelPolicyParserFactory.newYamlParserBuilder().addTagVisitor(new K8sTagHandler()).build(); private static final CelPolicyConfigParser POLICY_CONFIG_PARSER = CelPolicyParserFactory.newYamlConfigParser(); private static final CelOptions CEL_OPTIONS = diff --git a/policy/src/test/java/dev/cel/policy/CelPolicyYamlParserTest.java b/policy/src/test/java/dev/cel/policy/CelPolicyYamlParserTest.java index 6a7cfc800..7e4d8c412 100644 --- a/policy/src/test/java/dev/cel/policy/CelPolicyYamlParserTest.java +++ b/policy/src/test/java/dev/cel/policy/CelPolicyYamlParserTest.java @@ -19,6 +19,7 @@ import com.google.testing.junit.testparameterinjector.TestParameter; import com.google.testing.junit.testparameterinjector.TestParameterInjector; +import dev.cel.policy.PolicyTestHelper.K8sTagHandler; import dev.cel.policy.PolicyTestHelper.TestYamlPolicy; import org.junit.Test; import org.junit.runner.RunWith; @@ -27,7 +28,7 @@ public final class CelPolicyYamlParserTest { private static final CelPolicyParser POLICY_PARSER = - CelPolicyParserFactory.newYamlParserBuilder().build(); + CelPolicyParserFactory.newYamlParserBuilder().addTagVisitor(new K8sTagHandler()).build(); @Test public void parseYamlPolicy_success(@TestParameter TestYamlPolicy yamlPolicy) throws Exception { diff --git a/policy/src/test/java/dev/cel/policy/PolicyTestHelper.java b/policy/src/test/java/dev/cel/policy/PolicyTestHelper.java index ed1b94a66..8b7eb1b40 100644 --- a/policy/src/test/java/dev/cel/policy/PolicyTestHelper.java +++ b/policy/src/test/java/dev/cel/policy/PolicyTestHelper.java @@ -19,6 +19,11 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Ascii; import com.google.common.io.Resources; +import dev.cel.policy.CelPolicy.Match; +import dev.cel.policy.CelPolicy.Match.Result; +import dev.cel.policy.CelPolicy.Rule; +import dev.cel.policy.CelPolicyParser.TagVisitor; +import dev.cel.policy.ParserContext.PolicyParserContext; import java.io.IOException; import java.net.URL; import java.util.List; @@ -26,6 +31,8 @@ import org.yaml.snakeyaml.LoaderOptions; import org.yaml.snakeyaml.Yaml; import org.yaml.snakeyaml.constructor.Constructor; +import org.yaml.snakeyaml.nodes.Node; +import org.yaml.snakeyaml.nodes.SequenceNode; /** Package-private class to assist with policy testing. */ final class PolicyTestHelper { @@ -66,8 +73,16 @@ enum TestYamlPolicy { + " variables.matches_dest_ip || variables.matches_dest_label," + " (variables.matches_nationality && variables.matches_dest) ? true :" + " ((!variables.has_nationality && variables.matches_origin_ip &&" - + " variables.matches_dest) ? true : false)))))))"); - + + " variables.matches_dest) ? true : false)))))))"), + K8S( + "k8s", + true, + "cel.bind(variables.env, resource.labels.?environment.orValue(\"prod\")," + + " cel.bind(variables.break_glass, resource.labels.?break_glass.orValue(\"false\") ==" + + " \"true\", !(variables.break_glass || resource.containers.all(c," + + " c.startsWith(variables.env + \".\"))) ? optional.of(\"only \" + variables.env + \"" + + " containers are allowed in namespace \" + resource.namespace) :" + + " optional.none()))"); private final String name; private final boolean producesOptionalResult; private final String unparsed; @@ -221,5 +236,106 @@ private static String readFile(String path) throws IOException { return Resources.toString(getResource(path), UTF_8); } + static class K8sTagHandler implements TagVisitor { + + @Override + public void visitPolicyTag( + PolicyParserContext ctx, + long id, + String tagName, + Node node, + CelPolicy.Builder policyBuilder) { + switch (tagName) { + case "kind": + policyBuilder.putMetadata("kind", ctx.newValueString(node)); + break; + case "metadata": + long metadataId = ctx.collectMetadata(node); + if (!node.getTag().getValue().equals("tag:yaml.org,2002:map")) { + ctx.reportError( + metadataId, + String.format( + "invalid 'metadata' type, expected map got: %s", node.getTag().getValue())); + } + break; + case "spec": + Rule rule = ctx.parseRule(ctx, policyBuilder, node); + policyBuilder.setRule(rule); + break; + default: + TagVisitor.super.visitPolicyTag(ctx, id, tagName, node, policyBuilder); + break; + } + } + + @Override + public void visitRuleTag( + PolicyParserContext ctx, + long id, + String tagName, + Node node, + CelPolicy.Builder policyBuilder, + Rule.Builder ruleBuilder) { + switch (tagName) { + case "failurePolicy": + policyBuilder.putMetadata(tagName, ctx.newValueString(node)); + break; + case "matchConstraints": + long matchConstraintsId = ctx.collectMetadata(node); + if (!node.getTag().getValue().equals("tag:yaml.org,2002:map")) { + ctx.reportError( + matchConstraintsId, + String.format( + "invalid 'matchConstraints' type, expected map got: %s", + node.getTag().getValue())); + } + break; + case "validations": + long validationId = ctx.collectMetadata(node); + if (!node.getTag().getValue().equals("tag:yaml.org,2002:seq")) { + ctx.reportError( + validationId, + String.format( + "invalid 'validations' type, expected list got: %s", node.getTag().getValue())); + } + + SequenceNode validationNodes = (SequenceNode) node; + for (Node element : validationNodes.getValue()) { + ruleBuilder.addMatches(ctx.parseMatch(ctx, policyBuilder, element)); + } + break; + default: + TagVisitor.super.visitRuleTag(ctx, id, tagName, node, policyBuilder, ruleBuilder); + break; + } + } + + @Override + public void visitMatchTag( + PolicyParserContext ctx, + long id, + String tagName, + Node node, + CelPolicy.Builder policyBuilder, + Match.Builder matchBuilder) { + switch (tagName) { + case "expression": + // The K8s expression to validate must return false in order to generate a violation + // message. + ValueString conditionValue = ctx.newValueString(node); + conditionValue = + conditionValue.toBuilder().setValue("!(" + conditionValue.value() + ")").build(); + matchBuilder.setCondition(conditionValue); + break; + case "messageExpression": + matchBuilder.setResult(Result.ofOutput(ctx.newValueString(node))); + break; + default: + TagVisitor.super.visitMatchTag(ctx, id, tagName, node, policyBuilder, matchBuilder); + break; + } + } + } + private PolicyTestHelper() {} } diff --git a/policy/src/test/resources/k8s/config.yaml b/policy/src/test/resources/k8s/config.yaml new file mode 100644 index 000000000..4df8439ea --- /dev/null +++ b/policy/src/test/resources/k8s/config.yaml @@ -0,0 +1,33 @@ +# Copyright 2024 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. + +name: k8s +extensions: +- name: "strings" + version: 2 +variables: +- name: "resource.labels" + type: + type_name: "map" + params: + - type_name: "string" + - type_name: "string" +- name: "resource.containers" + type: + type_name: "list" + params: + - type_name: "string" +- name: "resource.namespace" + type: + type_name: "string" diff --git a/policy/src/test/resources/k8s/policy.yaml b/policy/src/test/resources/k8s/policy.yaml new file mode 100644 index 000000000..9cc9782fa --- /dev/null +++ b/policy/src/test/resources/k8s/policy.yaml @@ -0,0 +1,36 @@ +# Copyright 2024 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. + +name: k8s +kind: ValidatingAdmissionPolicy +metadata: + name: "policy.cel.dev" +spec: + failurePolicy: Fail + matchConstraints: + resourceRules: + - apiGroups: ["services"] + apiVersions: ["v3"] + operations: ["CREATE", "UPDATE"] + variables: + - name: env + expression: "resource.labels.?environment.orValue('prod')" + - name: break_glass + expression: "resource.labels.?break_glass.orValue('false') == 'true'" + validations: + - expression: > + variables.break_glass || + resource.containers.all(c, c.startsWith(variables.env + '.')) + messageExpression: > + 'only ' + variables.env + ' containers are allowed in namespace ' + resource.namespace diff --git a/policy/src/test/resources/k8s/tests.yaml b/policy/src/test/resources/k8s/tests.yaml new file mode 100644 index 000000000..8585c5efb --- /dev/null +++ b/policy/src/test/resources/k8s/tests.yaml @@ -0,0 +1,31 @@ +# Copyright 2024 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. + +description: K8s admission control tests +section: +- name: "invalid" + tests: + - name: "restricted_container" + input: + resource.namespace: + value: "dev.cel" + resource.labels: + value: + environment: "staging" + resource.containers: + value: + - staging.dev.cel.container1 + - staging.dev.cel.container2 + - preprod.dev.cel.container3 + output: "'only staging containers are allowed in namespace dev.cel'" From e85ee166dc090d0d33342fb8eb2b74ac39ed2646 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Wed, 3 Jul 2024 14:17:33 -0700 Subject: [PATCH 149/486] Pull getIssueString logic into CelIssue PiperOrigin-RevId: 649196570 --- .../test/java/dev/cel/checker/CelIssueTest.java | 11 ++++------- .../src/main/java/dev/cel/common/CelIssue.java | 11 +++++++++++ .../dev/cel/common/CelValidationException.java | 14 ++++---------- .../dev/cel/common/CelValidationResult.java | 8 ++------ policy/src/main/java/dev/cel/policy/BUILD.bazel | 6 +++--- .../dev/cel/policy/CelPolicyCompilerImpl.java | 8 +------- .../cel/policy/CelPolicyYamlConfigParser.java | 6 ++++-- .../dev/cel/policy/CelPolicyYamlParser.java | 17 +++++++---------- .../main/java/dev/cel/policy/ParserContext.java | 7 +++---- .../dev/cel/policy/YamlParserContextImpl.java | 16 +++------------- 10 files changed, 42 insertions(+), 62 deletions(-) diff --git a/checker/src/test/java/dev/cel/checker/CelIssueTest.java b/checker/src/test/java/dev/cel/checker/CelIssueTest.java index e0d34fd0c..a200a5fd5 100644 --- a/checker/src/test/java/dev/cel/checker/CelIssueTest.java +++ b/checker/src/test/java/dev/cel/checker/CelIssueTest.java @@ -16,9 +16,7 @@ import static com.google.common.truth.Truth.assertThat; -import com.google.common.base.Joiner; import com.google.common.collect.ImmutableList; -import com.google.common.collect.Iterables; import dev.cel.common.CelIssue; import dev.cel.common.CelSource; import org.junit.Test; @@ -28,8 +26,6 @@ @RunWith(JUnit4.class) public final class CelIssueTest { - private static final Joiner JOINER = Joiner.on('\n'); - @Test public void toDisplayString_narrow() throws Exception { CelSource source = @@ -38,7 +34,7 @@ public void toDisplayString_narrow() throws Exception { ImmutableList.of( CelIssue.formatError(1, 1, "No such field"), CelIssue.formatError(2, 20, "Syntax error, missing paren")); - assertThat(JOINER.join(Iterables.transform(issues, error -> error.toDisplayString(source)))) + assertThat(CelIssue.toDisplayString(issues, source)) .isEqualTo( "ERROR: issues-test:1:2: No such field\n" + " | a.b\n" @@ -53,7 +49,7 @@ public void toDisplayString_wideAndNarrow() throws Exception { CelSource source = CelSource.newBuilder("你好吗\n我b很好\n").setDescription("issues-test").build(); ImmutableList issues = ImmutableList.of(CelIssue.formatError(2, 3, "Unexpected character '好'")); - assertThat(JOINER.join(Iterables.transform(issues, error -> error.toDisplayString(source)))) + assertThat(CelIssue.toDisplayString(issues, source)) .isEqualTo("ERROR: issues-test:2:4: Unexpected character '好'\n" + " | 我b很好\n" + " | ...^"); } @@ -73,7 +69,8 @@ public void toDisplayString_emojis() throws Exception { + " IDENTIFIER}"), CelIssue.formatError(1, 35, "Syntax error: token recognition error at: '😁'"), CelIssue.formatError(1, 36, "Syntax error: missing IDENTIFIER at ''")); - assertThat(JOINER.join(Iterables.transform(issues, error -> error.toDisplayString(source)))) + + assertThat(CelIssue.toDisplayString(issues, source)) .isEqualTo( "ERROR: issues-test:1:33: Syntax error: extraneous input 'in' expecting {'[', '{'," + " '(', '.', '-', '!', 'true', 'false', 'null', NUM_FLOAT, NUM_INT, NUM_UINT," diff --git a/common/src/main/java/dev/cel/common/CelIssue.java b/common/src/main/java/dev/cel/common/CelIssue.java index 1e3cdb58e..2f507d5a7 100644 --- a/common/src/main/java/dev/cel/common/CelIssue.java +++ b/common/src/main/java/dev/cel/common/CelIssue.java @@ -14,10 +14,14 @@ package dev.cel.common; +import static com.google.common.collect.ImmutableList.toImmutableList; + import com.google.auto.value.AutoValue; +import com.google.common.base.Joiner; import com.google.errorprone.annotations.CheckReturnValue; import com.google.errorprone.annotations.Immutable; import dev.cel.common.internal.SafeStringFormatter; +import java.util.Collection; import java.util.Optional; import java.util.PrimitiveIterator; @@ -28,6 +32,7 @@ @Immutable @SuppressWarnings("UnicodeEscape") // Suppressed to distinguish half-width and full-width chars. public abstract class CelIssue { + private static final Joiner JOINER = Joiner.on('\n'); /** Severity of a CelIssue. */ public enum Severity { @@ -73,6 +78,12 @@ public static CelIssue formatError(int line, int column, String message) { private static final char WIDE_DOT = '\uff0e'; private static final char WIDE_HAT = '\uff3e'; + /** Returns a human-readable error with all issues joined in a single string. */ + public static String toDisplayString(Collection issues, Source source) { + return JOINER.join( + issues.stream().map(iss -> iss.toDisplayString(source)).collect(toImmutableList())); + } + /** Returns a string representing this error that is suitable for displaying to humans. */ public String toDisplayString(Source source) { // Based onhttps://github.com/google/cel-go/blob/v0.5.1/common/error.go#L42. diff --git a/common/src/main/java/dev/cel/common/CelValidationException.java b/common/src/main/java/dev/cel/common/CelValidationException.java index ef136f8a7..522706e83 100644 --- a/common/src/main/java/dev/cel/common/CelValidationException.java +++ b/common/src/main/java/dev/cel/common/CelValidationException.java @@ -15,15 +15,12 @@ package dev.cel.common; import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Joiner; import com.google.common.collect.ImmutableList; -import com.google.common.collect.Iterables; import java.util.List; /** Base class for all checked exceptions explicitly thrown by the library during parsing. */ public final class CelValidationException extends CelException { - private static final Joiner JOINER = Joiner.on('\n'); // Truncates all errors beyond this limit in the message. private static final int MAX_ERRORS_TO_REPORT = 1000; @@ -46,17 +43,14 @@ public CelValidationException(CelSource source, List errors) { private static String safeJoinErrorMessage(CelSource source, List errors) { if (errors.size() <= MAX_ERRORS_TO_REPORT) { - return JOINER.join(Iterables.transform(errors, error -> error.toDisplayString(source))); + return CelIssue.toDisplayString(errors, source); } List truncatedErrors = errors.subList(0, MAX_ERRORS_TO_REPORT); - StringBuilder sb = new StringBuilder(); - JOINER.appendTo( - sb, Iterables.transform(truncatedErrors, error -> error.toDisplayString(source))); - sb.append( - String.format("%n...and %d more errors (truncated)", errors.size() - MAX_ERRORS_TO_REPORT)); - return sb.toString(); + return CelIssue.toDisplayString(truncatedErrors, source) + + String.format( + "%n...and %d more errors (truncated)", errors.size() - MAX_ERRORS_TO_REPORT); } /** Returns the {@link CelSource} that was being validated. */ diff --git a/common/src/main/java/dev/cel/common/CelValidationResult.java b/common/src/main/java/dev/cel/common/CelValidationResult.java index 3e52bc8e1..61152c493 100644 --- a/common/src/main/java/dev/cel/common/CelValidationResult.java +++ b/common/src/main/java/dev/cel/common/CelValidationResult.java @@ -17,9 +17,7 @@ import static com.google.common.collect.ImmutableList.toImmutableList; import static java.util.Comparator.comparing; -import com.google.common.base.Joiner; import com.google.common.collect.ImmutableList; -import com.google.common.collect.Iterables; import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.errorprone.annotations.Immutable; import com.google.errorprone.annotations.InlineMe; @@ -33,8 +31,6 @@ @Immutable public final class CelValidationResult { - private static final Joiner JOINER = Joiner.on('\n'); - @SuppressWarnings("Immutable") private final @Nullable Throwable failure; @@ -115,7 +111,7 @@ public ImmutableList getAllIssues() { /** Convert all issues to a human-readable string. */ public String getIssueString() { - return JOINER.join(Iterables.transform(issues, iss -> iss.toDisplayString(source))); + return CelIssue.toDisplayString(issues, source); } /** @@ -131,7 +127,7 @@ public String getDebugString() { /** Convert the {@code CelIssue}s with {@code ERROR} severity to an error string. */ public String getErrorString() { - return JOINER.join(Iterables.transform(getErrors(), error -> error.toDisplayString(source))); + return CelIssue.toDisplayString(getErrors(), source); } private static boolean issueIsError(CelIssue iss) { diff --git a/policy/src/main/java/dev/cel/policy/BUILD.bazel b/policy/src/main/java/dev/cel/policy/BUILD.bazel index 407ce2f4e..c13bcf0c4 100644 --- a/policy/src/main/java/dev/cel/policy/BUILD.bazel +++ b/policy/src/main/java/dev/cel/policy/BUILD.bazel @@ -109,7 +109,7 @@ java_library( ":source", ":validation_exception", ":value_string", - "//common:source", + "//common:compiler_common", "//common/internal", "@maven//:com_google_guava_guava", "@maven//:org_yaml_snakeyaml", @@ -217,6 +217,7 @@ java_library( ":parser_context", ":source", ":validation_exception", + "//common:compiler_common", "//common/internal", "@maven//:com_google_guava_guava", "@maven//:org_yaml_snakeyaml", @@ -265,7 +266,7 @@ java_library( deps = [ ":policy", ":value_string", - "//common:source", + "//common:compiler_common", ], ) @@ -302,7 +303,6 @@ java_library( ":value_string", "//common", "//common:compiler_common", - "//common:source", "//common/internal", "@maven//:com_google_guava_guava", "@maven//:org_yaml_snakeyaml", diff --git a/policy/src/main/java/dev/cel/policy/CelPolicyCompilerImpl.java b/policy/src/main/java/dev/cel/policy/CelPolicyCompilerImpl.java index 4fb81f42b..c2f1516db 100644 --- a/policy/src/main/java/dev/cel/policy/CelPolicyCompilerImpl.java +++ b/policy/src/main/java/dev/cel/policy/CelPolicyCompilerImpl.java @@ -15,9 +15,7 @@ package dev.cel.policy; import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.collect.ImmutableList.toImmutableList; -import com.google.common.base.Joiner; import com.google.common.collect.ImmutableList; import com.google.errorprone.annotations.CanIgnoreReturnValue; import dev.cel.bundle.Cel; @@ -145,7 +143,6 @@ private static CelAbstractSyntaxTree newErrorAst() { } private static final class CompilerContext { - private static final Joiner JOINER = Joiner.on('\n'); private final ArrayList issues; private final ArrayList newVariableDeclarations; private final CelPolicySource celPolicySource; @@ -170,10 +167,7 @@ private boolean hasError() { } private String getIssueString() { - return JOINER.join( - issues.stream() - .map(iss -> iss.toDisplayString(celPolicySource)) - .collect(toImmutableList())); + return CelIssue.toDisplayString(issues, celPolicySource); } private CompilerContext(CelPolicySource celPolicySource) { diff --git a/policy/src/main/java/dev/cel/policy/CelPolicyYamlConfigParser.java b/policy/src/main/java/dev/cel/policy/CelPolicyYamlConfigParser.java index 01dfc77b6..d8955fe2b 100644 --- a/policy/src/main/java/dev/cel/policy/CelPolicyYamlConfigParser.java +++ b/policy/src/main/java/dev/cel/policy/CelPolicyYamlConfigParser.java @@ -24,6 +24,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; +import dev.cel.common.CelIssue; import dev.cel.common.internal.CelCodePointArray; import dev.cel.policy.CelPolicyConfig.ExtensionConfig; import dev.cel.policy.CelPolicyConfig.FunctionDecl; @@ -339,8 +340,9 @@ private CelPolicyConfig parseYaml(String source, String description) .setPositionsMap(ctx.getIdToOffsetMap()) .build(); - if (ctx.hasError()) { - throw new CelPolicyValidationException(ctx.getIssueString(configSource)); + if (!ctx.getIssues().isEmpty()) { + throw new CelPolicyValidationException( + CelIssue.toDisplayString(ctx.getIssues(), configSource)); } return policyConfig.setConfigSource(configSource).build(); diff --git a/policy/src/main/java/dev/cel/policy/CelPolicyYamlParser.java b/policy/src/main/java/dev/cel/policy/CelPolicyYamlParser.java index 5d36185ab..0972451f4 100644 --- a/policy/src/main/java/dev/cel/policy/CelPolicyYamlParser.java +++ b/policy/src/main/java/dev/cel/policy/CelPolicyYamlParser.java @@ -20,13 +20,14 @@ import static dev.cel.policy.YamlHelper.assertYamlType; import com.google.common.collect.ImmutableSet; -import dev.cel.common.Source; +import dev.cel.common.CelIssue; import dev.cel.common.internal.CelCodePointArray; import dev.cel.policy.CelPolicy.Match; import dev.cel.policy.CelPolicy.Match.Result; import dev.cel.policy.CelPolicy.Variable; import dev.cel.policy.ParserContext.PolicyParserContext; import dev.cel.policy.YamlHelper.YamlNodeType; +import java.util.List; import java.util.Map; import org.yaml.snakeyaml.nodes.MappingNode; import org.yaml.snakeyaml.nodes.Node; @@ -76,8 +77,9 @@ private CelPolicy parseYaml() throws CelPolicyValidationException { CelPolicy celPolicy = parsePolicy(this, node); - if (ctx.hasError()) { - throw new CelPolicyValidationException(ctx.getIssueString(celPolicy.policySource())); + if (!ctx.getIssues().isEmpty()) { + throw new CelPolicyValidationException( + CelIssue.toDisplayString(ctx.getIssues(), celPolicy.policySource())); } return celPolicy; @@ -296,13 +298,8 @@ public void reportError(long id, String message) { } @Override - public String getIssueString(Source source) { - return ctx.getIssueString(source); - } - - @Override - public boolean hasError() { - return ctx.hasError(); + public List getIssues() { + return ctx.getIssues(); } @Override diff --git a/policy/src/main/java/dev/cel/policy/ParserContext.java b/policy/src/main/java/dev/cel/policy/ParserContext.java index 385a022c3..13b816414 100644 --- a/policy/src/main/java/dev/cel/policy/ParserContext.java +++ b/policy/src/main/java/dev/cel/policy/ParserContext.java @@ -14,10 +14,11 @@ package dev.cel.policy; -import dev.cel.common.Source; +import dev.cel.common.CelIssue; import dev.cel.policy.CelPolicy.Match; import dev.cel.policy.CelPolicy.Rule; import dev.cel.policy.CelPolicy.Variable; +import java.util.List; import java.util.Map; /** @@ -40,9 +41,7 @@ public interface ParserContext { void reportError(long id, String message); - String getIssueString(Source source); - - boolean hasError(); + List getIssues(); Map getIdToOffsetMap(); diff --git a/policy/src/main/java/dev/cel/policy/YamlParserContextImpl.java b/policy/src/main/java/dev/cel/policy/YamlParserContextImpl.java index 613aca537..d84b9f830 100644 --- a/policy/src/main/java/dev/cel/policy/YamlParserContextImpl.java +++ b/policy/src/main/java/dev/cel/policy/YamlParserContextImpl.java @@ -14,18 +14,16 @@ package dev.cel.policy; -import static com.google.common.collect.ImmutableList.toImmutableList; import static dev.cel.policy.YamlHelper.ERROR; import static dev.cel.policy.YamlHelper.assertYamlType; -import com.google.common.base.Joiner; import dev.cel.common.CelIssue; import dev.cel.common.CelSourceLocation; -import dev.cel.common.Source; import dev.cel.common.internal.CelCodePointArray; import dev.cel.policy.YamlHelper.YamlNodeType; import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import org.yaml.snakeyaml.DumperOptions; import org.yaml.snakeyaml.nodes.Node; @@ -34,8 +32,6 @@ /** Package-private class to assist with storing policy parsing context. */ final class YamlParserContextImpl implements ParserContext { - private static final Joiner JOINER = Joiner.on('\n'); - private final ArrayList issues; private final HashMap idToLocationMap; private final HashMap idToOffsetMap; @@ -48,14 +44,8 @@ public void reportError(long id, String message) { } @Override - public String getIssueString(Source source) { - return JOINER.join( - issues.stream().map(iss -> iss.toDisplayString(source)).collect(toImmutableList())); - } - - @Override - public boolean hasError() { - return !issues.isEmpty(); + public List getIssues() { + return issues; } @Override From 893dfeaa28de3bf5d0b1aba537d48d7430d3fc1d Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Wed, 3 Jul 2024 14:54:49 -0700 Subject: [PATCH 150/486] Internal Changes PiperOrigin-RevId: 649207240 --- policy/BUILD.bazel | 15 +++ .../src/main/java/dev/cel/policy/BUILD.bazel | 109 +++++++++++------- 2 files changed, 80 insertions(+), 44 deletions(-) diff --git a/policy/BUILD.bazel b/policy/BUILD.bazel index 222619d9f..8d7b5d909 100644 --- a/policy/BUILD.bazel +++ b/policy/BUILD.bazel @@ -52,3 +52,18 @@ java_library( name = "compiler_factory", exports = ["//policy/src/main/java/dev/cel/policy:compiler_factory"], ) + +java_library( + name = "parser_builder", + exports = ["//policy/src/main/java/dev/cel/policy:parser_builder"], +) + +java_library( + name = "compiler", + exports = ["//policy/src/main/java/dev/cel/policy:compiler"], +) + +java_library( + name = "compiler_builder", + exports = ["//policy/src/main/java/dev/cel/policy:compiler_builder"], +) diff --git a/policy/src/main/java/dev/cel/policy/BUILD.bazel b/policy/src/main/java/dev/cel/policy/BUILD.bazel index c13bcf0c4..e334293da 100644 --- a/policy/src/main/java/dev/cel/policy/BUILD.bazel +++ b/policy/src/main/java/dev/cel/policy/BUILD.bazel @@ -10,6 +10,8 @@ java_library( srcs = [ "CelPolicy.java", ], + tags = [ + ], deps = [ ":required_fields_checker", ":source", @@ -86,6 +88,8 @@ java_library( java_library( name = "parser_factory", srcs = ["CelPolicyParserFactory.java"], + tags = [ + ], deps = [ ":config_parser", ":parser_builder", @@ -121,6 +125,8 @@ java_library( srcs = [ "CelPolicyParser.java", ], + tags = [ + ], deps = [ ":parser_context", ":policy", @@ -133,6 +139,8 @@ java_library( srcs = [ "CelPolicyParserBuilder.java", ], + tags = [ + ], deps = [ ":parser", "@maven//:com_google_errorprone_error_prone_annotations", @@ -144,6 +152,8 @@ java_library( srcs = [ "CelPolicyCompiler.java", ], + tags = [ + ], deps = [ ":policy", ":validation_exception", @@ -156,17 +166,63 @@ java_library( srcs = [ "CelPolicyCompilerBuilder.java", ], + tags = [ + ], deps = [ ":compiler", "@maven//:com_google_errorprone_error_prone_annotations", ], ) +java_library( + name = "compiler_factory", + srcs = ["CelPolicyCompilerFactory.java"], + tags = [ + ], + deps = [ + ":compiler_builder", + ":compiler_impl", + "//bundle:cel", + "//checker:checker_builder", + "//compiler", + "//compiler:compiler_builder", + "//parser:parser_builder", + "//runtime", + ], +) + +java_library( + name = "value_string", + srcs = [ + "ValueString.java", + ], + tags = [ + ], + deps = [ + "//:auto_value", + ], +) + +java_library( + name = "parser_context", + srcs = [ + "ParserContext.java", + ], + tags = [ + ], + deps = [ + ":policy", + ":value_string", + "//common:compiler_common", + ], +) + java_library( name = "compiler_impl", srcs = [ "CelPolicyCompilerImpl.java", ], + visibility = ["//visibility:private"], deps = [ ":compiled_rule", ":compiler", @@ -191,17 +247,14 @@ java_library( ) java_library( - name = "compiler_factory", - srcs = ["CelPolicyCompilerFactory.java"], + name = "required_fields_checker", + srcs = [ + "RequiredFieldsChecker.java", + ], + visibility = ["//visibility:private"], deps = [ - ":compiler_builder", - ":compiler_impl", - "//bundle:cel", - "//checker:checker_builder", - "//compiler", - "//compiler:compiler_builder", - "//parser:parser_builder", - "//runtime", + "//:auto_value", + "@maven//:com_google_guava_guava", ], ) @@ -210,6 +263,7 @@ java_library( srcs = [ "CelPolicyYamlConfigParser.java", ], + visibility = ["//visibility:private"], deps = [ ":common_internal", ":config", @@ -224,31 +278,10 @@ java_library( ], ) -java_library( - name = "value_string", - srcs = [ - "ValueString.java", - ], - deps = [ - "//:auto_value", - ], -) - -java_library( - name = "required_fields_checker", - srcs = [ - "RequiredFieldsChecker.java", - ], - visibility = ["//visibility:private"], - deps = [ - "//:auto_value", - "@maven//:com_google_guava_guava", - ], -) - java_library( name = "compiled_rule", srcs = ["CelCompiledRule.java"], + visibility = ["//visibility:private"], deps = [ "//:auto_value", "//bundle:cel", @@ -258,18 +291,6 @@ java_library( ], ) -java_library( - name = "parser_context", - srcs = [ - "ParserContext.java", - ], - deps = [ - ":policy", - ":value_string", - "//common:compiler_common", - ], -) - java_library( name = "rule_composer", srcs = ["RuleComposer.java"], From 138b11dab2fdcb9060f8d486ad03fefb462a1b48 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Wed, 3 Jul 2024 15:12:12 -0700 Subject: [PATCH 151/486] Introduce protobuf message testing to policies PiperOrigin-RevId: 649212262 --- .../src/test/java/dev/cel/policy/BUILD.bazel | 1 + .../cel/policy/CelPolicyCompilerImplTest.java | 22 +++++++++---- .../java/dev/cel/policy/PolicyTestHelper.java | 7 +++- policy/src/test/resources/pb/config.yaml | 23 +++++++++++++ policy/src/test/resources/pb/policy.yaml | 20 +++++++++++ policy/src/test/resources/pb/tests.yaml | 33 +++++++++++++++++++ 6 files changed, 99 insertions(+), 7 deletions(-) create mode 100644 policy/src/test/resources/pb/config.yaml create mode 100644 policy/src/test/resources/pb/policy.yaml create mode 100644 policy/src/test/resources/pb/tests.yaml diff --git a/policy/src/test/java/dev/cel/policy/BUILD.bazel b/policy/src/test/java/dev/cel/policy/BUILD.bazel index a77a76e6b..8606ca254 100644 --- a/policy/src/test/java/dev/cel/policy/BUILD.bazel +++ b/policy/src/test/java/dev/cel/policy/BUILD.bazel @@ -15,6 +15,7 @@ java_library( "//common", "//common:options", "//common/internal", + "//common/resources/testdata/proto3:test_all_types_java_proto", "//compiler", "//extensions:optional_library", "//parser", diff --git a/policy/src/test/java/dev/cel/policy/CelPolicyCompilerImplTest.java b/policy/src/test/java/dev/cel/policy/CelPolicyCompilerImplTest.java index 562044ca3..188e9b199 100644 --- a/policy/src/test/java/dev/cel/policy/CelPolicyCompilerImplTest.java +++ b/policy/src/test/java/dev/cel/policy/CelPolicyCompilerImplTest.java @@ -14,7 +14,7 @@ package dev.cel.policy; -import static com.google.common.collect.ImmutableMap.toImmutableMap; +import static com.google.common.base.Strings.isNullOrEmpty; import static com.google.common.truth.Truth.assertThat; import static dev.cel.policy.PolicyTestHelper.readFromYaml; import static org.junit.Assert.assertThrows; @@ -36,9 +36,11 @@ import dev.cel.policy.PolicyTestHelper.PolicyTestSuite; import dev.cel.policy.PolicyTestHelper.PolicyTestSuite.PolicyTestSection; import dev.cel.policy.PolicyTestHelper.PolicyTestSuite.PolicyTestSection.PolicyTestCase; +import dev.cel.policy.PolicyTestHelper.PolicyTestSuite.PolicyTestSection.PolicyTestCase.PolicyTestInput; import dev.cel.policy.PolicyTestHelper.TestYamlPolicy; import dev.cel.runtime.CelRuntime.CelFunctionBinding; -import java.util.Map.Entry; +import dev.cel.testing.testdata.proto3.TestAllTypesProto.TestAllTypes; +import java.util.Map; import java.util.Optional; import org.junit.Test; import org.junit.runner.RunWith; @@ -138,10 +140,17 @@ public void evaluateYamlPolicy_withCanonicalTestData( // Compile then evaluate the policy CelAbstractSyntaxTree compiledPolicyAst = CelPolicyCompilerFactory.newPolicyCompiler(cel).build().compile(policy); - ImmutableMap input = - testData.testCase.getInput().entrySet().stream() - .collect(toImmutableMap(Entry::getKey, e -> e.getValue().getValue())); - Object evalResult = cel.createProgram(compiledPolicyAst).eval(input); + ImmutableMap.Builder inputBuilder = ImmutableMap.builder(); + for (Map.Entry entry : testData.testCase.getInput().entrySet()) { + String exprInput = entry.getValue().getExpr(); + if (isNullOrEmpty(exprInput)) { + inputBuilder.put(entry.getKey(), entry.getValue().getValue()); + } else { + CelAbstractSyntaxTree exprInputAst = cel.compile(exprInput).getAst(); + inputBuilder.put(entry.getKey(), cel.createProgram(exprInputAst).eval()); + } + } + Object evalResult = cel.createProgram(compiledPolicyAst).eval(inputBuilder.buildOrThrow()); // Assert // Note that policies may either produce an optional or a non-optional result, @@ -219,6 +228,7 @@ private static Cel newCel() { .setStandardMacros(CelStandardMacro.STANDARD_MACROS) .addCompilerLibraries(CelOptionalLibrary.INSTANCE) .addRuntimeLibraries(CelOptionalLibrary.INSTANCE) + .addMessageTypes(TestAllTypes.getDescriptor()) .setOptions(CEL_OPTIONS) .addFunctionBindings( CelFunctionBinding.from( diff --git a/policy/src/test/java/dev/cel/policy/PolicyTestHelper.java b/policy/src/test/java/dev/cel/policy/PolicyTestHelper.java index 8b7eb1b40..f323e5ca5 100644 --- a/policy/src/test/java/dev/cel/policy/PolicyTestHelper.java +++ b/policy/src/test/java/dev/cel/policy/PolicyTestHelper.java @@ -82,7 +82,12 @@ enum TestYamlPolicy { + " \"true\", !(variables.break_glass || resource.containers.all(c," + " c.startsWith(variables.env + \".\"))) ? optional.of(\"only \" + variables.env + \"" + " containers are allowed in namespace \" + resource.namespace) :" - + " optional.none()))"); + + " optional.none()))"), + PB( + "pb", + true, + "(spec.single_int32 > 10) ? optional.of(\"invalid spec, got single_int32=\" +" + + " string(spec.single_int32) + \", wanted <= 10\") : optional.none()"); private final String name; private final boolean producesOptionalResult; private final String unparsed; diff --git a/policy/src/test/resources/pb/config.yaml b/policy/src/test/resources/pb/config.yaml new file mode 100644 index 000000000..d412ec012 --- /dev/null +++ b/policy/src/test/resources/pb/config.yaml @@ -0,0 +1,23 @@ +# Copyright 2024 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. + +name: "pb" +container: "dev.cel.testing.testdata.proto3" +extensions: +- name: "strings" + version: 2 +variables: +- name: "spec" + type: + type_name: "dev.cel.testing.testdata.proto3.TestAllTypes" diff --git a/policy/src/test/resources/pb/policy.yaml b/policy/src/test/resources/pb/policy.yaml new file mode 100644 index 000000000..b26c0dd3b --- /dev/null +++ b/policy/src/test/resources/pb/policy.yaml @@ -0,0 +1,20 @@ +# Copyright 2024 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. + +name: "pb" +rule: + match: + - condition: spec.single_int32 > 10 + output: | + "invalid spec, got single_int32=" + string(spec.single_int32) + ", wanted <= 10" diff --git a/policy/src/test/resources/pb/tests.yaml b/policy/src/test/resources/pb/tests.yaml new file mode 100644 index 000000000..82dd6b11b --- /dev/null +++ b/policy/src/test/resources/pb/tests.yaml @@ -0,0 +1,33 @@ +# Copyright 2024 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. + +description: "Protobuf input tests" +section: +- name: "valid" + tests: + - name: "good spec" + input: + spec: + expr: > + TestAllTypes{single_int32: 10} + output: "optional.none()" +- name: "invalid" + tests: + - name: "bad spec" + input: + spec: + expr: > + TestAllTypes{single_int32: 11} + output: > + "invalid spec, got single_int32=11, wanted <= 10" From 48d5ce6fd119ca5a1849a0974c42315983425070 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Wed, 3 Jul 2024 15:24:10 -0700 Subject: [PATCH 152/486] Validate required fields for policy variables PiperOrigin-RevId: 649215393 --- .../main/java/dev/cel/policy/CelPolicy.java | 16 ++++++++++---- .../dev/cel/policy/CelPolicyYamlParser.java | 12 +++++----- .../cel/policy/CelPolicyYamlParserTest.java | 22 +++++++++++++++++-- 3 files changed, 39 insertions(+), 11 deletions(-) diff --git a/policy/src/main/java/dev/cel/policy/CelPolicy.java b/policy/src/main/java/dev/cel/policy/CelPolicy.java index 0c14b745f..45a2c666c 100644 --- a/policy/src/main/java/dev/cel/policy/CelPolicy.java +++ b/policy/src/main/java/dev/cel/policy/CelPolicy.java @@ -217,20 +217,28 @@ public abstract static class Variable { /** Builder for {@link Variable}. */ @AutoValue.Builder - public abstract static class Builder { + public abstract static class Builder implements RequiredFieldsChecker { + + abstract Optional name(); + + abstract Optional expression(); public abstract Builder setName(ValueString name); public abstract Builder setExpression(ValueString expression); + @Override + public ImmutableList requiredFields() { + return ImmutableList.of( + RequiredField.of("name", this::name), RequiredField.of("expression", this::expression)); + } + public abstract Variable build(); } /** Creates a new builder to construct a {@link Variable} instance. */ public static Builder newBuilder() { - return new AutoValue_CelPolicy_Variable.Builder() - .setName(ValueString.newBuilder().build()) - .setExpression(ValueString.newBuilder().build()); + return new AutoValue_CelPolicy_Variable.Builder(); } } } diff --git a/policy/src/main/java/dev/cel/policy/CelPolicyYamlParser.java b/policy/src/main/java/dev/cel/policy/CelPolicyYamlParser.java index 0972451f4..b1b96834d 100644 --- a/policy/src/main/java/dev/cel/policy/CelPolicyYamlParser.java +++ b/policy/src/main/java/dev/cel/policy/CelPolicyYamlParser.java @@ -38,13 +38,11 @@ final class CelPolicyYamlParser implements CelPolicyParser { // Sentinel values for parsing errors + private static final ValueString ERROR_VALUE = ValueString.newBuilder().setValue(ERROR).build(); private static final Match ERROR_MATCH = - Match.newBuilder() - .setCondition(ValueString.newBuilder().setValue(ERROR).build()) - .setResult(Result.ofOutput(ValueString.newBuilder().setValue(ERROR).build())) - .build(); + Match.newBuilder().setCondition(ERROR_VALUE).setResult(Result.ofOutput(ERROR_VALUE)).build(); private static final Variable ERROR_VARIABLE = - Variable.newBuilder().setName(ValueString.newBuilder().setValue(ERROR).build()).build(); + Variable.newBuilder().setExpression(ERROR_VALUE).setName(ERROR_VALUE).build(); private final TagVisitor tagVisitor; @@ -272,6 +270,10 @@ public CelPolicy.Variable parseVariable( } } + if (!assertRequiredFields(ctx, id, builder.getMissingRequiredFieldNames())) { + return ERROR_VARIABLE; + } + return builder.build(); } diff --git a/policy/src/test/java/dev/cel/policy/CelPolicyYamlParserTest.java b/policy/src/test/java/dev/cel/policy/CelPolicyYamlParserTest.java index 7e4d8c412..5bc90cfb9 100644 --- a/policy/src/test/java/dev/cel/policy/CelPolicyYamlParserTest.java +++ b/policy/src/test/java/dev/cel/policy/CelPolicyYamlParserTest.java @@ -134,10 +134,28 @@ private enum PolicyParseErrorTestCase { "inputs:\n" + " - name: a\n" + " - name: b", "ERROR: :1:1: Unsupported policy tag: inputs\n" + " | inputs:\n" + " | ^"), UNSUPPORTED_VARIABLE_TAG( - "rule:\n" + " variables:\n" + " - name: 'true'\n" + " alt_name: 'bool_true'", - "ERROR: :4:7: Unsupported variable tag: alt_name\n" + "rule:\n" // + + " variables:\n" // + + " - name: 'hello'\n" // + + " expression: 'true'\n" // + + " alt_name: 'bool_true'", + "ERROR: :5:7: Unsupported variable tag: alt_name\n" + " | alt_name: 'bool_true'\n" + " | ......^"), + MISSING_VARIABLE_NAME( + "rule:\n" // + + " variables:\n" // + + " - expression: 'true'", // + "ERROR: :3:7: Missing required attribute(s): name\n" + + " | - expression: 'true'\n" + + " | ......^"), + MISSING_VARIABLE_EXPRESSION( + "rule:\n" // + + " variables:\n" // + + " - name: 'hello'", // + "ERROR: :3:7: Missing required attribute(s): expression\n" + + " | - name: 'hello'\n" + + " | ......^"), UNSUPPORTED_MATCH_TAG( "rule:\n" + " match:\n" From 393da34c75bf2206b43269214a84526e7f727413 Mon Sep 17 00:00:00 2001 From: Tristan Swadell Date: Mon, 8 Jul 2024 11:20:52 -0700 Subject: [PATCH 153/486] Return `Optional.empty()` rather than Precondition fail When computing source location offsets, a precondition check to verify value lines and columns was causing upstream callers to fail rather than returning the empty optional. The change simply reverts to an empty optional on unsupported input ranges. PiperOrigin-RevId: 650315192 --- common/src/main/java/dev/cel/common/CelSource.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/common/src/main/java/dev/cel/common/CelSource.java b/common/src/main/java/dev/cel/common/CelSource.java index cc9244e30..1c8d4dbe8 100644 --- a/common/src/main/java/dev/cel/common/CelSource.java +++ b/common/src/main/java/dev/cel/common/CelSource.java @@ -125,8 +125,9 @@ public Optional getSnippet(int line) { */ private static Optional getLocationOffsetImpl( List lineOffsets, int line, int column) { - checkArgument(line > 0); - checkArgument(column >= 0); + if (line <= 0 || column < 0) { + return Optional.empty(); + } int offset = CelSourceHelper.findLineOffset(lineOffsets, line); if (offset == -1) { return Optional.empty(); From 041b37eab4e211114d76f879a6955383ea0106eb Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Mon, 8 Jul 2024 12:03:00 -0700 Subject: [PATCH 154/486] Internal Changes PiperOrigin-RevId: 650329658 --- policy/BUILD.bazel | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/policy/BUILD.bazel b/policy/BUILD.bazel index 8d7b5d909..a63a0752c 100644 --- a/policy/BUILD.bazel +++ b/policy/BUILD.bazel @@ -1,6 +1,6 @@ package( default_applicable_licenses = ["//:license"], - default_visibility = ["//visibility:public"], # TODO: Expose to public + default_visibility = ["//visibility:public"], ) java_library( From 8321498c554bc33585a9bdb6b45e05db3d9d4023 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Thu, 11 Jul 2024 14:43:46 -0700 Subject: [PATCH 155/486] Compute absolute source location correctly for multiline YAML strings PiperOrigin-RevId: 651540935 --- .../src/main/java/dev/cel/policy/BUILD.bazel | 2 +- .../dev/cel/policy/CelPolicyCompilerImpl.java | 26 +++-- .../cel/policy/CelPolicyYamlConfigParser.java | 9 +- .../dev/cel/policy/CelPolicyYamlParser.java | 17 ++-- .../dev/cel/policy/YamlParserContextImpl.java | 65 ++++++++++--- .../cel/policy/CelPolicyCompilerImplTest.java | 94 ++++++++++++++++++- 6 files changed, 177 insertions(+), 36 deletions(-) diff --git a/policy/src/main/java/dev/cel/policy/BUILD.bazel b/policy/src/main/java/dev/cel/policy/BUILD.bazel index e334293da..9e42067fb 100644 --- a/policy/src/main/java/dev/cel/policy/BUILD.bazel +++ b/policy/src/main/java/dev/cel/policy/BUILD.bazel @@ -321,10 +321,10 @@ java_library( visibility = ["//visibility:private"], deps = [ ":parser_context", + ":source", ":value_string", "//common", "//common:compiler_common", - "//common/internal", "@maven//:com_google_guava_guava", "@maven//:org_yaml_snakeyaml", ], diff --git a/policy/src/main/java/dev/cel/policy/CelPolicyCompilerImpl.java b/policy/src/main/java/dev/cel/policy/CelPolicyCompilerImpl.java index c2f1516db..7ec28d546 100644 --- a/policy/src/main/java/dev/cel/policy/CelPolicyCompilerImpl.java +++ b/policy/src/main/java/dev/cel/policy/CelPolicyCompilerImpl.java @@ -149,15 +149,29 @@ private static final class CompilerContext { private void addIssue(long id, List issues) { for (CelIssue issue : issues) { - // Compute relative source and add them into the issues set - int position = Optional.ofNullable(celPolicySource.getPositionsMap().get(id)).orElse(-1); - position += issue.getSourceLocation().getColumn(); - CelSourceLocation loc = - celPolicySource.getOffsetLocation(position).orElse(CelSourceLocation.NONE); - this.issues.add(CelIssue.formatError(loc, issue.getMessage())); + CelSourceLocation absoluteLocation = computeAbsoluteLocation(id, issue); + this.issues.add(CelIssue.formatError(absoluteLocation, issue.getMessage())); } } + private CelSourceLocation computeAbsoluteLocation(long id, CelIssue issue) { + int policySourceOffset = + Optional.ofNullable(celPolicySource.getPositionsMap().get(id)).orElse(-1); + CelSourceLocation policySourceLocation = + celPolicySource.getOffsetLocation(policySourceOffset).orElse(null); + if (policySourceLocation == null) { + return CelSourceLocation.NONE; + } + + int absoluteLine = issue.getSourceLocation().getLine() + policySourceLocation.getLine() - 1; + int absoluteColumn = issue.getSourceLocation().getColumn() + policySourceLocation.getColumn(); + int absoluteOffset = celPolicySource.getContent().lineOffsets().get(absoluteLine - 2); + + return celPolicySource + .getOffsetLocation(absoluteOffset + absoluteColumn) + .orElse(CelSourceLocation.NONE); + } + private void addNewVarDecl(CelVarDecl newVarDecl) { newVariableDeclarations.add(newVarDecl); } diff --git a/policy/src/main/java/dev/cel/policy/CelPolicyYamlConfigParser.java b/policy/src/main/java/dev/cel/policy/CelPolicyYamlConfigParser.java index d8955fe2b..f0525f7ef 100644 --- a/policy/src/main/java/dev/cel/policy/CelPolicyYamlConfigParser.java +++ b/policy/src/main/java/dev/cel/policy/CelPolicyYamlConfigParser.java @@ -331,14 +331,13 @@ private CelPolicyConfig parseYaml(String source, String description) throw new CelPolicyValidationException("YAML document is malformed: " + e.getMessage(), e); } - CelCodePointArray configCodePointArray = CelCodePointArray.fromString(source); - ParserContext ctx = YamlParserContextImpl.newInstance(configCodePointArray); - CelPolicyConfig.Builder policyConfig = parseConfig(ctx, node); CelPolicySource configSource = - CelPolicySource.newBuilder(configCodePointArray) + CelPolicySource.newBuilder(CelCodePointArray.fromString(source)) .setDescription(description) - .setPositionsMap(ctx.getIdToOffsetMap()) .build(); + ParserContext ctx = YamlParserContextImpl.newInstance(configSource); + CelPolicyConfig.Builder policyConfig = parseConfig(ctx, node); + configSource = configSource.toBuilder().setPositionsMap(ctx.getIdToOffsetMap()).build(); if (!ctx.getIssues().isEmpty()) { throw new CelPolicyValidationException( diff --git a/policy/src/main/java/dev/cel/policy/CelPolicyYamlParser.java b/policy/src/main/java/dev/cel/policy/CelPolicyYamlParser.java index b1b96834d..541dfdfb3 100644 --- a/policy/src/main/java/dev/cel/policy/CelPolicyYamlParser.java +++ b/policy/src/main/java/dev/cel/policy/CelPolicyYamlParser.java @@ -61,14 +61,13 @@ public CelPolicy parse(String policySource, String description) private static class ParserImpl implements PolicyParserContext { private final TagVisitor tagVisitor; - private final CelCodePointArray policySource; - private final String description; + private final CelPolicySource policySource; private final ParserContext ctx; private CelPolicy parseYaml() throws CelPolicyValidationException { Node node; try { - node = YamlHelper.parseYamlSource(policySource.toString()); + node = YamlHelper.parseYamlSource(policySource.getContent().toString()); } catch (RuntimeException e) { throw new CelPolicyValidationException("YAML document is malformed: " + e.getMessage(), e); } @@ -86,11 +85,9 @@ private CelPolicy parseYaml() throws CelPolicyValidationException { @Override public CelPolicy parsePolicy(PolicyParserContext ctx, Node node) { CelPolicy.Builder policyBuilder = CelPolicy.newBuilder(); - CelPolicySource.Builder sourceBuilder = - CelPolicySource.newBuilder(policySource).setDescription(description); long id = ctx.collectMetadata(node); if (!assertYamlType(ctx, id, node, YamlNodeType.MAP)) { - return policyBuilder.setPolicySource(sourceBuilder.build()).build(); + return policyBuilder.setPolicySource(policySource).build(); } MappingNode rootNode = (MappingNode) node; @@ -117,7 +114,7 @@ public CelPolicy parsePolicy(PolicyParserContext ctx, Node node) { } return policyBuilder - .setPolicySource(sourceBuilder.setPositionsMap(ctx.getIdToOffsetMap()).build()) + .setPolicySource(policySource.toBuilder().setPositionsMap(ctx.getIdToOffsetMap()).build()) .build(); } @@ -279,8 +276,10 @@ public CelPolicy.Variable parseVariable( private ParserImpl(TagVisitor tagVisitor, String source, String description) { this.tagVisitor = tagVisitor; - this.policySource = CelCodePointArray.fromString(source); - this.description = description; + this.policySource = + CelPolicySource.newBuilder(CelCodePointArray.fromString(source)) + .setDescription(description) + .build(); this.ctx = YamlParserContextImpl.newInstance(policySource); } diff --git a/policy/src/main/java/dev/cel/policy/YamlParserContextImpl.java b/policy/src/main/java/dev/cel/policy/YamlParserContextImpl.java index d84b9f830..9dbf77f72 100644 --- a/policy/src/main/java/dev/cel/policy/YamlParserContextImpl.java +++ b/policy/src/main/java/dev/cel/policy/YamlParserContextImpl.java @@ -17,15 +17,16 @@ import static dev.cel.policy.YamlHelper.ERROR; import static dev.cel.policy.YamlHelper.assertYamlType; +import com.google.common.base.Strings; import dev.cel.common.CelIssue; import dev.cel.common.CelSourceLocation; -import dev.cel.common.internal.CelCodePointArray; import dev.cel.policy.YamlHelper.YamlNodeType; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.yaml.snakeyaml.DumperOptions; +import org.yaml.snakeyaml.DumperOptions.ScalarStyle; import org.yaml.snakeyaml.nodes.Node; import org.yaml.snakeyaml.nodes.ScalarNode; @@ -35,7 +36,7 @@ final class YamlParserContextImpl implements ParserContext { private final ArrayList issues; private final HashMap idToLocationMap; private final HashMap idToOffsetMap; - private final CelCodePointArray policyContent; + private final CelPolicySource policySource; private long id; @Override @@ -61,8 +62,32 @@ public ValueString newValueString(Node node) { } ScalarNode scalarNode = (ScalarNode) node; + ScalarStyle style = scalarNode.getScalarStyle(); + if (style.equals(ScalarStyle.FOLDED) || style.equals(ScalarStyle.LITERAL)) { + CelSourceLocation location = idToLocationMap.get(id); + int line = location.getLine(); + int column = location.getColumn(); + + String indent = Strings.padStart("", column, ' '); + String text = policySource.getSnippet(line).orElse(""); + StringBuilder raw = new StringBuilder(); + while (text.startsWith(indent)) { + line++; + raw.append(text); + text = policySource.getSnippet(line).orElse(""); + if (text.isEmpty()) { + break; + } + if (text.startsWith(indent)) { + raw.append("\n"); + } + } + + idToOffsetMap.compute(id, (k, offset) -> offset - column); + + return ValueString.of(id, raw.toString()); + } - // TODO: Compute relative source for multiline strings return ValueString.of(id, scalarNode.getValue()); } @@ -73,16 +98,34 @@ public long collectMetadata(Node node) { int column = node.getStartMark().getColumn(); if (node instanceof ScalarNode) { DumperOptions.ScalarStyle style = ((ScalarNode) node).getScalarStyle(); - if (style.equals(DumperOptions.ScalarStyle.SINGLE_QUOTED) - || style.equals(DumperOptions.ScalarStyle.DOUBLE_QUOTED)) { - column++; + switch (style) { + case SINGLE_QUOTED: + case DOUBLE_QUOTED: + column++; + break; + case LITERAL: + case FOLDED: + // For multi-lines, actual string content begins on next line + line++; + // Columns must be computed from the indentation + column = 0; + String snippet = policySource.getSnippet(line).orElse(""); + for (char c : snippet.toCharArray()) { + if (!Character.isWhitespace(c)) { + break; + } + column++; + } + break; + default: + break; } } idToLocationMap.put(id, CelSourceLocation.of(line, column)); int offset = 0; if (line > 1) { - offset = policyContent.lineOffsets().get(line - 2) + column; + offset = policySource.getContent().lineOffsets().get(line - 2) + column; } idToOffsetMap.put(id, offset); @@ -94,14 +137,14 @@ public long nextId() { return ++id; } - static ParserContext newInstance(CelCodePointArray policyContent) { - return new YamlParserContextImpl(policyContent); + static ParserContext newInstance(CelPolicySource source) { + return new YamlParserContextImpl(source); } - private YamlParserContextImpl(CelCodePointArray policyContent) { + private YamlParserContextImpl(CelPolicySource source) { this.issues = new ArrayList<>(); this.idToLocationMap = new HashMap<>(); this.idToOffsetMap = new HashMap<>(); - this.policyContent = policyContent; + this.policySource = source; } } diff --git a/policy/src/test/java/dev/cel/policy/CelPolicyCompilerImplTest.java b/policy/src/test/java/dev/cel/policy/CelPolicyCompilerImplTest.java index 188e9b199..22a18d69c 100644 --- a/policy/src/test/java/dev/cel/policy/CelPolicyCompilerImplTest.java +++ b/policy/src/test/java/dev/cel/policy/CelPolicyCompilerImplTest.java @@ -104,21 +104,35 @@ public void compileYamlPolicy_containsError_throws() throws Exception { + "ERROR: errors/policy.yaml:23:27: mismatched input '2' expecting {'}', ','}\n" + " | expression: \"{1:305 2:569}\"\n" + " | ..........................^\n" - + "ERROR: errors/policy.yaml:31:65: extraneous input ']' expecting ')'\n" + + "ERROR: errors/policy.yaml:31:75: extraneous input ']' expecting ')'\n" + " | \"missing one or more required labels:" + " %s\".format(variables.missing])\n" - + " | ................................................................^\n" - + "ERROR: errors/policy.yaml:34:57: undeclared reference to 'format' (in container" + + " | ..........................................................................^\n" + + "ERROR: errors/policy.yaml:34:67: undeclared reference to 'format' (in container" + " '')\n" + " | \"invalid values provided on one or more labels:" + " %s\".format([variables.invalid])\n" - + " | ........................................................^\n" + + " | ..................................................................^\n" + "ERROR: errors/policy.yaml:35:24: found no matching overload for '_==_' applied" + " to '(bool, string)' (candidates: (%A0, %A0))\n" + " | - condition: false == \"0\"\n" + " | .......................^"); } + @Test + public void compileYamlPolicy_multilineContainsError_throws( + @TestParameter MultilineErrorTest testCase) throws Exception { + String policyContent = testCase.yaml; + CelPolicy policy = POLICY_PARSER.parse(policyContent); + + CelPolicyValidationException e = + assertThrows( + CelPolicyValidationException.class, + () -> CelPolicyCompilerFactory.newPolicyCompiler(newCel()).build().compile(policy)); + + assertThat(e).hasMessageThat().isEqualTo(testCase.expected); + } + @Test @SuppressWarnings("unchecked") public void evaluateYamlPolicy_withCanonicalTestData( @@ -246,4 +260,76 @@ private static Cel newCel() { })) .build(); } + + private enum MultilineErrorTest { + SINGLE_FOLDED( + "name: \"errors\"\n" + + "rule:\n" + + " match:\n" + + " - output: >\n" + + " 'test'.format(variables.missing])", + "ERROR: :5:40: extraneous input ']' expecting ')'\n" + + " | 'test'.format(variables.missing])\n" + + " | .......................................^"), + DOUBLE_FOLDED( + "name: \"errors\"\n" + + "rule:\n" + + " match:\n" + + " - output: >\n" + + " 'test'.format(\n" + + " variables.missing])", + "ERROR: :6:26: extraneous input ']' expecting ')'\n" + + " | variables.missing])\n" + + " | .........................^"), + TRIPLE_FOLDED( + "name: \"errors\"\n" + + "rule:\n" + + " match:\n" + + " - output: >\n" + + " 'test'.\n" + + " format(\n" + + " variables.missing])", + "ERROR: :7:26: extraneous input ']' expecting ')'\n" + + " | variables.missing])\n" + + " | .........................^"), + SINGLE_LITERAL( + "name: \"errors\"\n" + + "rule:\n" + + " match:\n" + + " - output: |\n" + + " 'test'.format(variables.missing])", + "ERROR: :5:40: extraneous input ']' expecting ')'\n" + + " | 'test'.format(variables.missing])\n" + + " | .......................................^"), + DOUBLE_LITERAL( + "name: \"errors\"\n" + + "rule:\n" + + " match:\n" + + " - output: |\n" + + " 'test'.format(\n" + + " variables.missing])", + "ERROR: :6:26: extraneous input ']' expecting ')'\n" + + " | variables.missing])\n" + + " | .........................^"), + TRIPLE_LITERAL( + "name: \"errors\"\n" + + "rule:\n" + + " match:\n" + + " - output: |\n" + + " 'test'.\n" + + " format(\n" + + " variables.missing])", + "ERROR: :7:26: extraneous input ']' expecting ')'\n" + + " | variables.missing])\n" + + " | .........................^"), + ; + + private final String yaml; + private final String expected; + + MultilineErrorTest(String yaml, String expected) { + this.yaml = yaml; + this.expected = expected; + } + } } From e7c246bb758e71d7eaf5fe9b7a5e8ca8d9990bae Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Thu, 11 Jul 2024 15:19:04 -0700 Subject: [PATCH 156/486] Make iteration limit configurable for rule composer PiperOrigin-RevId: 651551461 --- .../cel/policy/CelPolicyCompilerBuilder.java | 8 +++++++ .../dev/cel/policy/CelPolicyCompilerImpl.java | 24 +++++++++++++++---- .../java/dev/cel/policy/RuleComposer.java | 15 ++++++++---- 3 files changed, 38 insertions(+), 9 deletions(-) diff --git a/policy/src/main/java/dev/cel/policy/CelPolicyCompilerBuilder.java b/policy/src/main/java/dev/cel/policy/CelPolicyCompilerBuilder.java index a56054e03..13bac2885 100644 --- a/policy/src/main/java/dev/cel/policy/CelPolicyCompilerBuilder.java +++ b/policy/src/main/java/dev/cel/policy/CelPolicyCompilerBuilder.java @@ -20,9 +20,17 @@ /** Interface for building an instance of {@link CelPolicyCompiler} */ public interface CelPolicyCompilerBuilder { + /** Sets the prefix for the policy variables. Default is `variables.`. */ @CanIgnoreReturnValue CelPolicyCompilerBuilder setVariablesPrefix(String prefix); + /** + * Limit the number of iteration while composing rules into a single AST. An exception is thrown + * if the iteration count exceeds the set value. + */ + @CanIgnoreReturnValue + CelPolicyCompilerBuilder setIterationLimit(int iterationLimit); + @CheckReturnValue CelPolicyCompiler build(); } diff --git a/policy/src/main/java/dev/cel/policy/CelPolicyCompilerImpl.java b/policy/src/main/java/dev/cel/policy/CelPolicyCompilerImpl.java index 7ec28d546..7c9e8dcce 100644 --- a/policy/src/main/java/dev/cel/policy/CelPolicyCompilerImpl.java +++ b/policy/src/main/java/dev/cel/policy/CelPolicyCompilerImpl.java @@ -44,8 +44,10 @@ /** Package-private implementation for policy compiler. */ final class CelPolicyCompilerImpl implements CelPolicyCompiler { private static final String DEFAULT_VARIABLE_PREFIX = "variables."; + private static final int DEFAULT_ITERATION_LIMIT = 1000; private final Cel cel; private final String variablesPrefix; + private final int iterationLimit; @Override public CelAbstractSyntaxTree compile(CelPolicy policy) throws CelPolicyValidationException { @@ -59,7 +61,10 @@ public CelAbstractSyntaxTree compile(CelPolicy policy) throws CelPolicyValidatio CelOptimizerFactory.standardCelOptimizerBuilder(compiledRule.cel()) .addAstOptimizers( RuleComposer.newInstance( - compiledRule, compilerContext.newVariableDeclarations, variablesPrefix)) + compiledRule, + compilerContext.newVariableDeclarations, + variablesPrefix, + iterationLimit)) .build(); CelAbstractSyntaxTree ast; @@ -194,6 +199,7 @@ private CompilerContext(CelPolicySource celPolicySource) { static final class Builder implements CelPolicyCompilerBuilder { private final Cel cel; private String variablesPrefix; + private int iterationLimit; private Builder(Cel cel) { this.cel = cel; @@ -206,18 +212,28 @@ public Builder setVariablesPrefix(String prefix) { return this; } + @Override + @CanIgnoreReturnValue + public Builder setIterationLimit(int iterationLimit) { + this.iterationLimit = iterationLimit; + return this; + } + @Override public CelPolicyCompiler build() { - return new CelPolicyCompilerImpl(cel, this.variablesPrefix); + return new CelPolicyCompilerImpl(cel, this.variablesPrefix, this.iterationLimit); } } static Builder newBuilder(Cel cel) { - return new Builder(cel).setVariablesPrefix(DEFAULT_VARIABLE_PREFIX); + return new Builder(cel) + .setVariablesPrefix(DEFAULT_VARIABLE_PREFIX) + .setIterationLimit(DEFAULT_ITERATION_LIMIT); } - private CelPolicyCompilerImpl(Cel cel, String variablesPrefix) { + private CelPolicyCompilerImpl(Cel cel, String variablesPrefix, int iterationLimit) { this.cel = checkNotNull(cel); this.variablesPrefix = checkNotNull(variablesPrefix); + this.iterationLimit = iterationLimit; } } diff --git a/policy/src/main/java/dev/cel/policy/RuleComposer.java b/policy/src/main/java/dev/cel/policy/RuleComposer.java index 9650b04a7..c449bf7ac 100644 --- a/policy/src/main/java/dev/cel/policy/RuleComposer.java +++ b/policy/src/main/java/dev/cel/policy/RuleComposer.java @@ -34,7 +34,6 @@ /** Package-private class for composing various rules into a single expression using optimizer. */ final class RuleComposer implements CelAstOptimizer { - private static final int AST_MUTATOR_ITERATION_LIMIT = 1000; private final CelCompiledRule compiledRule; private final ImmutableList newVarDecls; private final String variablePrefix; @@ -121,15 +120,21 @@ private RuleOptimizationResult optimizeRule(CelCompiledRule compiledRule) { } static RuleComposer newInstance( - CelCompiledRule compiledRule, List newVarDecls, String variablePrefix) { - return new RuleComposer(compiledRule, newVarDecls, variablePrefix); + CelCompiledRule compiledRule, + List newVarDecls, + String variablePrefix, + int iterationLimit) { + return new RuleComposer(compiledRule, newVarDecls, variablePrefix, iterationLimit); } private RuleComposer( - CelCompiledRule compiledRule, List newVarDecls, String variablePrefix) { + CelCompiledRule compiledRule, + List newVarDecls, + String variablePrefix, + int iterationLimit) { this.compiledRule = checkNotNull(compiledRule); this.newVarDecls = ImmutableList.copyOf(checkNotNull(newVarDecls)); this.variablePrefix = variablePrefix; - this.astMutator = AstMutator.newInstance(AST_MUTATOR_ITERATION_LIMIT); + this.astMutator = AstMutator.newInstance(iterationLimit); } } From d20d37787b91d6f3282f35484270b08374aade00 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Mon, 15 Jul 2024 10:22:53 -0700 Subject: [PATCH 157/486] Decompose policy compile API into rule compilation and composition PiperOrigin-RevId: 652523792 --- policy/BUILD.bazel | 5 ++ .../src/main/java/dev/cel/policy/BUILD.bazel | 28 +++++----- .../java/dev/cel/policy/CelCompiledRule.java | 52 ++++++++++++------- .../dev/cel/policy/CelPolicyCompiler.java | 23 ++++++-- .../dev/cel/policy/CelPolicyCompilerImpl.java | 30 +++++------ .../java/dev/cel/policy/RuleComposer.java | 25 ++++----- 6 files changed, 96 insertions(+), 67 deletions(-) diff --git a/policy/BUILD.bazel b/policy/BUILD.bazel index a63a0752c..4773984b4 100644 --- a/policy/BUILD.bazel +++ b/policy/BUILD.bazel @@ -8,6 +8,11 @@ java_library( exports = ["//policy/src/main/java/dev/cel/policy"], ) +java_library( + name = "compiled_rule", + exports = ["//policy/src/main/java/dev/cel/policy:compiled_rule"], +) + java_library( name = "value_string", exports = ["//policy/src/main/java/dev/cel/policy:value_string"], diff --git a/policy/src/main/java/dev/cel/policy/BUILD.bazel b/policy/src/main/java/dev/cel/policy/BUILD.bazel index 9e42067fb..562f14722 100644 --- a/policy/src/main/java/dev/cel/policy/BUILD.bazel +++ b/policy/src/main/java/dev/cel/policy/BUILD.bazel @@ -155,6 +155,7 @@ java_library( tags = [ ], deps = [ + ":compiled_rule", ":policy", ":validation_exception", "//common", @@ -217,6 +218,19 @@ java_library( ], ) +java_library( + name = "compiled_rule", + srcs = ["CelCompiledRule.java"], + deps = [ + "//:auto_value", + "//bundle:cel", + "//common", + "//common:compiler_common", + "@maven//:com_google_errorprone_error_prone_annotations", + "@maven//:com_google_guava_guava", + ], +) + java_library( name = "compiler_impl", srcs = [ @@ -278,19 +292,6 @@ java_library( ], ) -java_library( - name = "compiled_rule", - srcs = ["CelCompiledRule.java"], - visibility = ["//visibility:private"], - deps = [ - "//:auto_value", - "//bundle:cel", - "//common", - "@maven//:com_google_errorprone_error_prone_annotations", - "@maven//:com_google_guava_guava", - ], -) - java_library( name = "rule_composer", srcs = ["RuleComposer.java"], @@ -300,7 +301,6 @@ java_library( "//:auto_value", "//bundle:cel", "//common", - "//common:compiler_common", "//common:mutable_ast", "//common/ast", "//extensions:optional_library", diff --git a/policy/src/main/java/dev/cel/policy/CelCompiledRule.java b/policy/src/main/java/dev/cel/policy/CelCompiledRule.java index f7ee8340d..a5fd23515 100644 --- a/policy/src/main/java/dev/cel/policy/CelCompiledRule.java +++ b/policy/src/main/java/dev/cel/policy/CelCompiledRule.java @@ -19,40 +19,55 @@ import com.google.common.collect.ImmutableList; import dev.cel.bundle.Cel; import dev.cel.common.CelAbstractSyntaxTree; +import dev.cel.common.CelVarDecl; -/** Abstract representation of a compiled rule. */ +/** + * Abstract representation of a compiled rule. This contains set of compiled variables and match + * statements which defines an expression graph for a policy. + */ @AutoValue -abstract class CelCompiledRule { - abstract ImmutableList variables(); +public abstract class CelCompiledRule { + public abstract ImmutableList variables(); - abstract ImmutableList matches(); + public abstract ImmutableList matches(); - abstract Cel cel(); + public abstract Cel cel(); + /** + * A compiled policy variable (ex: variables.foo). Note that this is not the same thing as the + * variables declared in the config. + */ @AutoValue - abstract static class CelCompiledVariable { - abstract String name(); + public abstract static class CelCompiledVariable { + public abstract String name(); - abstract CelAbstractSyntaxTree ast(); + /** Compiled variable in AST. */ + public abstract CelAbstractSyntaxTree ast(); - static CelCompiledVariable create(String name, CelAbstractSyntaxTree ast) { - return new AutoValue_CelCompiledRule_CelCompiledVariable(name, ast); + /** The variable declaration used to compile this variable in {@link #ast}. */ + public abstract CelVarDecl celVarDecl(); + + static CelCompiledVariable create( + String name, CelAbstractSyntaxTree ast, CelVarDecl celVarDecl) { + return new AutoValue_CelCompiledRule_CelCompiledVariable(name, ast, celVarDecl); } } + /** A compiled Match. */ @AutoValue - abstract static class CelCompiledMatch { - abstract CelAbstractSyntaxTree condition(); + public abstract static class CelCompiledMatch { + public abstract CelAbstractSyntaxTree condition(); - abstract Result result(); + public abstract Result result(); + /** Encapsulates the result of this match when condition is met. (either an output or a rule) */ @AutoOneOf(CelCompiledMatch.Result.Kind.class) - abstract static class Result { - abstract CelAbstractSyntaxTree output(); + public abstract static class Result { + public abstract CelAbstractSyntaxTree output(); - abstract CelCompiledRule rule(); + public abstract CelCompiledRule rule(); - abstract Kind kind(); + public abstract Kind kind(); static Result ofOutput(CelAbstractSyntaxTree value) { return AutoOneOf_CelCompiledRule_CelCompiledMatch_Result.output(value); @@ -62,7 +77,8 @@ static Result ofRule(CelCompiledRule value) { return AutoOneOf_CelCompiledRule_CelCompiledMatch_Result.rule(value); } - enum Kind { + /** Kind for {@link Result}. */ + public enum Kind { OUTPUT, RULE } diff --git a/policy/src/main/java/dev/cel/policy/CelPolicyCompiler.java b/policy/src/main/java/dev/cel/policy/CelPolicyCompiler.java index 6a63f0389..b1dae87e5 100644 --- a/policy/src/main/java/dev/cel/policy/CelPolicyCompiler.java +++ b/policy/src/main/java/dev/cel/policy/CelPolicyCompiler.java @@ -20,8 +20,25 @@ public interface CelPolicyCompiler { /** - * Generates a single CEL AST from a collection of policy expressions associated with a CEL - * environment. + * Combines the {@link #compileRule} and {@link #compose} into a single call. + * + *

This generates a single CEL AST from a collection of policy expressions associated with a + * CEL environment. */ - CelAbstractSyntaxTree compile(CelPolicy policy) throws CelPolicyValidationException; + default CelAbstractSyntaxTree compile(CelPolicy policy) throws CelPolicyValidationException { + return compose(compileRule(policy)); + } + + /** + * Produces a {@link CelCompiledRule} from the policy which contains a set of compiled variables + * and match statements. Compiled rule defines an expression graph, which can be composed into a + * single expression via {@link #compose} call. + */ + CelCompiledRule compileRule(CelPolicy policy) throws CelPolicyValidationException; + + /** + * Composes {@link CelCompiledRule}, representing an expression graph, into a single expression + * value. + */ + CelAbstractSyntaxTree compose(CelCompiledRule compiledRule) throws CelPolicyValidationException; } diff --git a/policy/src/main/java/dev/cel/policy/CelPolicyCompilerImpl.java b/policy/src/main/java/dev/cel/policy/CelPolicyCompilerImpl.java index 7c9e8dcce..f8884a911 100644 --- a/policy/src/main/java/dev/cel/policy/CelPolicyCompilerImpl.java +++ b/policy/src/main/java/dev/cel/policy/CelPolicyCompilerImpl.java @@ -50,21 +50,23 @@ final class CelPolicyCompilerImpl implements CelPolicyCompiler { private final int iterationLimit; @Override - public CelAbstractSyntaxTree compile(CelPolicy policy) throws CelPolicyValidationException { + public CelCompiledRule compileRule(CelPolicy policy) throws CelPolicyValidationException { CompilerContext compilerContext = new CompilerContext(policy.policySource()); - CelCompiledRule compiledRule = compileRule(policy.rule(), cel, compilerContext); + CelCompiledRule compiledRule = compileRuleImpl(policy.rule(), cel, compilerContext); if (compilerContext.hasError()) { throw new CelPolicyValidationException(compilerContext.getIssueString()); } + return compiledRule; + } + + @Override + public CelAbstractSyntaxTree compose(CelCompiledRule compiledRule) + throws CelPolicyValidationException { CelOptimizer optimizer = CelOptimizerFactory.standardCelOptimizerBuilder(compiledRule.cel()) .addAstOptimizers( - RuleComposer.newInstance( - compiledRule, - compilerContext.newVariableDeclarations, - variablesPrefix, - iterationLimit)) + RuleComposer.newInstance(compiledRule, variablesPrefix, iterationLimit)) .build(); CelAbstractSyntaxTree ast; @@ -82,7 +84,7 @@ public CelAbstractSyntaxTree compile(CelPolicy policy) throws CelPolicyValidatio return ast; } - private CelCompiledRule compileRule( + private CelCompiledRule compileRuleImpl( CelPolicy.Rule rule, Cel ruleCel, CompilerContext compilerContext) { ImmutableList.Builder variableBuilder = ImmutableList.builder(); for (Variable variable : rule.variables()) { @@ -100,9 +102,8 @@ private CelCompiledRule compileRule( String variableName = variable.name().value(); CelVarDecl newVariable = CelVarDecl.newVarDeclaration(variablesPrefix + variableName, outputType); - compilerContext.addNewVarDecl(newVariable); ruleCel = ruleCel.toCelBuilder().addVarDeclarations(newVariable).build(); - variableBuilder.add(CelCompiledVariable.create(variableName, varAst)); + variableBuilder.add(CelCompiledVariable.create(variableName, varAst, newVariable)); } ImmutableList.Builder matchBuilder = ImmutableList.builder(); @@ -129,7 +130,8 @@ private CelCompiledRule compileRule( matchResult = Result.ofOutput(outputAst); break; case RULE: - CelCompiledRule nestedRule = compileRule(match.result().rule(), ruleCel, compilerContext); + CelCompiledRule nestedRule = + compileRuleImpl(match.result().rule(), ruleCel, compilerContext); matchResult = Result.ofRule(nestedRule); break; default: @@ -149,7 +151,6 @@ private static CelAbstractSyntaxTree newErrorAst() { private static final class CompilerContext { private final ArrayList issues; - private final ArrayList newVariableDeclarations; private final CelPolicySource celPolicySource; private void addIssue(long id, List issues) { @@ -177,10 +178,6 @@ private CelSourceLocation computeAbsoluteLocation(long id, CelIssue issue) { .orElse(CelSourceLocation.NONE); } - private void addNewVarDecl(CelVarDecl newVarDecl) { - newVariableDeclarations.add(newVarDecl); - } - private boolean hasError() { return !issues.isEmpty(); } @@ -191,7 +188,6 @@ private String getIssueString() { private CompilerContext(CelPolicySource celPolicySource) { this.issues = new ArrayList<>(); - this.newVariableDeclarations = new ArrayList<>(); this.celPolicySource = celPolicySource; } } diff --git a/policy/src/main/java/dev/cel/policy/RuleComposer.java b/policy/src/main/java/dev/cel/policy/RuleComposer.java index c449bf7ac..77a82b73c 100644 --- a/policy/src/main/java/dev/cel/policy/RuleComposer.java +++ b/policy/src/main/java/dev/cel/policy/RuleComposer.java @@ -15,6 +15,7 @@ package dev.cel.policy; import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.collect.ImmutableList.toImmutableList; import com.google.auto.value.AutoValue; import com.google.common.collect.ImmutableList; @@ -22,7 +23,6 @@ import dev.cel.bundle.Cel; import dev.cel.common.CelAbstractSyntaxTree; import dev.cel.common.CelMutableAst; -import dev.cel.common.CelVarDecl; import dev.cel.common.ast.CelConstant.Kind; import dev.cel.extensions.CelOptionalLibrary.Function; import dev.cel.optimizer.AstMutator; @@ -30,19 +30,22 @@ import dev.cel.parser.Operator; import dev.cel.policy.CelCompiledRule.CelCompiledMatch; import dev.cel.policy.CelCompiledRule.CelCompiledVariable; -import java.util.List; /** Package-private class for composing various rules into a single expression using optimizer. */ final class RuleComposer implements CelAstOptimizer { private final CelCompiledRule compiledRule; - private final ImmutableList newVarDecls; private final String variablePrefix; private final AstMutator astMutator; @Override public OptimizationResult optimize(CelAbstractSyntaxTree ast, Cel cel) { RuleOptimizationResult result = optimizeRule(compiledRule); - return OptimizationResult.create(result.ast().toParsedAst(), newVarDecls, ImmutableList.of()); + return OptimizationResult.create( + result.ast().toParsedAst(), + compiledRule.variables().stream() + .map(CelCompiledVariable::celVarDecl) + .collect(toImmutableList()), + ImmutableList.of()); } @AutoValue @@ -120,20 +123,12 @@ private RuleOptimizationResult optimizeRule(CelCompiledRule compiledRule) { } static RuleComposer newInstance( - CelCompiledRule compiledRule, - List newVarDecls, - String variablePrefix, - int iterationLimit) { - return new RuleComposer(compiledRule, newVarDecls, variablePrefix, iterationLimit); + CelCompiledRule compiledRule, String variablePrefix, int iterationLimit) { + return new RuleComposer(compiledRule, variablePrefix, iterationLimit); } - private RuleComposer( - CelCompiledRule compiledRule, - List newVarDecls, - String variablePrefix, - int iterationLimit) { + private RuleComposer(CelCompiledRule compiledRule, String variablePrefix, int iterationLimit) { this.compiledRule = checkNotNull(compiledRule); - this.newVarDecls = ImmutableList.copyOf(checkNotNull(newVarDecls)); this.variablePrefix = variablePrefix; this.astMutator = AstMutator.newInstance(iterationLimit); } From 9f78ec3fc0ce4a52f8593bb06af5c62d240187e9 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Mon, 15 Jul 2024 15:51:38 -0700 Subject: [PATCH 158/486] Surface type-mismatch errors in a readable fashion during rule composition PiperOrigin-RevId: 652621800 --- .../src/main/java/dev/cel/policy/BUILD.bazel | 3 + .../java/dev/cel/policy/CelCompiledRule.java | 28 ++++++- .../dev/cel/policy/CelPolicyCompiler.java | 5 +- .../dev/cel/policy/CelPolicyCompilerImpl.java | 50 +++++++++++-- .../java/dev/cel/policy/RuleComposer.java | 75 ++++++++++++++++--- .../cel/policy/CelPolicyCompilerImplTest.java | 72 +++++++++--------- policy/src/test/resources/BUILD.bazel | 2 +- .../{errors => compile_errors}/config.yaml | 0 .../compile_errors/expected_errors.baseline | 24 ++++++ .../{errors => compile_errors}/policy.yaml | 5 +- .../config.yaml | 22 ++++++ .../expected_errors.baseline | 6 ++ .../policy.yaml | 23 ++++++ .../config.yaml | 22 ++++++ .../expected_errors.baseline | 3 + .../policy.yaml | 37 +++++++++ 16 files changed, 316 insertions(+), 61 deletions(-) rename policy/src/test/resources/{errors => compile_errors}/config.yaml (100%) create mode 100644 policy/src/test/resources/compile_errors/expected_errors.baseline rename policy/src/test/resources/{errors => compile_errors}/policy.yaml (92%) create mode 100644 policy/src/test/resources/compose_errors_conflicting_output/config.yaml create mode 100644 policy/src/test/resources/compose_errors_conflicting_output/expected_errors.baseline create mode 100644 policy/src/test/resources/compose_errors_conflicting_output/policy.yaml create mode 100644 policy/src/test/resources/compose_errors_conflicting_subrule/config.yaml create mode 100644 policy/src/test/resources/compose_errors_conflicting_subrule/expected_errors.baseline create mode 100644 policy/src/test/resources/compose_errors_conflicting_subrule/policy.yaml diff --git a/policy/src/main/java/dev/cel/policy/BUILD.bazel b/policy/src/main/java/dev/cel/policy/BUILD.bazel index 562f14722..15e2977c2 100644 --- a/policy/src/main/java/dev/cel/policy/BUILD.bazel +++ b/policy/src/main/java/dev/cel/policy/BUILD.bazel @@ -222,6 +222,7 @@ java_library( name = "compiled_rule", srcs = ["CelCompiledRule.java"], deps = [ + ":value_string", "//:auto_value", "//bundle:cel", "//common", @@ -301,12 +302,14 @@ java_library( "//:auto_value", "//bundle:cel", "//common", + "//common:compiler_common", "//common:mutable_ast", "//common/ast", "//extensions:optional_library", "//optimizer:ast_optimizer", "//optimizer:mutable_ast", "//parser:operator", + "//policy:value_string", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", ], diff --git a/policy/src/main/java/dev/cel/policy/CelCompiledRule.java b/policy/src/main/java/dev/cel/policy/CelCompiledRule.java index a5fd23515..4c39fee94 100644 --- a/policy/src/main/java/dev/cel/policy/CelCompiledRule.java +++ b/policy/src/main/java/dev/cel/policy/CelCompiledRule.java @@ -20,6 +20,7 @@ import dev.cel.bundle.Cel; import dev.cel.common.CelAbstractSyntaxTree; import dev.cel.common.CelVarDecl; +import java.util.Optional; /** * Abstract representation of a compiled rule. This contains set of compiled variables and match @@ -27,6 +28,8 @@ */ @AutoValue public abstract class CelCompiledRule { + public abstract Optional id(); + public abstract ImmutableList variables(); public abstract ImmutableList matches(); @@ -63,14 +66,15 @@ public abstract static class CelCompiledMatch { /** Encapsulates the result of this match when condition is met. (either an output or a rule) */ @AutoOneOf(CelCompiledMatch.Result.Kind.class) public abstract static class Result { - public abstract CelAbstractSyntaxTree output(); + public abstract OutputValue output(); public abstract CelCompiledRule rule(); public abstract Kind kind(); - static Result ofOutput(CelAbstractSyntaxTree value) { - return AutoOneOf_CelCompiledRule_CelCompiledMatch_Result.output(value); + static Result ofOutput(long id, CelAbstractSyntaxTree ast) { + return AutoOneOf_CelCompiledRule_CelCompiledMatch_Result.output( + OutputValue.create(id, ast)); } static Result ofRule(CelCompiledRule value) { @@ -84,6 +88,21 @@ public enum Kind { } } + /** + * Encapsulates the output value of the match with its original ID that was used to compile + * with. + */ + @AutoValue + public abstract static class OutputValue { + public abstract long id(); + + public abstract CelAbstractSyntaxTree ast(); + + public static OutputValue create(long id, CelAbstractSyntaxTree ast) { + return new AutoValue_CelCompiledRule_CelCompiledMatch_OutputValue(id, ast); + } + } + static CelCompiledMatch create( CelAbstractSyntaxTree condition, CelCompiledMatch.Result result) { return new AutoValue_CelCompiledRule_CelCompiledMatch(condition, result); @@ -91,9 +110,10 @@ static CelCompiledMatch create( } static CelCompiledRule create( + Optional id, ImmutableList variables, ImmutableList matches, Cel cel) { - return new AutoValue_CelCompiledRule(variables, matches, cel); + return new AutoValue_CelCompiledRule(id, variables, matches, cel); } } diff --git a/policy/src/main/java/dev/cel/policy/CelPolicyCompiler.java b/policy/src/main/java/dev/cel/policy/CelPolicyCompiler.java index b1dae87e5..e0af6d85b 100644 --- a/policy/src/main/java/dev/cel/policy/CelPolicyCompiler.java +++ b/policy/src/main/java/dev/cel/policy/CelPolicyCompiler.java @@ -26,7 +26,7 @@ public interface CelPolicyCompiler { * CEL environment. */ default CelAbstractSyntaxTree compile(CelPolicy policy) throws CelPolicyValidationException { - return compose(compileRule(policy)); + return compose(policy, compileRule(policy)); } /** @@ -40,5 +40,6 @@ default CelAbstractSyntaxTree compile(CelPolicy policy) throws CelPolicyValidati * Composes {@link CelCompiledRule}, representing an expression graph, into a single expression * value. */ - CelAbstractSyntaxTree compose(CelCompiledRule compiledRule) throws CelPolicyValidationException; + CelAbstractSyntaxTree compose(CelPolicy policy, CelCompiledRule compiledRule) + throws CelPolicyValidationException; } diff --git a/policy/src/main/java/dev/cel/policy/CelPolicyCompilerImpl.java b/policy/src/main/java/dev/cel/policy/CelPolicyCompilerImpl.java index f8884a911..8ca38dad4 100644 --- a/policy/src/main/java/dev/cel/policy/CelPolicyCompilerImpl.java +++ b/policy/src/main/java/dev/cel/policy/CelPolicyCompilerImpl.java @@ -15,6 +15,7 @@ package dev.cel.policy; import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.collect.ImmutableList.toImmutableList; import com.google.common.collect.ImmutableList; import com.google.errorprone.annotations.CanIgnoreReturnValue; @@ -37,7 +38,9 @@ import dev.cel.policy.CelCompiledRule.CelCompiledVariable; import dev.cel.policy.CelPolicy.Match; import dev.cel.policy.CelPolicy.Variable; +import dev.cel.policy.RuleComposer.RuleCompositionException; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Optional; @@ -61,7 +64,7 @@ public CelCompiledRule compileRule(CelPolicy policy) throws CelPolicyValidationE } @Override - public CelAbstractSyntaxTree compose(CelCompiledRule compiledRule) + public CelAbstractSyntaxTree compose(CelPolicy policy, CelCompiledRule compiledRule) throws CelPolicyValidationException { CelOptimizer optimizer = CelOptimizerFactory.standardCelOptimizerBuilder(compiledRule.cel()) @@ -77,8 +80,28 @@ public CelAbstractSyntaxTree compose(CelCompiledRule compiledRule) ast = cel.compile("true").getAst(); ast = optimizer.optimize(ast); } catch (CelValidationException | CelOptimizationException e) { - // TODO: Surface these errors better - throw new CelPolicyValidationException("Failed composing the rules", e); + if (e.getCause() instanceof RuleCompositionException) { + RuleCompositionException re = (RuleCompositionException) e.getCause(); + CompilerContext compilerContext = new CompilerContext(policy.policySource()); + // The exact CEL error message produced from composition failure isn't too useful for users. + // Ex: ERROR: :1:1: found no matching overload for '_?_:_' applied to '(bool, map(int, int), + // bool)' (candidates: (bool, %A0, %A0)) + // Transform the error messages in a user-friendly way while retaining the original + // CelValidationException as its originating cause. + + ImmutableList transformedIssues = + re.compileException.getErrors().stream() + .map(x -> CelIssue.formatError(x.getSourceLocation(), re.failureReason)) + .collect(toImmutableList()); + for (long id : re.errorIds) { + compilerContext.addIssue(id, transformedIssues); + } + + throw new CelPolicyValidationException(compilerContext.getIssueString(), re.getCause()); + } + + // Something has gone seriously wrong. + throw new CelPolicyValidationException("Unexpected error while composing rules.", e); } return ast; @@ -111,6 +134,11 @@ private CelCompiledRule compileRuleImpl( CelAbstractSyntaxTree conditionAst; try { conditionAst = ruleCel.compile(match.condition().value()).getAst(); + if (!conditionAst.getResultType().equals(SimpleType.BOOL)) { + compilerContext.addIssue( + match.condition().id(), + CelIssue.formatError(1, 0, "condition must produce a boolean output.")); + } } catch (CelValidationException e) { compilerContext.addIssue(match.condition().id(), e.getErrors()); continue; @@ -120,14 +148,15 @@ private CelCompiledRule compileRuleImpl( switch (match.result().kind()) { case OUTPUT: CelAbstractSyntaxTree outputAst; + ValueString output = match.result().output(); try { - outputAst = ruleCel.compile(match.result().output().value()).getAst(); + outputAst = ruleCel.compile(output.value()).getAst(); } catch (CelValidationException e) { - compilerContext.addIssue(match.result().output().id(), e.getErrors()); + compilerContext.addIssue(output.id(), e.getErrors()); continue; } - matchResult = Result.ofOutput(outputAst); + matchResult = Result.ofOutput(output.id(), outputAst); break; case RULE: CelCompiledRule nestedRule = @@ -141,7 +170,7 @@ private CelCompiledRule compileRuleImpl( matchBuilder.add(CelCompiledMatch.create(conditionAst, matchResult)); } - return CelCompiledRule.create(variableBuilder.build(), matchBuilder.build(), cel); + return CelCompiledRule.create(rule.id(), variableBuilder.build(), matchBuilder.build(), cel); } private static CelAbstractSyntaxTree newErrorAst() { @@ -153,6 +182,10 @@ private static final class CompilerContext { private final ArrayList issues; private final CelPolicySource celPolicySource; + private void addIssue(long id, CelIssue... issues) { + addIssue(id, Arrays.asList(issues)); + } + private void addIssue(long id, List issues) { for (CelIssue issue : issues) { CelSourceLocation absoluteLocation = computeAbsoluteLocation(id, issue); @@ -163,6 +196,9 @@ private void addIssue(long id, List issues) { private CelSourceLocation computeAbsoluteLocation(long id, CelIssue issue) { int policySourceOffset = Optional.ofNullable(celPolicySource.getPositionsMap().get(id)).orElse(-1); + if (policySourceOffset == -1) { + return CelSourceLocation.NONE; + } CelSourceLocation policySourceLocation = celPolicySource.getOffsetLocation(policySourceOffset).orElse(null); if (policySourceLocation == null) { diff --git a/policy/src/main/java/dev/cel/policy/RuleComposer.java b/policy/src/main/java/dev/cel/policy/RuleComposer.java index 77a82b73c..732b60394 100644 --- a/policy/src/main/java/dev/cel/policy/RuleComposer.java +++ b/policy/src/main/java/dev/cel/policy/RuleComposer.java @@ -16,20 +16,25 @@ import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.collect.ImmutableList.toImmutableList; +import static java.util.stream.Collectors.toCollection; import com.google.auto.value.AutoValue; -import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import dev.cel.bundle.Cel; import dev.cel.common.CelAbstractSyntaxTree; import dev.cel.common.CelMutableAst; +import dev.cel.common.CelValidationException; import dev.cel.common.ast.CelConstant.Kind; import dev.cel.extensions.CelOptionalLibrary.Function; import dev.cel.optimizer.AstMutator; import dev.cel.optimizer.CelAstOptimizer; import dev.cel.parser.Operator; import dev.cel.policy.CelCompiledRule.CelCompiledMatch; +import dev.cel.policy.CelCompiledRule.CelCompiledMatch.OutputValue; import dev.cel.policy.CelCompiledRule.CelCompiledVariable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; /** Package-private class for composing various rules into a single expression using optimizer. */ final class RuleComposer implements CelAstOptimizer { @@ -39,13 +44,8 @@ final class RuleComposer implements CelAstOptimizer { @Override public OptimizationResult optimize(CelAbstractSyntaxTree ast, Cel cel) { - RuleOptimizationResult result = optimizeRule(compiledRule); - return OptimizationResult.create( - result.ast().toParsedAst(), - compiledRule.variables().stream() - .map(CelCompiledVariable::celVarDecl) - .collect(toImmutableList()), - ImmutableList.of()); + RuleOptimizationResult result = optimizeRule(cel, compiledRule); + return OptimizationResult.create(result.ast().toParsedAst()); } @AutoValue @@ -59,9 +59,20 @@ static RuleOptimizationResult create(CelMutableAst ast, boolean isOptionalResult } } - private RuleOptimizationResult optimizeRule(CelCompiledRule compiledRule) { + private RuleOptimizationResult optimizeRule(Cel cel, CelCompiledRule compiledRule) { + cel = + cel.toCelBuilder() + .addVarDeclarations( + compiledRule.variables().stream() + .map(CelCompiledVariable::celVarDecl) + .collect(toImmutableList())) + .build(); + CelMutableAst matchAst = astMutator.newGlobalCall(Function.OPTIONAL_NONE.getFunction()); boolean isOptionalResult = true; + // Keep track of the last output ID that might cause type-check failure while attempting to + // compose the subgraphs. + long lastOutputId = 0; for (CelCompiledMatch match : Lists.reverse(compiledRule.matches())) { CelAbstractSyntaxTree conditionAst = match.condition(); boolean isTriviallyTrue = @@ -69,10 +80,12 @@ private RuleOptimizationResult optimizeRule(CelCompiledRule compiledRule) { && conditionAst.getExpr().constant().booleanValue(); switch (match.result().kind()) { case OUTPUT: - CelMutableAst outAst = CelMutableAst.fromCelAst(match.result().output()); + OutputValue matchOutput = match.result().output(); + CelMutableAst outAst = CelMutableAst.fromCelAst(matchOutput.ast()); if (isTriviallyTrue) { matchAst = outAst; isOptionalResult = false; + lastOutputId = matchOutput.id(); continue; } if (isOptionalResult) { @@ -85,9 +98,13 @@ private RuleOptimizationResult optimizeRule(CelCompiledRule compiledRule) { CelMutableAst.fromCelAst(conditionAst), outAst, matchAst); + assertComposedAstIsValid( + cel, matchAst, "conflicting output types found.", matchOutput.id(), lastOutputId); + lastOutputId = matchOutput.id(); continue; case RULE: - RuleOptimizationResult nestedRule = optimizeRule(match.result().rule()); + CelCompiledRule matchNestedRule = match.result().rule(); + RuleOptimizationResult nestedRule = optimizeRule(cel, matchNestedRule); CelMutableAst nestedRuleAst = nestedRule.ast(); if (isOptionalResult && !nestedRule.isOptionalResult()) { nestedRuleAst = @@ -101,6 +118,13 @@ private RuleOptimizationResult optimizeRule(CelCompiledRule compiledRule) { throw new IllegalArgumentException("Subrule early terminates policy"); } matchAst = astMutator.newMemberCall(nestedRuleAst, Function.OR.getFunction(), matchAst); + assertComposedAstIsValid( + cel, + matchAst, + String.format( + "failed composing the subrule '%s' due to conflicting output types.", + matchNestedRule.id().map(ValueString::value).orElse("")), + lastOutputId); break; } } @@ -127,9 +151,38 @@ static RuleComposer newInstance( return new RuleComposer(compiledRule, variablePrefix, iterationLimit); } + private void assertComposedAstIsValid( + Cel cel, CelMutableAst composedAst, String failureMessage, Long... ids) { + assertComposedAstIsValid(cel, composedAst, failureMessage, Arrays.asList(ids)); + } + + private void assertComposedAstIsValid( + Cel cel, CelMutableAst composedAst, String failureMessage, List ids) { + try { + cel.check(composedAst.toParsedAst()).getAst(); + } catch (CelValidationException e) { + ids = ids.stream().filter(id -> id > 0).collect(toCollection(ArrayList::new)); + throw new RuleCompositionException(failureMessage, e, ids); + } + } + private RuleComposer(CelCompiledRule compiledRule, String variablePrefix, int iterationLimit) { this.compiledRule = checkNotNull(compiledRule); this.variablePrefix = variablePrefix; this.astMutator = AstMutator.newInstance(iterationLimit); } + + static final class RuleCompositionException extends RuntimeException { + final String failureReason; + final List errorIds; + final CelValidationException compileException; + + private RuleCompositionException( + String failureReason, CelValidationException e, List errorIds) { + super(e); + this.failureReason = failureReason; + this.errorIds = errorIds; + this.compileException = e; + } + } } diff --git a/policy/src/test/java/dev/cel/policy/CelPolicyCompilerImplTest.java b/policy/src/test/java/dev/cel/policy/CelPolicyCompilerImplTest.java index 22a18d69c..30915be4a 100644 --- a/policy/src/test/java/dev/cel/policy/CelPolicyCompilerImplTest.java +++ b/policy/src/test/java/dev/cel/policy/CelPolicyCompilerImplTest.java @@ -40,6 +40,7 @@ import dev.cel.policy.PolicyTestHelper.TestYamlPolicy; import dev.cel.runtime.CelRuntime.CelFunctionBinding; import dev.cel.testing.testdata.proto3.TestAllTypesProto.TestAllTypes; +import java.io.IOException; import java.util.Map; import java.util.Optional; import org.junit.Test; @@ -72,51 +73,22 @@ public void compileYamlPolicy_success(@TestParameter TestYamlPolicy yamlPolicy) } @Test - public void compileYamlPolicy_containsError_throws() throws Exception { + public void compileYamlPolicy_containsCompilationError_throws( + @TestParameter TestErrorYamlPolicy testCase) throws Exception { // Read config and produce an environment to compile policies - String configSource = readFromYaml("errors/config.yaml"); + String configSource = testCase.readConfigYamlContent(); CelPolicyConfig policyConfig = POLICY_CONFIG_PARSER.parse(configSource); Cel cel = policyConfig.extend(newCel(), CEL_OPTIONS); // Read the policy source - String policyFilePath = "errors/policy.yaml"; - String policySource = readFromYaml(policyFilePath); - CelPolicy policy = POLICY_PARSER.parse(policySource, policyFilePath); + String policySource = testCase.readPolicyYamlContent(); + CelPolicy policy = POLICY_PARSER.parse(policySource, testCase.getPolicyFilePath()); CelPolicyValidationException e = assertThrows( CelPolicyValidationException.class, () -> CelPolicyCompilerFactory.newPolicyCompiler(cel).build().compile(policy)); - assertThat(e) - .hasMessageThat() - .isEqualTo( - "ERROR: errors/policy.yaml:19:19: undeclared reference to 'spec' (in container '')\n" - + " | expression: spec.labels\n" - + " | ..................^\n" - + "ERROR: errors/policy.yaml:21:50: mismatched input 'resource' expecting {'=='," - + " '!=', 'in', '<', '<=', '>=', '>', '&&', '||', '[', '(', ')', '.', '-', '?'," - + " '+', '*', '/', '%%'}\n" - + " | expression: variables.want.filter(l, !(lin resource.labels))\n" - + " | .................................................^\n" - + "ERROR: errors/policy.yaml:21:66: extraneous input ')' expecting \n" - + " | expression: variables.want.filter(l, !(lin resource.labels))\n" - + " | .................................................................^\n" - + "ERROR: errors/policy.yaml:23:27: mismatched input '2' expecting {'}', ','}\n" - + " | expression: \"{1:305 2:569}\"\n" - + " | ..........................^\n" - + "ERROR: errors/policy.yaml:31:75: extraneous input ']' expecting ')'\n" - + " | \"missing one or more required labels:" - + " %s\".format(variables.missing])\n" - + " | ..........................................................................^\n" - + "ERROR: errors/policy.yaml:34:67: undeclared reference to 'format' (in container" - + " '')\n" - + " | \"invalid values provided on one or more labels:" - + " %s\".format([variables.invalid])\n" - + " | ..................................................................^\n" - + "ERROR: errors/policy.yaml:35:24: found no matching overload for '_==_' applied" - + " to '(bool, string)' (candidates: (%A0, %A0))\n" - + " | - condition: false == \"0\"\n" - + " | .......................^"); + assertThat(e).hasMessageThat().isEqualTo(testCase.readExpectedErrorsBaseline()); } @Test @@ -332,4 +304,34 @@ private enum MultilineErrorTest { this.expected = expected; } } + + private enum TestErrorYamlPolicy { + COMPILE_ERRORS("compile_errors"), + COMPOSE_ERRORS_CONFLICTING_OUTPUT("compose_errors_conflicting_output"), + COMPOSE_ERRORS_CONFLICTING_SUBRULE("compose_errors_conflicting_subrule"); + + private final String name; + private final String policyFilePath; + + private String getPolicyFilePath() { + return policyFilePath; + } + + private String readPolicyYamlContent() throws IOException { + return readFromYaml(String.format("%s/policy.yaml", name)); + } + + private String readConfigYamlContent() throws IOException { + return readFromYaml(String.format("%s/config.yaml", name)); + } + + private String readExpectedErrorsBaseline() throws IOException { + return readFromYaml(String.format("%s/expected_errors.baseline", name)); + } + + TestErrorYamlPolicy(String name) { + this.name = name; + this.policyFilePath = String.format("%s/policy.yaml", name); + } + } } diff --git a/policy/src/test/resources/BUILD.bazel b/policy/src/test/resources/BUILD.bazel index 71285b61a..4876f22fb 100644 --- a/policy/src/test/resources/BUILD.bazel +++ b/policy/src/test/resources/BUILD.bazel @@ -10,5 +10,5 @@ package( filegroup( name = "policy_yaml_files", - srcs = glob(["**/*.yaml"]), + srcs = glob(["**/*.yaml"]) + glob(["**/*.baseline"]), ) diff --git a/policy/src/test/resources/errors/config.yaml b/policy/src/test/resources/compile_errors/config.yaml similarity index 100% rename from policy/src/test/resources/errors/config.yaml rename to policy/src/test/resources/compile_errors/config.yaml diff --git a/policy/src/test/resources/compile_errors/expected_errors.baseline b/policy/src/test/resources/compile_errors/expected_errors.baseline new file mode 100644 index 000000000..a8c0ec047 --- /dev/null +++ b/policy/src/test/resources/compile_errors/expected_errors.baseline @@ -0,0 +1,24 @@ +ERROR: compile_errors/policy.yaml:19:19: undeclared reference to 'spec' (in container '') + | expression: spec.labels + | ..................^ +ERROR: compile_errors/policy.yaml:21:50: mismatched input 'resource' expecting {'==', '!=', 'in', '<', '<=', '>=', '>', '&&', '||', '[', '(', ')', '.', '-', '?', '+', '*', '/', '%%'} + | expression: variables.want.filter(l, !(lin resource.labels)) + | .................................................^ +ERROR: compile_errors/policy.yaml:21:66: extraneous input ')' expecting + | expression: variables.want.filter(l, !(lin resource.labels)) + | .................................................................^ +ERROR: compile_errors/policy.yaml:23:27: mismatched input '2' expecting {'}', ','} + | expression: "{1:305 2:569}" + | ..........................^ +ERROR: compile_errors/policy.yaml:31:75: extraneous input ']' expecting ')' + | "missing one or more required labels: %s".format(variables.missing]) + | ..........................................................................^ +ERROR: compile_errors/policy.yaml:34:67: undeclared reference to 'format' (in container '') + | "invalid values provided on one or more labels: %s".format([variables.invalid]) + | ..................................................................^ +ERROR: compile_errors/policy.yaml:35:19: condition must produce a boolean output. + | - condition: '1' + | ..................^ +ERROR: compile_errors/policy.yaml:38:24: found no matching overload for '_==_' applied to '(bool, string)' (candidates: (%A0, %A0)) + | - condition: false == "0" + | .......................^ \ No newline at end of file diff --git a/policy/src/test/resources/errors/policy.yaml b/policy/src/test/resources/compile_errors/policy.yaml similarity index 92% rename from policy/src/test/resources/errors/policy.yaml rename to policy/src/test/resources/compile_errors/policy.yaml index e322e8a83..c69bda507 100644 --- a/policy/src/test/resources/errors/policy.yaml +++ b/policy/src/test/resources/compile_errors/policy.yaml @@ -32,6 +32,9 @@ rule: - condition: variables.invalid.size() > 0 output: | "invalid values provided on one or more labels: %s".format([variables.invalid]) + - condition: '1' + output: | + "condition wrong type" - condition: false == "0" output: | - "wrong type" + "condition type-check failure" diff --git a/policy/src/test/resources/compose_errors_conflicting_output/config.yaml b/policy/src/test/resources/compose_errors_conflicting_output/config.yaml new file mode 100644 index 000000000..5d048a225 --- /dev/null +++ b/policy/src/test/resources/compose_errors_conflicting_output/config.yaml @@ -0,0 +1,22 @@ +# Copyright 2024 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. + +name: "labels" +variables: +- name: "resource" + type: + type_name: "map" + params: + - type_name: "string" + - type_name: "dyn" diff --git a/policy/src/test/resources/compose_errors_conflicting_output/expected_errors.baseline b/policy/src/test/resources/compose_errors_conflicting_output/expected_errors.baseline new file mode 100644 index 000000000..3e2624b64 --- /dev/null +++ b/policy/src/test/resources/compose_errors_conflicting_output/expected_errors.baseline @@ -0,0 +1,6 @@ +ERROR: compose_errors_conflicting_output/policy.yaml:22:14: conflicting output types found. + | output: "false" + | .............^ +ERROR: compose_errors_conflicting_output/policy.yaml:23:14: conflicting output types found. + | - output: "{'banned': true}" + | .............^ \ No newline at end of file diff --git a/policy/src/test/resources/compose_errors_conflicting_output/policy.yaml b/policy/src/test/resources/compose_errors_conflicting_output/policy.yaml new file mode 100644 index 000000000..a5ed5c09c --- /dev/null +++ b/policy/src/test/resources/compose_errors_conflicting_output/policy.yaml @@ -0,0 +1,23 @@ +# Copyright 2024 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. + +name: nested_rule +rule: + variables: + - name: "permitted_regions" + expression: "['us', 'uk', 'es']" + match: + - condition: resource.origin in variables.permitted_regions + output: "false" + - output: "{'banned': true}" diff --git a/policy/src/test/resources/compose_errors_conflicting_subrule/config.yaml b/policy/src/test/resources/compose_errors_conflicting_subrule/config.yaml new file mode 100644 index 000000000..5d048a225 --- /dev/null +++ b/policy/src/test/resources/compose_errors_conflicting_subrule/config.yaml @@ -0,0 +1,22 @@ +# Copyright 2024 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. + +name: "labels" +variables: +- name: "resource" + type: + type_name: "map" + params: + - type_name: "string" + - type_name: "dyn" diff --git a/policy/src/test/resources/compose_errors_conflicting_subrule/expected_errors.baseline b/policy/src/test/resources/compose_errors_conflicting_subrule/expected_errors.baseline new file mode 100644 index 000000000..559d62e1d --- /dev/null +++ b/policy/src/test/resources/compose_errors_conflicting_subrule/expected_errors.baseline @@ -0,0 +1,3 @@ +ERROR: compose_errors_conflicting_subrule/policy.yaml:36:14: failed composing the subrule 'banned regions' due to conflicting output types. + | output: "{'banned': false}" + | .............^ \ No newline at end of file diff --git a/policy/src/test/resources/compose_errors_conflicting_subrule/policy.yaml b/policy/src/test/resources/compose_errors_conflicting_subrule/policy.yaml new file mode 100644 index 000000000..9df1df8d0 --- /dev/null +++ b/policy/src/test/resources/compose_errors_conflicting_subrule/policy.yaml @@ -0,0 +1,37 @@ +# Copyright 2024 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. + +name: nested_rule +rule: + variables: + - name: "permitted_regions" + expression: "['us', 'uk', 'es']" + match: + - rule: + id: "banned regions" + description: > + determine whether the resource origin is in the banned + list. If the region is also in the permitted list, the + ban has no effect. + variables: + - name: "banned_regions" + expression: "{'us': false, 'ru': false, 'ir': false}" + match: + - condition: | + resource.origin in variables.banned_regions && + !(resource.origin in variables.permitted_regions) + output: "true" + - condition: resource.origin in variables.permitted_regions + output: "{'banned': false}" + - output: "{'banned': true}" From d82820cb03d6100b45828870e82b8d6a4eb9028d Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Mon, 15 Jul 2024 17:42:44 -0700 Subject: [PATCH 159/486] Release 0.6.0 PiperOrigin-RevId: 652649980 --- README.md | 4 ++-- publish/cel_version.bzl | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b9cc5f3a9..b61d940f9 100644 --- a/README.md +++ b/README.md @@ -55,14 +55,14 @@ CEL-Java is available in Maven Central Repository. [Download the JARs here][8] o dev.cel cel - 0.5.2 + 0.6.0 ``` **Gradle** ```gradle -implementation 'dev.cel:cel:0.5.2' +implementation 'dev.cel:cel:0.6.0' ``` Then run this example: diff --git a/publish/cel_version.bzl b/publish/cel_version.bzl index 866840e0c..96be40f81 100644 --- a/publish/cel_version.bzl +++ b/publish/cel_version.bzl @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. """Maven artifact version for CEL.""" -CEL_VERSION = "0.5.2" +CEL_VERSION = "0.6.0" From 995243c63d760ae6f82630a3d272a8e9801cacbf Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Wed, 17 Jul 2024 16:07:10 -0700 Subject: [PATCH 160/486] Do not override the container if it's missing from policy config PiperOrigin-RevId: 653392239 --- policy/src/main/java/dev/cel/policy/CelPolicyConfig.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/policy/src/main/java/dev/cel/policy/CelPolicyConfig.java b/policy/src/main/java/dev/cel/policy/CelPolicyConfig.java index c5acc43f5..d3786d512 100644 --- a/policy/src/main/java/dev/cel/policy/CelPolicyConfig.java +++ b/policy/src/main/java/dev/cel/policy/CelPolicyConfig.java @@ -127,6 +127,10 @@ public Cel extend(Cel cel, CelOptions celOptions) throws CelPolicyValidationExce .map(f -> f.toCelFunctionDecl(celTypeProvider)) .collect(toImmutableList())); + if (!container().isEmpty()) { + celBuilder.setContainer(container()); + } + addAllExtensions(celBuilder, celOptions); return celBuilder.build(); From 882f6318cac908e103ab4b3fdf17409c4b929f7e Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Thu, 18 Jul 2024 22:16:24 -0700 Subject: [PATCH 161/486] Add option to specify folding designated custom functions only PiperOrigin-RevId: 653874748 --- .../main/java/dev/cel/extensions/BUILD.bazel | 1 + .../cel/extensions/CelEncoderExtensions.java | 56 ++++++++++++++----- .../dev/cel/extensions/CelExtensions.java | 24 ++++++++ .../dev/cel/extensions/CelMathExtensions.java | 6 +- .../dev/cel/extensions/CelSetsExtensions.java | 4 ++ .../cel/extensions/CelStringExtensions.java | 4 ++ .../dev/cel/extensions/CelExtensionsTest.java | 24 +++++++- .../dev/cel/optimizer/optimizers/BUILD.bazel | 21 ++++++- .../optimizers/ConstantFoldingOptimizer.java | 54 +++++++++++++++++- .../optimizers/DefaultOptimizerConstants.java | 50 +++++++++++++++++ .../optimizers/SubexpressionOptimizer.java | 15 +---- .../ConstantFoldingOptimizerTest.java | 46 ++++++++++++++- 12 files changed, 269 insertions(+), 36 deletions(-) create mode 100644 optimizer/src/main/java/dev/cel/optimizer/optimizers/DefaultOptimizerConstants.java diff --git a/extensions/src/main/java/dev/cel/extensions/BUILD.bazel b/extensions/src/main/java/dev/cel/extensions/BUILD.bazel index da8aba9a0..9cf66cf1e 100644 --- a/extensions/src/main/java/dev/cel/extensions/BUILD.bazel +++ b/extensions/src/main/java/dev/cel/extensions/BUILD.bazel @@ -102,6 +102,7 @@ java_library( "//compiler:compiler_builder", "//runtime", "@maven//:com_google_errorprone_error_prone_annotations", + "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", ], ) diff --git a/extensions/src/main/java/dev/cel/extensions/CelEncoderExtensions.java b/extensions/src/main/java/dev/cel/extensions/CelEncoderExtensions.java index 46ad08262..bc882aa0e 100644 --- a/extensions/src/main/java/dev/cel/extensions/CelEncoderExtensions.java +++ b/extensions/src/main/java/dev/cel/extensions/CelEncoderExtensions.java @@ -14,6 +14,7 @@ package dev.cel.extensions; +import com.google.common.collect.ImmutableSet; import com.google.errorprone.annotations.Immutable; import com.google.protobuf.ByteString; import dev.cel.checker.CelCheckerBuilder; @@ -35,31 +36,58 @@ public class CelEncoderExtensions implements CelCompilerLibrary, CelRuntimeLibra private static final Decoder BASE64_DECODER = Base64.getDecoder(); - @Override - public void setCheckerOptions(CelCheckerBuilder checkerBuilder) { - checkerBuilder.addFunctionDeclarations( + private final ImmutableSet functions; + + enum Function { + DECODE( CelFunctionDecl.newFunctionDeclaration( "base64.decode", CelOverloadDecl.newGlobalOverload( "base64_decode_string", SimpleType.BYTES, SimpleType.STRING)), + ImmutableSet.of( + CelRuntime.CelFunctionBinding.from( + "base64_decode_string", + String.class, + str -> ByteString.copyFrom(BASE64_DECODER.decode(str))))), + ENCODE( CelFunctionDecl.newFunctionDeclaration( "base64.encode", CelOverloadDecl.newGlobalOverload( - "base64_encode_bytes", SimpleType.STRING, SimpleType.BYTES))); + "base64_encode_bytes", SimpleType.STRING, SimpleType.BYTES)), + ImmutableSet.of( + CelRuntime.CelFunctionBinding.from( + "base64_encode_bytes", + ByteString.class, + bytes -> BASE64_ENCODER.encodeToString(bytes.toByteArray())))), + ; + + private final CelFunctionDecl functionDecl; + private final ImmutableSet functionBindings; + + String getFunction() { + return functionDecl.name(); + } + + Function( + CelFunctionDecl functionDecl, + ImmutableSet functionBindings) { + this.functionDecl = functionDecl; + this.functionBindings = functionBindings; + } + } + + @Override + public void setCheckerOptions(CelCheckerBuilder checkerBuilder) { + functions.forEach(function -> checkerBuilder.addFunctionDeclarations(function.functionDecl)); } @SuppressWarnings("Immutable") // Instances of java.util.Base64 are immutable @Override public void setRuntimeOptions(CelRuntimeBuilder runtimeBuilder) { - runtimeBuilder.addFunctionBindings( - CelRuntime.CelFunctionBinding.from( - "base64_decode_string", - String.class, - str -> ByteString.copyFrom(BASE64_DECODER.decode(str))), - CelRuntime.CelFunctionBinding.from( - "base64_encode_bytes", - ByteString.class, - bytes -> BASE64_ENCODER.encodeToString(bytes.toByteArray()))); + functions.forEach(function -> runtimeBuilder.addFunctionBindings(function.functionBindings)); } -} + public CelEncoderExtensions() { + this.functions = ImmutableSet.copyOf(Function.values()); + } +} diff --git a/extensions/src/main/java/dev/cel/extensions/CelExtensions.java b/extensions/src/main/java/dev/cel/extensions/CelExtensions.java index 5515d6a89..662246283 100644 --- a/extensions/src/main/java/dev/cel/extensions/CelExtensions.java +++ b/extensions/src/main/java/dev/cel/extensions/CelExtensions.java @@ -14,7 +14,11 @@ package dev.cel.extensions; +import static com.google.common.collect.ImmutableSet.toImmutableSet; +import static java.util.Arrays.stream; + import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Streams; import dev.cel.common.CelOptions; import java.util.Set; @@ -206,5 +210,25 @@ public static CelSetsExtensions sets(Set functions) return new CelSetsExtensions(functions); } + /** + * Retrieves all function names used by every extension libraries. + * + *

Note: Certain extensions such as {@link CelProtoExtensions} and {@link + * CelBindingsExtensions} are implemented via macros, not functions, and those are not included + * here. + */ + public static ImmutableSet getAllFunctionNames() { + return Streams.concat( + stream(CelMathExtensions.Function.values()) + .map(CelMathExtensions.Function::getFunction), + stream(CelStringExtensions.Function.values()) + .map(CelStringExtensions.Function::getFunction), + stream(CelSetsExtensions.Function.values()) + .map(CelSetsExtensions.Function::getFunction), + stream(CelEncoderExtensions.Function.values()) + .map(CelEncoderExtensions.Function::getFunction)) + .collect(toImmutableSet()); + } + private CelExtensions() {} } diff --git a/extensions/src/main/java/dev/cel/extensions/CelMathExtensions.java b/extensions/src/main/java/dev/cel/extensions/CelMathExtensions.java index c6423a05a..ef1877b4c 100644 --- a/extensions/src/main/java/dev/cel/extensions/CelMathExtensions.java +++ b/extensions/src/main/java/dev/cel/extensions/CelMathExtensions.java @@ -104,7 +104,7 @@ final class CelMathExtensions implements CelCompilerLibrary, CelRuntimeLibrary { return builder.buildOrThrow(); } - public enum Function { + enum Function { MAX( CelFunctionDecl.newFunctionDeclaration( MATH_MAX_FUNCTION, @@ -341,6 +341,10 @@ public enum Function { private final ImmutableSet functionBindingsULongSigned; private final ImmutableSet functionBindingsULongUnsigned; + String getFunction() { + return functionDecl.name(); + } + Function( CelFunctionDecl functionDecl, ImmutableSet functionBindings, diff --git a/extensions/src/main/java/dev/cel/extensions/CelSetsExtensions.java b/extensions/src/main/java/dev/cel/extensions/CelSetsExtensions.java index 10fcbdd0c..e410edade 100644 --- a/extensions/src/main/java/dev/cel/extensions/CelSetsExtensions.java +++ b/extensions/src/main/java/dev/cel/extensions/CelSetsExtensions.java @@ -112,6 +112,10 @@ public enum Function { private final CelFunctionDecl functionDecl; private final ImmutableSet functionBindings; + String getFunction() { + return functionDecl.name(); + } + Function(CelFunctionDecl functionDecl, CelRuntime.CelFunctionBinding... functionBindings) { this.functionDecl = functionDecl; this.functionBindings = ImmutableSet.copyOf(functionBindings); diff --git a/extensions/src/main/java/dev/cel/extensions/CelStringExtensions.java b/extensions/src/main/java/dev/cel/extensions/CelStringExtensions.java index 69fbad8d1..473722b26 100644 --- a/extensions/src/main/java/dev/cel/extensions/CelStringExtensions.java +++ b/extensions/src/main/java/dev/cel/extensions/CelStringExtensions.java @@ -229,6 +229,10 @@ public enum Function { private final CelFunctionDecl functionDecl; private final ImmutableSet functionBindings; + String getFunction() { + return functionDecl.name(); + } + Function(CelFunctionDecl functionDecl, CelRuntime.CelFunctionBinding... functionBindings) { this.functionDecl = functionDecl; this.functionBindings = ImmutableSet.copyOf(functionBindings); diff --git a/extensions/src/test/java/dev/cel/extensions/CelExtensionsTest.java b/extensions/src/test/java/dev/cel/extensions/CelExtensionsTest.java index 0b2e7b2cd..d7b75f8dd 100644 --- a/extensions/src/test/java/dev/cel/extensions/CelExtensionsTest.java +++ b/extensions/src/test/java/dev/cel/extensions/CelExtensionsTest.java @@ -138,5 +138,27 @@ public void addEncoderExtension_success() throws Exception { assertThat(evaluatedResult).isTrue(); } -} + @Test + public void getAllFunctionNames() { + assertThat(CelExtensions.getAllFunctionNames()) + .containsExactly( + "math.@max", + "math.@min", + "charAt", + "indexOf", + "join", + "lastIndexOf", + "lowerAscii", + "replace", + "split", + "substring", + "trim", + "upperAscii", + "sets.contains", + "sets.equivalent", + "sets.intersects", + "base64.decode", + "base64.encode"); + } +} diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel b/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel index 2b0cc563b..9b679d9bd 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel @@ -14,6 +14,7 @@ java_library( tags = [ ], deps = [ + ":default_optimizer_constants", "//:auto_value", "//bundle:cel", "//common", @@ -29,6 +30,7 @@ java_library( "//optimizer:optimization_exception", "//parser:operator", "//runtime", + "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", ], ) @@ -41,9 +43,9 @@ java_library( tags = [ ], deps = [ + ":default_optimizer_constants", "//:auto_value", "//bundle:cel", - "//checker:checker_legacy_environment", "//common", "//common:compiler_common", "//common:mutable_ast", @@ -55,12 +57,25 @@ java_library( "//common/navigation:mutable_navigation", "//common/types", "//common/types:type_providers", - "//extensions:optional_library", "//optimizer:ast_optimizer", "//optimizer:mutable_ast", - "//parser:operator", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", "@maven//:org_jspecify_jspecify", ], ) + +java_library( + name = "default_optimizer_constants", + srcs = [ + "DefaultOptimizerConstants.java", + ], + visibility = ["//visibility:private"], + deps = [ + "//checker:checker_legacy_environment", + "//extensions", + "//extensions:optional_library", + "//parser:operator", + "@maven//:com_google_guava_guava", + ], +) diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java b/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java index 150f614df..7cf1ce1c3 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java @@ -13,11 +13,14 @@ // limitations under the License. package dev.cel.optimizer.optimizers; +import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.collect.ImmutableList.toImmutableList; import static com.google.common.collect.MoreCollectors.onlyElement; import com.google.auto.value.AutoValue; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import com.google.errorprone.annotations.CanIgnoreReturnValue; import dev.cel.bundle.Cel; import dev.cel.common.CelAbstractSyntaxTree; import dev.cel.common.CelMutableAst; @@ -40,6 +43,7 @@ import dev.cel.parser.Operator; import dev.cel.runtime.CelEvaluationException; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.List; @@ -71,6 +75,7 @@ public static ConstantFoldingOptimizer newInstance( private final ConstantFoldingOptions constantFoldingOptions; private final AstMutator astMutator; + private final ImmutableSet foldableFunctions; // Use optional.of and optional.none as sentinel function names for folding optional calls. // TODO: Leverage CelValue representation of Optionals instead when available. @@ -95,7 +100,7 @@ public OptimizationResult optimize(CelAbstractSyntaxTree ast, Cel cel) CelNavigableMutableAst.fromAst(mutableAst) .getRoot() .allNodes() - .filter(ConstantFoldingOptimizer::canFold) + .filter(this::canFold) .collect(toImmutableList()); for (CelNavigableMutableExpr foldableExpr : foldableExprs) { iterCount++; @@ -124,9 +129,13 @@ public OptimizationResult optimize(CelAbstractSyntaxTree ast, Cel cel) return OptimizationResult.create(astMutator.renumberIdsConsecutively(mutableAst).toParsedAst()); } - private static boolean canFold(CelNavigableMutableExpr navigableExpr) { + private boolean canFold(CelNavigableMutableExpr navigableExpr) { switch (navigableExpr.getKind()) { case CALL: + if (!containsFoldableFunctionOnly(navigableExpr)) { + return false; + } + CelMutableCall mutableCall = navigableExpr.expr().call(); String functionName = mutableCall.function(); @@ -169,6 +178,19 @@ private static boolean canFold(CelNavigableMutableExpr navigableExpr) { } } + private boolean containsFoldableFunctionOnly(CelNavigableMutableExpr navigableExpr) { + return navigableExpr + .allNodes() + .allMatch( + node -> { + if (node.getKind().equals(Kind.CALL)) { + return foldableFunctions.contains(node.expr().call().function()); + } + + return true; + }); + } + private static boolean canFoldInOperator(CelNavigableMutableExpr navigableExpr) { ImmutableList allIdents = navigableExpr @@ -574,16 +596,39 @@ private CelMutableAst pruneOptionalStructElements(CelMutableAst ast, CelMutableE public abstract static class ConstantFoldingOptions { public abstract int maxIterationLimit(); + public abstract ImmutableSet foldableFunctions(); + /** Builder for configuring the {@link ConstantFoldingOptions}. */ @AutoValue.Builder public abstract static class Builder { + abstract ImmutableSet.Builder foldableFunctionsBuilder(); + /** * Limit the number of iteration while performing constant folding. An exception is thrown if * the iteration count exceeds the set value. */ public abstract Builder maxIterationLimit(int value); + /** + * Adds a collection of custom functions that will be a candidate for constant folding. By + * default, standard functions are foldable. + * + *

Note that the implementation of custom functions must be free of side effects. + */ + @CanIgnoreReturnValue + public Builder addFoldableFunctions(Iterable functions) { + checkNotNull(functions); + this.foldableFunctionsBuilder().addAll(functions); + return this; + } + + /** See {@link #addFoldableFunctions(Iterable)}. */ + @CanIgnoreReturnValue + public Builder addFoldableFunctions(String... functions) { + return addFoldableFunctions(Arrays.asList(functions)); + } + public abstract ConstantFoldingOptions build(); Builder() {} @@ -601,5 +646,10 @@ public static Builder newBuilder() { private ConstantFoldingOptimizer(ConstantFoldingOptions constantFoldingOptions) { this.constantFoldingOptions = constantFoldingOptions; this.astMutator = AstMutator.newInstance(constantFoldingOptions.maxIterationLimit()); + this.foldableFunctions = + ImmutableSet.builder() + .addAll(DefaultOptimizerConstants.CEL_CANONICAL_FUNCTIONS) + .addAll(constantFoldingOptions.foldableFunctions()) + .build(); } } diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/DefaultOptimizerConstants.java b/optimizer/src/main/java/dev/cel/optimizer/optimizers/DefaultOptimizerConstants.java new file mode 100644 index 000000000..07a3f062b --- /dev/null +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/DefaultOptimizerConstants.java @@ -0,0 +1,50 @@ +// Copyright 2024 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.optimizers; + +import static com.google.common.collect.ImmutableSet.toImmutableSet; +import static java.util.Arrays.stream; + +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Streams; +import dev.cel.checker.Standard; +import dev.cel.extensions.CelExtensions; +import dev.cel.extensions.CelOptionalLibrary; +import dev.cel.extensions.CelOptionalLibrary.Function; +import dev.cel.parser.Operator; + +/** + * Package-private class that holds constants that's generally applicable across canonical + * optimizers provided from CEL. + */ +final class DefaultOptimizerConstants { + + /** + * List of function names from standard functions and extension libraries. These are free of side + * effects, thus amenable for optimization. + */ + static final ImmutableSet CEL_CANONICAL_FUNCTIONS = + ImmutableSet.builder() + .addAll( + Streams.concat( + stream(Operator.values()).map(Operator::getFunction), + stream(Standard.Function.values()).map(Standard.Function::getFunction), + stream(CelOptionalLibrary.Function.values()).map(Function::getFunction)) + .collect(toImmutableSet())) + .addAll(CelExtensions.getAllFunctionNames()) + .build(); + + private DefaultOptimizerConstants() {} +} diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java index 967c68d3c..ecb5b22e4 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java @@ -16,8 +16,6 @@ import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.collect.ImmutableList.toImmutableList; -import static com.google.common.collect.ImmutableSet.toImmutableSet; -import static java.util.Arrays.stream; import static java.util.stream.Collectors.toCollection; import com.google.auto.value.AutoValue; @@ -30,7 +28,6 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue; import dev.cel.bundle.Cel; import dev.cel.bundle.CelBuilder; -import dev.cel.checker.Standard; import dev.cel.common.CelAbstractSyntaxTree; import dev.cel.common.CelFunctionDecl; import dev.cel.common.CelMutableAst; @@ -54,12 +51,9 @@ import dev.cel.common.types.CelType; import dev.cel.common.types.ListType; import dev.cel.common.types.SimpleType; -import dev.cel.extensions.CelOptionalLibrary; -import dev.cel.extensions.CelOptionalLibrary.Function; import dev.cel.optimizer.AstMutator; import dev.cel.optimizer.AstMutator.MangledComprehensionAst; import dev.cel.optimizer.CelAstOptimizer; -import dev.cel.parser.Operator; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; @@ -94,12 +88,7 @@ * */ public class SubexpressionOptimizer implements CelAstOptimizer { - private static final ImmutableSet CSE_DEFAULT_ELIMINABLE_FUNCTIONS = - Streams.concat( - stream(Operator.values()).map(Operator::getFunction), - stream(Standard.Function.values()).map(Standard.Function::getFunction), - stream(CelOptionalLibrary.Function.values()).map(Function::getFunction)) - .collect(toImmutableSet()); + private static final SubexpressionOptimizer INSTANCE = new SubexpressionOptimizer(SubexpressionOptimizerOptions.newBuilder().build()); private static final String BIND_IDENTIFIER_PREFIX = "@r"; @@ -738,7 +727,7 @@ private SubexpressionOptimizer(SubexpressionOptimizerOptions cseOptions) { this.astMutator = AstMutator.newInstance(cseOptions.iterationLimit()); this.cseEliminableFunctions = ImmutableSet.builder() - .addAll(CSE_DEFAULT_ELIMINABLE_FUNCTIONS) + .addAll(DefaultOptimizerConstants.CEL_CANONICAL_FUNCTIONS) .addAll(cseOptions.eliminableFunctions()) .build(); } diff --git a/optimizer/src/test/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizerTest.java b/optimizer/src/test/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizerTest.java index 9813ee266..96040b508 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizerTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizerTest.java @@ -17,12 +17,15 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertThrows; +import com.google.common.collect.ImmutableList; import com.google.testing.junit.testparameterinjector.TestParameterInjector; import com.google.testing.junit.testparameterinjector.TestParameters; import dev.cel.bundle.Cel; import dev.cel.bundle.CelFactory; import dev.cel.common.CelAbstractSyntaxTree; +import dev.cel.common.CelFunctionDecl; import dev.cel.common.CelOptions; +import dev.cel.common.CelOverloadDecl; import dev.cel.common.types.ListType; import dev.cel.common.types.MapType; import dev.cel.common.types.SimpleType; @@ -35,6 +38,7 @@ import dev.cel.parser.CelStandardMacro; import dev.cel.parser.CelUnparser; import dev.cel.parser.CelUnparserFactory; +import dev.cel.runtime.CelRuntime.CelFunctionBinding; import dev.cel.testing.testdata.proto3.TestAllTypesProto.TestAllTypes; import org.junit.Test; import org.junit.runner.RunWith; @@ -47,10 +51,27 @@ public class ConstantFoldingOptimizerTest { .addVar("y", SimpleType.DYN) .addVar("list_var", ListType.create(SimpleType.STRING)) .addVar("map_var", MapType.create(SimpleType.STRING, SimpleType.STRING)) + .addFunctionDeclarations( + CelFunctionDecl.newFunctionDeclaration( + "get_true", + CelOverloadDecl.newGlobalOverload("get_true_overload", SimpleType.BOOL))) + .addFunctionBindings( + CelFunctionBinding.from("get_true_overload", ImmutableList.of(), unused -> true)) .addMessageTypes(TestAllTypes.getDescriptor()) .setContainer("dev.cel.testing.testdata.proto3") - .addCompilerLibraries(CelExtensions.bindings(), CelOptionalLibrary.INSTANCE) - .addRuntimeLibraries(CelOptionalLibrary.INSTANCE) + .addCompilerLibraries( + CelExtensions.bindings(), + CelOptionalLibrary.INSTANCE, + CelExtensions.math(CelOptions.DEFAULT), + CelExtensions.strings(), + CelExtensions.sets(), + CelExtensions.encoders()) + .addRuntimeLibraries( + CelOptionalLibrary.INSTANCE, + CelExtensions.math(CelOptions.DEFAULT), + CelExtensions.strings(), + CelExtensions.sets(), + CelExtensions.encoders()) .build(); private static final CelOptimizer CEL_OPTIMIZER = @@ -161,6 +182,10 @@ public class ConstantFoldingOptimizerTest { @TestParameters("{source: 'map_var[?\"key\"]', expected: 'map_var[?\"key\"]'}") @TestParameters("{source: '\"abc\" in list_var', expected: '\"abc\" in list_var'}") @TestParameters("{source: '[?optional.none(), [?optional.none()]]', expected: '[[]]'}") + @TestParameters("{source: 'math.greatest(1.0, 2, 3.0)', expected: '3.0'}") + @TestParameters("{source: '\"world\".charAt(1)', expected: '\"o\"'}") + @TestParameters("{source: 'base64.encode(b\"hello\")', expected: '\"aGVsbG8=\"'}") + @TestParameters("{source: 'sets.contains([1], [1])', expected: 'true'}") @TestParameters( "{source: 'cel.bind(r0, [1, 2, 3], cel.bind(r1, 1 in r0, r1))', expected: 'true'}") // TODO: Support folding lists with mixed types. This requires mutable lists. @@ -291,6 +316,8 @@ public void constantFold_macros_withoutMacroCallMetadata(String source) throws E @TestParameters("{source: '[optional.none()]'}") @TestParameters("{source: '[?x.?y]'}") @TestParameters("{source: 'TestAllTypes{single_int32: x, repeated_int32: [1, 2, 3]}'}") + @TestParameters("{source: 'get_true() == get_true()'}") + @TestParameters("{source: 'get_true() == true'}") public void constantFold_noOp(String source) throws Exception { CelAbstractSyntaxTree ast = CEL.compile(source).getAst(); @@ -299,6 +326,21 @@ public void constantFold_noOp(String source) throws Exception { assertThat(CEL_UNPARSER.unparse(optimizedAst)).isEqualTo(source); } + @Test + public void constantFold_addFoldableFunction_success() throws Exception { + CelAbstractSyntaxTree ast = CEL.compile("get_true() == get_true()").getAst(); + ConstantFoldingOptions options = + ConstantFoldingOptions.newBuilder().addFoldableFunctions("get_true").build(); + CelOptimizer optimizer = + CelOptimizerFactory.standardCelOptimizerBuilder(CEL) + .addAstOptimizers(ConstantFoldingOptimizer.newInstance(options)) + .build(); + + CelAbstractSyntaxTree optimizedAst = optimizer.optimize(ast); + + assertThat(CEL_UNPARSER.unparse(optimizedAst)).isEqualTo("true"); + } + @Test public void constantFold_withMacroCallPopulated_comprehensionsAreReplacedWithNotSet() throws Exception { From 77d78530081736db644422aa4e7693c61e1346cb Mon Sep 17 00:00:00 2001 From: Tristan Swadell Date: Wed, 24 Jul 2024 15:03:19 -0700 Subject: [PATCH 162/486] Introduce ProtoUnsetFieldOptions to support unset handling like C++ PiperOrigin-RevId: 655712342 --- .../main/java/dev/cel/common/CelOptions.java | 26 ++++++++++++++- .../main/java/dev/cel/runtime/Activation.java | 8 +++++ .../java/dev/cel/runtime/ActivationTest.java | 33 +++++++++++++++++++ 3 files changed, 66 insertions(+), 1 deletion(-) diff --git a/common/src/main/java/dev/cel/common/CelOptions.java b/common/src/main/java/dev/cel/common/CelOptions.java index fb5ec6ad7..c5288aa2f 100644 --- a/common/src/main/java/dev/cel/common/CelOptions.java +++ b/common/src/main/java/dev/cel/common/CelOptions.java @@ -30,6 +30,18 @@ @Immutable public abstract class CelOptions { + /** + * ProtoUnsetFieldOptions describes how to handle Activation.fromProto() calls where proto message + * fields may be unset and should either be handled perhaps as absent or as the default proto + * value. + */ + public enum ProtoUnsetFieldOptions { + // Do not bind a field if it is unset. Repeated fields are bound as empty list. + SKIP, + // Bind the (proto api) default value for a field. + BIND_DEFAULT; + } + public static final CelOptions DEFAULT = current().build(); public static final CelOptions LEGACY = newBuilder().disableCelStandardEquality(true).build(); @@ -95,6 +107,8 @@ public abstract class CelOptions { public abstract boolean unwrapWellKnownTypesOnFunctionDispatch(); + public abstract ProtoUnsetFieldOptions fromProtoUnsetFieldOption(); + public abstract Builder toBuilder(); public ImmutableSet toExprFeatures() { @@ -185,7 +199,8 @@ public static Builder newBuilder() { .enableUnknownTracking(false) .enableCelValue(false) .comprehensionMaxIterations(-1) - .unwrapWellKnownTypesOnFunctionDispatch(true); + .unwrapWellKnownTypesOnFunctionDispatch(true) + .fromProtoUnsetFieldOption(ProtoUnsetFieldOptions.BIND_DEFAULT); } /** @@ -479,6 +494,15 @@ public abstract static class Builder { @Deprecated public abstract Builder unwrapWellKnownTypesOnFunctionDispatch(boolean value); + /** + * Configure how unset proto fields are handled when evaluating over a protobuf message where + * fields are intended to be treated as top-level variables. Defaults to binding all fields to + * their default value if unset. + * + * @see ProtoUnsetFieldOptions + */ + public abstract Builder fromProtoUnsetFieldOption(ProtoUnsetFieldOptions value); + public abstract CelOptions build(); } } diff --git a/runtime/src/main/java/dev/cel/runtime/Activation.java b/runtime/src/main/java/dev/cel/runtime/Activation.java index 1894c16ca..0ea70662e 100644 --- a/runtime/src/main/java/dev/cel/runtime/Activation.java +++ b/runtime/src/main/java/dev/cel/runtime/Activation.java @@ -172,7 +172,15 @@ public static Activation fromProto(Message message, CelOptions celOptions) { new ProtoAdapter( DynamicProto.create(DefaultMessageFactory.INSTANCE), celOptions.enableUnsignedLongs()); + boolean skipUnsetFields = + celOptions.fromProtoUnsetFieldOption().equals(CelOptions.ProtoUnsetFieldOptions.SKIP); + for (FieldDescriptor field : message.getDescriptorForType().getFields()) { + // If skipping unset fields and the field is not repeated, then continue. + if (skipUnsetFields && !field.isRepeated() && !msgFieldValues.containsKey(field)) { + continue; + } + // Get the value of the field set on the message, if present, otherwise use reflection to // get the default value for the field using the FieldDescriptor. Object fieldValue = msgFieldValues.getOrDefault(field, message.getField(field)); diff --git a/runtime/src/test/java/dev/cel/runtime/ActivationTest.java b/runtime/src/test/java/dev/cel/runtime/ActivationTest.java index 5eb10737c..04bc1cfb2 100644 --- a/runtime/src/test/java/dev/cel/runtime/ActivationTest.java +++ b/runtime/src/test/java/dev/cel/runtime/ActivationTest.java @@ -35,6 +35,13 @@ public final class ActivationTest { private static final CelOptions TEST_OPTIONS = CelOptions.current().enableTimestampEpoch(true).enableUnsignedLongs(true).build(); + private static final CelOptions TEST_OPTIONS_SKIP_UNSET_FIELDS = + CelOptions.current() + .enableTimestampEpoch(true) + .enableUnsignedLongs(true) + .fromProtoUnsetFieldOption(CelOptions.ProtoUnsetFieldOptions.SKIP) + .build(); + @Test public void copyOf_success_withNullEntries() { Map map = new HashMap<>(); @@ -64,6 +71,13 @@ public void fromProto_unsetScalarField() { assertThat(activation.resolve("bb")).isEqualTo(0); } + @Test + public void fromProto_unsetScalarField_skipUnsetFields() { + Activation activation = + Activation.fromProto(NestedMessage.getDefaultInstance(), TEST_OPTIONS_SKIP_UNSET_FIELDS); + assertThat(activation.resolve("bb")).isNull(); + } + @Test public void fromProto_unsetAnyField() { // An unset Any field is the only field which cannot be accurately published into an Activation, @@ -102,6 +116,17 @@ public void fromProto_unsetRepeatedField() { assertThat((List) activation.resolve("repeated_nested_message")).isEmpty(); } + @Test + public void fromProto_unsetRepeatedField_skipUnsetFields() { + Activation activation = + Activation.fromProto(TestAllTypes.getDefaultInstance(), TEST_OPTIONS_SKIP_UNSET_FIELDS); + assertThat(activation.resolve("repeated_int64")).isInstanceOf(List.class); + assertThat((List) activation.resolve("repeated_int64")).isEmpty(); + + assertThat(activation.resolve("repeated_nested_message")).isInstanceOf(List.class); + assertThat((List) activation.resolve("repeated_nested_message")).isEmpty(); + } + @Test public void fromProto_unsetMapField() { Activation activation = Activation.fromProto(TestAllTypes.getDefaultInstance(), TEST_OPTIONS); @@ -109,6 +134,14 @@ public void fromProto_unsetMapField() { assertThat((Map) activation.resolve("map_int32_int64")).isEmpty(); } + @Test + public void fromProto_unsetMapField_skipUnsetFields() { + Activation activation = + Activation.fromProto(TestAllTypes.getDefaultInstance(), TEST_OPTIONS_SKIP_UNSET_FIELDS); + assertThat(activation.resolve("map_int32_int64")).isInstanceOf(Map.class); + assertThat((Map) activation.resolve("map_int32_int64")).isEmpty(); + } + @Test public void fromProto_unsignedLongField_unsignedResult() { Activation activation = From f78c6c4944f545e6984d2c0a20c272a41f1494e1 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Tue, 30 Jul 2024 13:39:04 -0700 Subject: [PATCH 163/486] Fix conditionally nested rules to include its condition PiperOrigin-RevId: 657714654 --- .../java/dev/cel/policy/CelCompiledRule.java | 4 +- .../cel/policy/CelPolicyYamlConfigParser.java | 14 +++++- .../java/dev/cel/policy/RuleComposer.java | 21 ++++++-- .../main/java/dev/cel/policy/YamlHelper.java | 13 ++++- .../policy/CelPolicyYamlConfigParserTest.java | 36 +++++++++++++ .../java/dev/cel/policy/PolicyTestHelper.java | 13 ++++- policy/src/test/resources/limits/config.yaml | 22 ++++++++ policy/src/test/resources/limits/policy.yaml | 50 +++++++++++++++++++ policy/src/test/resources/limits/tests.yaml | 38 ++++++++++++++ 9 files changed, 202 insertions(+), 9 deletions(-) create mode 100644 policy/src/test/resources/limits/config.yaml create mode 100644 policy/src/test/resources/limits/policy.yaml create mode 100644 policy/src/test/resources/limits/tests.yaml diff --git a/policy/src/main/java/dev/cel/policy/CelCompiledRule.java b/policy/src/main/java/dev/cel/policy/CelCompiledRule.java index 4c39fee94..3c5893dfb 100644 --- a/policy/src/main/java/dev/cel/policy/CelCompiledRule.java +++ b/policy/src/main/java/dev/cel/policy/CelCompiledRule.java @@ -94,7 +94,9 @@ public enum Kind { */ @AutoValue public abstract static class OutputValue { - public abstract long id(); + + /** Source metadata identifier associated with the output. */ + public abstract long sourceId(); public abstract CelAbstractSyntaxTree ast(); diff --git a/policy/src/main/java/dev/cel/policy/CelPolicyYamlConfigParser.java b/policy/src/main/java/dev/cel/policy/CelPolicyYamlConfigParser.java index f0525f7ef..6d84c8fcb 100644 --- a/policy/src/main/java/dev/cel/policy/CelPolicyYamlConfigParser.java +++ b/policy/src/main/java/dev/cel/policy/CelPolicyYamlConfigParser.java @@ -21,6 +21,7 @@ import static dev.cel.policy.YamlHelper.newInteger; import static dev.cel.policy.YamlHelper.newString; import static dev.cel.policy.YamlHelper.parseYamlSource; +import static dev.cel.policy.YamlHelper.validateYamlType; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; @@ -258,7 +259,18 @@ private static ExtensionConfig parseExtension(ParserContext ctx, Node node builder.setName(newString(ctx, valueNode)); break; case "version": - builder.setVersion(newInteger(ctx, valueNode)); + if (validateYamlType(valueNode, YamlNodeType.INTEGER)) { + builder.setVersion(newInteger(ctx, valueNode)); + break; + } else if (validateYamlType(valueNode, YamlNodeType.STRING, YamlNodeType.TEXT)) { + String versionStr = newString(ctx, valueNode); + if (versionStr.equals("latest")) { + builder.setVersion(Integer.MAX_VALUE); + break; + } + // Fall-through + } + ctx.reportError(keyId, String.format("Unsupported version tag: %s", keyName)); break; default: ctx.reportError(keyId, String.format("Unsupported extension tag: %s", keyName)); diff --git a/policy/src/main/java/dev/cel/policy/RuleComposer.java b/policy/src/main/java/dev/cel/policy/RuleComposer.java index 732b60394..c3b888887 100644 --- a/policy/src/main/java/dev/cel/policy/RuleComposer.java +++ b/policy/src/main/java/dev/cel/policy/RuleComposer.java @@ -85,7 +85,7 @@ private RuleOptimizationResult optimizeRule(Cel cel, CelCompiledRule compiledRul if (isTriviallyTrue) { matchAst = outAst; isOptionalResult = false; - lastOutputId = matchOutput.id(); + lastOutputId = matchOutput.sourceId(); continue; } if (isOptionalResult) { @@ -99,8 +99,12 @@ private RuleOptimizationResult optimizeRule(Cel cel, CelCompiledRule compiledRul outAst, matchAst); assertComposedAstIsValid( - cel, matchAst, "conflicting output types found.", matchOutput.id(), lastOutputId); - lastOutputId = matchOutput.id(); + cel, + matchAst, + "conflicting output types found.", + matchOutput.sourceId(), + lastOutputId); + lastOutputId = matchOutput.sourceId(); continue; case RULE: CelCompiledRule matchNestedRule = match.result().rule(); @@ -117,7 +121,16 @@ private RuleOptimizationResult optimizeRule(Cel cel, CelCompiledRule compiledRul if (!isOptionalResult && !nestedRule.isOptionalResult()) { throw new IllegalArgumentException("Subrule early terminates policy"); } - matchAst = astMutator.newMemberCall(nestedRuleAst, Function.OR.getFunction(), matchAst); + if (isTriviallyTrue) { + matchAst = astMutator.newMemberCall(nestedRuleAst, Function.OR.getFunction(), matchAst); + } else { + matchAst = + astMutator.newGlobalCall( + Operator.CONDITIONAL.getFunction(), + CelMutableAst.fromCelAst(conditionAst), + nestedRuleAst, + matchAst); + } assertComposedAstIsValid( cel, matchAst, diff --git a/policy/src/main/java/dev/cel/policy/YamlHelper.java b/policy/src/main/java/dev/cel/policy/YamlHelper.java index d340ce329..276c09be4 100644 --- a/policy/src/main/java/dev/cel/policy/YamlHelper.java +++ b/policy/src/main/java/dev/cel/policy/YamlHelper.java @@ -69,14 +69,23 @@ static boolean assertRequiredFields( return false; } - static boolean assertYamlType( - ParserContext ctx, long id, Node node, YamlNodeType... expectedNodeTypes) { + static boolean validateYamlType(Node node, YamlNodeType... expectedNodeTypes) { String nodeTag = node.getTag().getValue(); for (YamlNodeType expectedNodeType : expectedNodeTypes) { if (expectedNodeType.tag().equals(nodeTag)) { return true; } } + return false; + } + + static boolean assertYamlType( + ParserContext ctx, long id, Node node, YamlNodeType... expectedNodeTypes) { + if (validateYamlType(node, expectedNodeTypes)) { + return true; + } + String nodeTag = node.getTag().getValue(); + ctx.reportError( id, String.format( diff --git a/policy/src/test/java/dev/cel/policy/CelPolicyYamlConfigParserTest.java b/policy/src/test/java/dev/cel/policy/CelPolicyYamlConfigParserTest.java index 6da658729..630bfc76e 100644 --- a/policy/src/test/java/dev/cel/policy/CelPolicyYamlConfigParserTest.java +++ b/policy/src/test/java/dev/cel/policy/CelPolicyYamlConfigParserTest.java @@ -91,6 +91,42 @@ public void config_setExtensions() throws Exception { assertThat(policyConfig.extend(CEL_WITH_MESSAGE_TYPES, CelOptions.DEFAULT)).isNotNull(); } + @Test + public void config_setExtensionVersionToLatest() throws Exception { + String yamlConfig = + "extensions:\n" // + + " - name: 'bindings'\n" // + + " version: latest"; + + CelPolicyConfig policyConfig = POLICY_CONFIG_PARSER.parse(yamlConfig); + + assertThat(policyConfig) + .isEqualTo( + CelPolicyConfig.newBuilder() + .setConfigSource(policyConfig.configSource()) + .setExtensions(ImmutableSet.of(ExtensionConfig.of("bindings", Integer.MAX_VALUE))) + .build()); + assertThat(policyConfig.extend(CEL_WITH_MESSAGE_TYPES, CelOptions.DEFAULT)).isNotNull(); + } + + @Test + public void config_setExtensionVersionToInvalidValue() throws Exception { + String yamlConfig = + "extensions:\n" // + + " - name: 'bindings'\n" // + + " version: invalid"; + + CelPolicyValidationException e = + assertThrows( + CelPolicyValidationException.class, () -> POLICY_CONFIG_PARSER.parse(yamlConfig)); + assertThat(e) + .hasMessageThat() + .contains( + "ERROR: :3:5: Unsupported version tag: version\n" + + " | version: invalid\n" + + " | ....^"); + } + @Test public void config_setFunctions() throws Exception { String yamlConfig = diff --git a/policy/src/test/java/dev/cel/policy/PolicyTestHelper.java b/policy/src/test/java/dev/cel/policy/PolicyTestHelper.java index f323e5ca5..a41f398d1 100644 --- a/policy/src/test/java/dev/cel/policy/PolicyTestHelper.java +++ b/policy/src/test/java/dev/cel/policy/PolicyTestHelper.java @@ -87,7 +87,18 @@ enum TestYamlPolicy { "pb", true, "(spec.single_int32 > 10) ? optional.of(\"invalid spec, got single_int32=\" +" - + " string(spec.single_int32) + \", wanted <= 10\") : optional.none()"); + + " string(spec.single_int32) + \", wanted <= 10\") : optional.none()"), + LIMITS( + "limits", + true, + "cel.bind(variables.greeting, \"hello\", cel.bind(variables.farewell, \"goodbye\"," + + " cel.bind(variables.person, \"me\", cel.bind(variables.message_fmt, \"%s, %s\"," + + " (now.getHours() >= 20) ? cel.bind(variables.message, variables.farewell + \", \" +" + + " variables.person, (now.getHours() < 21) ? optional.of(variables.message + \"!\") :" + + " ((now.getHours() < 22) ? optional.of(variables.message + \"!!\") : ((now.getHours()" + + " < 24) ? optional.of(variables.message + \"!!!\") : optional.none()))) :" + + " optional.of(variables.greeting + \", \" + variables.person)))))"); + private final String name; private final boolean producesOptionalResult; private final String unparsed; diff --git a/policy/src/test/resources/limits/config.yaml b/policy/src/test/resources/limits/config.yaml new file mode 100644 index 000000000..fa6fc737c --- /dev/null +++ b/policy/src/test/resources/limits/config.yaml @@ -0,0 +1,22 @@ +# Copyright 2024 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. + +name: "limits" +extensions: +- name: "strings" + version: latest +variables: +- name: "now" + type: + type_name: "google.protobuf.Timestamp" \ No newline at end of file diff --git a/policy/src/test/resources/limits/policy.yaml b/policy/src/test/resources/limits/policy.yaml new file mode 100644 index 000000000..13c47c39b --- /dev/null +++ b/policy/src/test/resources/limits/policy.yaml @@ -0,0 +1,50 @@ +# Copyright 2024 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. + +name: "limits" +rule: + variables: + - name: "greeting" + expression: "'hello'" + - name: "farewell" + expression: "'goodbye'" + - name: "person" + expression: "'me'" + - name: "message_fmt" + expression: "'%s, %s'" + match: + - condition: | + now.getHours() >= 20 + rule: + id: "farewells" + variables: + - name: "message" + expression: > + variables.farewell + ', ' + variables.person +# TODO: replace when string.format is available +# variables.message_fmt.format([variables.farewell, +# variables.person]) + match: + - condition: > + now.getHours() < 21 + output: variables.message + "!" + - condition: > + now.getHours() < 22 + output: variables.message + "!!" + - condition: > + now.getHours() < 24 + output: variables.message + "!!!" + - output: > + variables.greeting + ', ' + variables.person +# variables.message_fmt.format([variables.greeting, variables.person]) TODO: replace when string.format is available \ No newline at end of file diff --git a/policy/src/test/resources/limits/tests.yaml b/policy/src/test/resources/limits/tests.yaml new file mode 100644 index 000000000..fe6daa61d --- /dev/null +++ b/policy/src/test/resources/limits/tests.yaml @@ -0,0 +1,38 @@ +# Copyright 2024 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. + +description: Limits related tests +section: +- name: "now_after_hours" + tests: + - name: "7pm" + input: + now: + expr: "timestamp('2024-07-30T00:30:00Z')" + output: "'hello, me'" + - name: "8pm" + input: + now: + expr: "timestamp('2024-07-30T20:30:00Z')" + output: "'goodbye, me!'" + - name: "9pm" + input: + now: + expr: "timestamp('2024-07-30T21:30:00Z')" + output: "'goodbye, me!!'" + - name: "11pm" + input: + now: + expr: "timestamp('2024-07-30T23:30:00Z')" + output: "'goodbye, me!!!'" \ No newline at end of file From 5b85b76c12e5a400ace4a772a667dc8c6a8fde60 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Thu, 1 Aug 2024 13:02:46 -0700 Subject: [PATCH 164/486] Remove unused list/map conversion functions from standard definitions PiperOrigin-RevId: 658509637 --- .../main/java/dev/cel/checker/Standard.java | 19 ------------------- .../test/resources/standardEnvDump.baseline | 2 -- 2 files changed, 21 deletions(-) diff --git a/checker/src/main/java/dev/cel/checker/Standard.java b/checker/src/main/java/dev/cel/checker/Standard.java index f595dde9a..1781fe559 100644 --- a/checker/src/main/java/dev/cel/checker/Standard.java +++ b/checker/src/main/java/dev/cel/checker/Standard.java @@ -419,25 +419,6 @@ private static ImmutableList coreFunctionDeclarations() { CelOverloadDecl.newGlobalOverload( "duration_to_string", "type_conversion", SimpleType.STRING, SimpleType.DURATION))); - // Conversions to list - celFunctionDeclBuilder.add( - CelFunctionDecl.newFunctionDeclaration( - Function.LIST.getFunction(), - CelOverloadDecl.newGlobalOverload( - "to_list", "type conversion", listOfA, TypeType.create(typeParamA), listOfA))); - - // Conversions to map - celFunctionDeclBuilder.add( - CelFunctionDecl.newFunctionDeclaration( - Function.MAP.getFunction(), - CelOverloadDecl.newGlobalOverload( - "to_map", - "type conversion", - mapOfAb, - TypeType.create(typeParamA), - TypeType.create(typeParamB), - mapOfAb))); - // Conversions to bytes celFunctionDeclBuilder.add( CelFunctionDecl.newFunctionDeclaration( diff --git a/checker/src/test/resources/standardEnvDump.baseline b/checker/src/test/resources/standardEnvDump.baseline index 4ef2fa9cf..a49852d84 100644 --- a/checker/src/test/resources/standardEnvDump.baseline +++ b/checker/src/test/resources/standardEnvDump.baseline @@ -220,11 +220,9 @@ declare int { } declare list { value type(list(dyn)) - function to_list (type(A), list(A)) -> list(A) } declare map { value type(map(dyn, dyn)) - function to_map (type(A), type(B), map(A, B)) -> map(A, B) } declare matches { function matches (string, string) -> bool From ea16dc41c5c4e851abc7bf3cef10d14466c5f98b Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Thu, 1 Aug 2024 14:57:15 -0700 Subject: [PATCH 165/486] Include identity functions in the standard definitions PiperOrigin-RevId: 658548681 --- .../src/main/java/dev/cel/checker/Env.java | 4 ++ .../main/java/dev/cel/checker/Standard.java | 41 ++++++++++++++++++- .../test/resources/standardEnvDump.baseline | 8 ++++ .../dev/cel/runtime/StandardFunctions.java | 22 ++++++++++ .../test/resources/boolConversions.baseline | 4 ++ .../test/resources/bytesConversions.baseline | 5 +++ .../test/resources/doubleConversions.baseline | 5 +++ .../test/resources/stringConversions.baseline | 5 +++ .../test/resources/timeConversions.baseline | 17 ++++++++ .../test/resources/uint64Conversions.baseline | 10 +++++ .../dev/cel/testing/BaseInterpreterTest.java | 27 ++++++++++++ 11 files changed, 147 insertions(+), 1 deletion(-) create mode 100644 runtime/src/test/resources/boolConversions.baseline diff --git a/checker/src/main/java/dev/cel/checker/Env.java b/checker/src/main/java/dev/cel/checker/Env.java index 8cc354fb2..613bef166 100644 --- a/checker/src/main/java/dev/cel/checker/Env.java +++ b/checker/src/main/java/dev/cel/checker/Env.java @@ -540,6 +540,10 @@ boolean enableTimestampEpoch() { return celOptions.enableTimestampEpoch(); } + boolean enableUnsignedLongs() { + return celOptions.enableUnsignedLongs(); + } + /** Add an identifier {@code decl} to the environment. */ @CanIgnoreReturnValue private Env addIdent(CelIdentDecl celIdentDecl) { diff --git a/checker/src/main/java/dev/cel/checker/Standard.java b/checker/src/main/java/dev/cel/checker/Standard.java index 1781fe559..eaac8c300 100644 --- a/checker/src/main/java/dev/cel/checker/Standard.java +++ b/checker/src/main/java/dev/cel/checker/Standard.java @@ -99,6 +99,14 @@ public static Env add(Env env) { timestampConversionDeclarations(env.enableTimestampEpoch()).forEach(env::add); numericComparisonDeclarations(env.enableHeterogeneousNumericComparisons()).forEach(env::add); + if (env.enableUnsignedLongs()) { + env.add( + CelFunctionDecl.newFunctionDeclaration( + Function.INT.getFunction(), + CelOverloadDecl.newGlobalOverload( + "int64_to_int64", "type conversion (identity)", SimpleType.INT, SimpleType.INT))); + } + return env; } @@ -384,6 +392,8 @@ private static ImmutableList coreFunctionDeclarations() { celFunctionDeclBuilder.add( CelFunctionDecl.newFunctionDeclaration( Function.UINT.getFunction(), + CelOverloadDecl.newGlobalOverload( + "uint64_to_uint64", "type conversion (identity)", SimpleType.UINT, SimpleType.UINT), CelOverloadDecl.newGlobalOverload( "int64_to_uint64", "type conversion", SimpleType.UINT, SimpleType.INT), CelOverloadDecl.newGlobalOverload( @@ -395,6 +405,11 @@ private static ImmutableList coreFunctionDeclarations() { celFunctionDeclBuilder.add( CelFunctionDecl.newFunctionDeclaration( Function.DOUBLE.getFunction(), + CelOverloadDecl.newGlobalOverload( + "double_to_double", + "type conversion (identity)", + SimpleType.DOUBLE, + SimpleType.DOUBLE), CelOverloadDecl.newGlobalOverload( "int64_to_double", "type conversion", SimpleType.DOUBLE, SimpleType.INT), CelOverloadDecl.newGlobalOverload( @@ -406,6 +421,11 @@ private static ImmutableList coreFunctionDeclarations() { celFunctionDeclBuilder.add( CelFunctionDecl.newFunctionDeclaration( Function.STRING.getFunction(), + CelOverloadDecl.newGlobalOverload( + "string_to_string", + "type conversion (identity)", + SimpleType.STRING, + SimpleType.STRING), CelOverloadDecl.newGlobalOverload( "int64_to_string", "type conversion", SimpleType.STRING, SimpleType.INT), CelOverloadDecl.newGlobalOverload( @@ -423,6 +443,8 @@ private static ImmutableList coreFunctionDeclarations() { celFunctionDeclBuilder.add( CelFunctionDecl.newFunctionDeclaration( Function.BYTES.getFunction(), + CelOverloadDecl.newGlobalOverload( + "bytes_to_bytes", "type conversion (identity)", SimpleType.BYTES, SimpleType.BYTES), CelOverloadDecl.newGlobalOverload( "string_to_bytes", "type conversion", SimpleType.BYTES, SimpleType.STRING))); @@ -437,12 +459,24 @@ private static ImmutableList coreFunctionDeclarations() { celFunctionDeclBuilder.add( CelFunctionDecl.newFunctionDeclaration( Function.DURATION.getFunction(), + CelOverloadDecl.newGlobalOverload( + "duration_to_duration", + "type conversion (identity)", + SimpleType.DURATION, + SimpleType.DURATION), CelOverloadDecl.newGlobalOverload( "string_to_duration", "type conversion, duration should be end with \"s\", which stands for seconds", SimpleType.DURATION, SimpleType.STRING))); + // Conversions to boolean + celFunctionDeclBuilder.add( + CelFunctionDecl.newFunctionDeclaration( + Function.BOOL.getFunction(), + CelOverloadDecl.newGlobalOverload( + "bool_to_bool", "type conversion (identity)", SimpleType.BOOL, SimpleType.BOOL))); + // String functions celFunctionDeclBuilder.add( CelFunctionDecl.newFunctionDeclaration( @@ -674,7 +708,12 @@ private static ImmutableList timestampConversionDeclarations(bo "Type conversion of strings to timestamps according to RFC3339. Example:" + " \"1972-01-01T10:00:20.021-05:00\".", SimpleType.TIMESTAMP, - SimpleType.STRING)); + SimpleType.STRING), + CelOverloadDecl.newGlobalOverload( + "timestamp_to_timestamp", + "type conversion (identity)", + SimpleType.TIMESTAMP, + SimpleType.TIMESTAMP)); if (withEpoch) { timestampBuilder.addOverloads( CelOverloadDecl.newGlobalOverload( diff --git a/checker/src/test/resources/standardEnvDump.baseline b/checker/src/test/resources/standardEnvDump.baseline index a49852d84..5f88f7f50 100644 --- a/checker/src/test/resources/standardEnvDump.baseline +++ b/checker/src/test/resources/standardEnvDump.baseline @@ -143,9 +143,11 @@ declare _||_ { } declare bool { value type(bool) + function bool_to_bool (bool) -> bool } declare bytes { value type(bytes) + function bytes_to_bytes (bytes) -> bytes function string_to_bytes (string) -> bytes } declare contains { @@ -153,11 +155,13 @@ declare contains { } declare double { value type(double) + function double_to_double (double) -> double function int64_to_double (int) -> double function uint64_to_double (uint) -> double function string_to_double (string) -> double } declare duration { + function duration_to_duration (google.protobuf.Duration) -> google.protobuf.Duration function string_to_duration (string) -> google.protobuf.Duration } declare dyn { @@ -217,6 +221,7 @@ declare int { function double_to_int64 (double) -> int function string_to_int64 (string) -> int function timestamp_to_int64 (google.protobuf.Timestamp) -> int + function int64_to_int64 (int) -> int } declare list { value type(list(dyn)) @@ -246,6 +251,7 @@ declare startsWith { } declare string { value type(string) + function string_to_string (string) -> string function int64_to_string (int) -> string function uint64_to_string (uint) -> string function double_to_string (double) -> string @@ -255,6 +261,7 @@ declare string { } declare timestamp { function string_to_timestamp (string) -> google.protobuf.Timestamp + function timestamp_to_timestamp (google.protobuf.Timestamp) -> google.protobuf.Timestamp function int64_to_timestamp (int) -> google.protobuf.Timestamp } declare type { @@ -263,6 +270,7 @@ declare type { } declare uint { value type(uint) + function uint64_to_uint64 (uint) -> uint function int64_to_uint64 (int) -> uint function double_to_uint64 (double) -> uint function string_to_uint64 (string) -> uint diff --git a/runtime/src/main/java/dev/cel/runtime/StandardFunctions.java b/runtime/src/main/java/dev/cel/runtime/StandardFunctions.java index d7d00fdaa..23a77c0c7 100644 --- a/runtime/src/main/java/dev/cel/runtime/StandardFunctions.java +++ b/runtime/src/main/java/dev/cel/runtime/StandardFunctions.java @@ -154,6 +154,8 @@ public static void addNonInlined( } private static void addBoolFunctions(Registrar registrar) { + // Identity + registrar.add("bool_to_bool", Boolean.class, (Boolean x) -> x); // The conditional, logical_or, logical_and, and not_strictly_false functions are special-cased. registrar.add("logical_not", Boolean.class, (Boolean x) -> !x); @@ -167,6 +169,8 @@ private static void addBoolFunctions(Registrar registrar) { } private static void addBytesFunctions(Registrar registrar) { + // Identity + registrar.add("bytes_to_bytes", ByteString.class, (ByteString x) -> x); // Bytes ordering functions: <, <=, >=, > registrar.add( "less_bytes", @@ -205,6 +209,8 @@ private static void addBytesFunctions(Registrar registrar) { } private static void addDoubleFunctions(Registrar registrar, CelOptions celOptions) { + // Identity + registrar.add("double_to_double", Double.class, (Double x) -> x); // Double ordering functions. registrar.add("less_double", Double.class, Double.class, (Double x, Double y) -> x < y); registrar.add("less_equals_double", Double.class, Double.class, (Double x, Double y) -> x <= y); @@ -245,6 +251,8 @@ private static void addDoubleFunctions(Registrar registrar, CelOptions celOption } private static void addDurationFunctions(Registrar registrar) { + // Identity + registrar.add("duration_to_duration", Duration.class, (Duration x) -> x); // Duration ordering functions: <, <=, >=, > registrar.add( "less_duration", @@ -307,6 +315,12 @@ private static void addDurationFunctions(Registrar registrar) { } private static void addIntFunctions(Registrar registrar, CelOptions celOptions) { + // Identity + if (celOptions.enableUnsignedLongs()) { + // Note that we require UnsignedLong flag here to avoid ambiguous overloads against + // "uint64_to_int64", because they both use the same Java Long class. + registrar.add("int64_to_int64", Long.class, (Long x) -> x); + } // Comparison functions. registrar.add("less_int64", Long.class, Long.class, (Long x, Long y) -> x < y); registrar.add("less_equals_int64", Long.class, Long.class, (Long x, Long y) -> x <= y); @@ -499,6 +513,8 @@ private static void addMapFunctions( } private static void addStringFunctions(Registrar registrar, CelOptions celOptions) { + // Identity + registrar.add("string_to_string", String.class, (String x) -> x); // String ordering functions: <, <=, >=, >. registrar.add( "less_string", String.class, String.class, (String x, String y) -> x.compareTo(y) < 0); @@ -547,6 +563,8 @@ private static void addStringFunctions(Registrar registrar, CelOptions celOption // timestamp_to_milliseconds overload @SuppressWarnings("JavaLocalDateTimeGetNano") private static void addTimestampFunctions(Registrar registrar) { + // Identity + registrar.add("timestamp_to_timestamp", Timestamp.class, (Timestamp x) -> x); // Timestamp relation operators: <, <=, >=, > registrar.add( "less_timestamp", @@ -714,6 +732,8 @@ private static void addTimestampFunctions(Registrar registrar) { } private static void addSignedUintFunctions(Registrar registrar, CelOptions celOptions) { + // Identity + registrar.add("uint64_to_uint64", Long.class, (Long x) -> x); // Uint relation operators: <, <=, >=, > registrar.add( "less_uint64", @@ -833,6 +853,8 @@ private static void addSignedUintFunctions(Registrar registrar, CelOptions celOp } private static void addUintFunctions(Registrar registrar, CelOptions celOptions) { + // Identity + registrar.add("uint64_to_uint64", UnsignedLong.class, (UnsignedLong x) -> x); registrar.add( "less_uint64", UnsignedLong.class, diff --git a/runtime/src/test/resources/boolConversions.baseline b/runtime/src/test/resources/boolConversions.baseline new file mode 100644 index 000000000..3d7415aba --- /dev/null +++ b/runtime/src/test/resources/boolConversions.baseline @@ -0,0 +1,4 @@ +Source: bool(true) +=====> +bindings: {} +result: true \ No newline at end of file diff --git a/runtime/src/test/resources/bytesConversions.baseline b/runtime/src/test/resources/bytesConversions.baseline index 4c1458268..6324929ce 100644 --- a/runtime/src/test/resources/bytesConversions.baseline +++ b/runtime/src/test/resources/bytesConversions.baseline @@ -2,3 +2,8 @@ Source: bytes('abc\303') =====> bindings: {} result: abcà + +Source: bytes(bytes('abc\303')) +=====> +bindings: {} +result: abcà \ No newline at end of file diff --git a/runtime/src/test/resources/doubleConversions.baseline b/runtime/src/test/resources/doubleConversions.baseline index d15dfe090..682e56edc 100644 --- a/runtime/src/test/resources/doubleConversions.baseline +++ b/runtime/src/test/resources/doubleConversions.baseline @@ -18,3 +18,8 @@ Source: double('bad') bindings: {} error: evaluation error: For input string: "bad" error_code: BAD_FORMAT + +Source: double(1.5) +=====> +bindings: {} +result: 1.5 \ No newline at end of file diff --git a/runtime/src/test/resources/stringConversions.baseline b/runtime/src/test/resources/stringConversions.baseline index 7e20cff19..59406fc85 100644 --- a/runtime/src/test/resources/stringConversions.baseline +++ b/runtime/src/test/resources/stringConversions.baseline @@ -32,3 +32,8 @@ Source: string(duration('1000000s')) =====> bindings: {} result: 1000000s + +Source: string('hello') +=====> +bindings: {} +result: hello \ No newline at end of file diff --git a/runtime/src/test/resources/timeConversions.baseline b/runtime/src/test/resources/timeConversions.baseline index 18b8fdcb0..cb1c4e886 100644 --- a/runtime/src/test/resources/timeConversions.baseline +++ b/runtime/src/test/resources/timeConversions.baseline @@ -54,3 +54,20 @@ declare t1 { bindings: {} error: evaluation error: invalid duration format error_code: BAD_FORMAT + +Source: duration(duration('15.0s')) +declare t1 { + value google.protobuf.Timestamp +} +=====> +bindings: {} +result: seconds: 15 + + +Source: timestamp(timestamp(123)) +declare t1 { + value google.protobuf.Timestamp +} +=====> +bindings: {} +result: seconds: 123 \ No newline at end of file diff --git a/runtime/src/test/resources/uint64Conversions.baseline b/runtime/src/test/resources/uint64Conversions.baseline index cfdc61974..fac9bfc52 100644 --- a/runtime/src/test/resources/uint64Conversions.baseline +++ b/runtime/src/test/resources/uint64Conversions.baseline @@ -35,3 +35,13 @@ Source: uint('f1') bindings: {} error: evaluation error: f1 error_code: BAD_FORMAT + +Source: uint(1u) +=====> +bindings: {} +result: 1 + +Source: uint(dyn(1u)) +=====> +bindings: {} +result: 1 diff --git a/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java b/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java index 795145508..3b9d63f11 100644 --- a/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java +++ b/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java @@ -1261,6 +1261,12 @@ public void timeConversions() throws Exception { // Not supported. source = "duration('inf')"; runTest(Activation.EMPTY); + + source = "duration(duration('15.0s'))"; // Identity + runTest(Activation.EMPTY); + + source = "timestamp(timestamp(123))"; // Identity + runTest(Activation.EMPTY); } @Test @@ -1491,6 +1497,12 @@ public void uint64Conversions() throws Exception { source = "uint('f1')"; // should error runTest(Activation.EMPTY); + + source = "uint(1u)"; // identity + runTest(Activation.EMPTY); + + source = "uint(dyn(1u))"; // identity, check dynamic dispatch + runTest(Activation.EMPTY); } @Test @@ -1506,6 +1518,9 @@ public void doubleConversions() throws Exception { source = "double('bad')"; runTest(Activation.EMPTY); + + source = "double(1.5)"; // Identity + runTest(Activation.EMPTY); } @Test @@ -1536,6 +1551,9 @@ public void stringConversions() throws Exception { source = "string(duration('1000000s'))"; runTest(Activation.EMPTY); + + source = "string('hello')"; // Identity + runTest(Activation.EMPTY); } @Test @@ -1546,10 +1564,19 @@ public void bytes() throws Exception { runTest(Activation.EMPTY); } + @Test + public void boolConversions() throws Exception { + source = "bool(true)"; + runTest(Activation.EMPTY); // Identity + } + @Test public void bytesConversions() throws Exception { source = "bytes('abc\\303')"; runTest(Activation.EMPTY); // string converts to abcà in bytes form. + + source = "bytes(bytes('abc\\303'))"; // Identity + runTest(Activation.EMPTY); } @Test From 4c34530eeef871f74a55cdfabe5967244bd42aeb Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Fri, 2 Aug 2024 13:06:41 -0700 Subject: [PATCH 166/486] Add string to boolean conversion function in the standard definition PiperOrigin-RevId: 658882554 --- .../main/java/dev/cel/checker/Standard.java | 4 ++- .../test/resources/standardEnvDump.baseline | 1 + .../dev/cel/runtime/StandardFunctions.java | 27 +++++++++++++++++++ .../test/resources/boolConversions.baseline | 24 ++++++++++++++++- .../dev/cel/testing/BaseInterpreterTest.java | 12 +++++++++ 5 files changed, 66 insertions(+), 2 deletions(-) diff --git a/checker/src/main/java/dev/cel/checker/Standard.java b/checker/src/main/java/dev/cel/checker/Standard.java index eaac8c300..acdc185eb 100644 --- a/checker/src/main/java/dev/cel/checker/Standard.java +++ b/checker/src/main/java/dev/cel/checker/Standard.java @@ -475,7 +475,9 @@ private static ImmutableList coreFunctionDeclarations() { CelFunctionDecl.newFunctionDeclaration( Function.BOOL.getFunction(), CelOverloadDecl.newGlobalOverload( - "bool_to_bool", "type conversion (identity)", SimpleType.BOOL, SimpleType.BOOL))); + "bool_to_bool", "type conversion (identity)", SimpleType.BOOL, SimpleType.BOOL), + CelOverloadDecl.newGlobalOverload( + "string_to_bool", "type conversion", SimpleType.BOOL, SimpleType.STRING))); // String functions celFunctionDeclBuilder.add( diff --git a/checker/src/test/resources/standardEnvDump.baseline b/checker/src/test/resources/standardEnvDump.baseline index 5f88f7f50..df1c66553 100644 --- a/checker/src/test/resources/standardEnvDump.baseline +++ b/checker/src/test/resources/standardEnvDump.baseline @@ -144,6 +144,7 @@ declare _||_ { declare bool { value type(bool) function bool_to_bool (bool) -> bool + function string_to_bool (string) -> bool } declare bytes { value type(bytes) diff --git a/runtime/src/main/java/dev/cel/runtime/StandardFunctions.java b/runtime/src/main/java/dev/cel/runtime/StandardFunctions.java index 23a77c0c7..c69c98271 100644 --- a/runtime/src/main/java/dev/cel/runtime/StandardFunctions.java +++ b/runtime/src/main/java/dev/cel/runtime/StandardFunctions.java @@ -156,6 +156,33 @@ public static void addNonInlined( private static void addBoolFunctions(Registrar registrar) { // Identity registrar.add("bool_to_bool", Boolean.class, (Boolean x) -> x); + // Conversion function + registrar.add( + "string_to_bool", + String.class, + (String str) -> { + // Note: this is a bit less permissive than what cel-go allows (it accepts '1', 't'). + switch (str) { + case "true": + case "TRUE": + case "True": + case "t": + case "1": + return true; + case "false": + case "FALSE": + case "False": + case "f": + case "0": + return false; + default: + throw new InterpreterException.Builder( + "Type conversion error from 'string' to 'bool': [%s]", str) + .setErrorCode(CelErrorCode.BAD_FORMAT) + .build(); + } + }); + // The conditional, logical_or, logical_and, and not_strictly_false functions are special-cased. registrar.add("logical_not", Boolean.class, (Boolean x) -> !x); diff --git a/runtime/src/test/resources/boolConversions.baseline b/runtime/src/test/resources/boolConversions.baseline index 3d7415aba..2bc832baa 100644 --- a/runtime/src/test/resources/boolConversions.baseline +++ b/runtime/src/test/resources/boolConversions.baseline @@ -1,4 +1,26 @@ Source: bool(true) =====> bindings: {} -result: true \ No newline at end of file +result: true + +Source: bool('true') && bool('TRUE') && bool('True') && bool('t') && bool('1') +=====> +bindings: {} +result: true + +Source: bool('false') || bool('FALSE') || bool('False') || bool('f') || bool('0') +=====> +bindings: {} +result: false + +Source: bool('TrUe') +=====> +bindings: {} +error: evaluation error: Type conversion error from 'string' to 'bool': [TrUe] +error_code: BAD_FORMAT + +Source: bool('FaLsE') +=====> +bindings: {} +error: evaluation error: Type conversion error from 'string' to 'bool': [FaLsE] +error_code: BAD_FORMAT diff --git a/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java b/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java index 3b9d63f11..811af7033 100644 --- a/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java +++ b/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java @@ -1568,6 +1568,18 @@ public void bytes() throws Exception { public void boolConversions() throws Exception { source = "bool(true)"; runTest(Activation.EMPTY); // Identity + + source = "bool('true') && bool('TRUE') && bool('True') && bool('t') && bool('1')"; + runTest(Activation.EMPTY); // result is true + + source = "bool('false') || bool('FALSE') || bool('False') || bool('f') || bool('0')"; + runTest(Activation.EMPTY); // result is false + + source = "bool('TrUe')"; + runTest(Activation.EMPTY); // exception + + source = "bool('FaLsE')"; + runTest(Activation.EMPTY); // exception } @Test From eba4c270e5cbc27e318d9f244e148ebb79e60b6e Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Fri, 2 Aug 2024 14:29:25 -0700 Subject: [PATCH 167/486] Upgrade protobuf version to 4.27.3 PiperOrigin-RevId: 658906809 --- WORKSPACE | 28 +++++++++++++------ .../src/main/java/dev/cel/bundle/BUILD.bazel | 2 +- .../src/test/java/dev/cel/bundle/BUILD.bazel | 5 ++-- .../src/main/java/dev/cel/checker/BUILD.bazel | 10 +++---- .../src/test/java/dev/cel/checker/BUILD.bazel | 4 +-- codelab/src/main/codelab/BUILD.bazel | 4 +-- .../src/main/codelab/solutions/BUILD.bazel | 4 +-- codelab/src/test/codelab/BUILD.bazel | 16 +++++------ .../src/test/codelab/solutions/BUILD.bazel | 16 +++++------ .../src/main/java/dev/cel/common/BUILD.bazel | 4 +-- .../main/java/dev/cel/common/ast/BUILD.bazel | 4 +-- .../java/dev/cel/common/internal/BUILD.bazel | 18 ++++++------ .../java/dev/cel/common/types/BUILD.bazel | 6 ++-- .../java/dev/cel/common/values/BUILD.bazel | 4 +-- .../src/test/java/dev/cel/common/BUILD.bazel | 4 +-- .../test/java/dev/cel/common/ast/BUILD.bazel | 2 +- .../java/dev/cel/common/internal/BUILD.bazel | 4 +-- .../java/dev/cel/common/values/BUILD.bazel | 2 +- .../main/java/dev/cel/compiler/BUILD.bazel | 4 +-- .../main/java/dev/cel/extensions/BUILD.bazel | 4 +-- .../test/java/dev/cel/extensions/BUILD.bazel | 2 +- .../src/main/java/dev/cel/parser/BUILD.bazel | 2 +- .../src/test/java/dev/cel/parser/BUILD.bazel | 2 +- .../src/test/java/dev/cel/policy/BUILD.bazel | 2 +- .../src/main/java/dev/cel/runtime/BUILD.bazel | 8 +++--- .../src/test/java/dev/cel/runtime/BUILD.bazel | 4 +-- .../src/main/java/dev/cel/testing/BUILD.bazel | 10 +++---- .../src/test/java/dev/cel/testing/BUILD.bazel | 4 +-- .../dev/cel/validator/validators/BUILD.bazel | 4 +-- .../dev/cel/validator/validators/BUILD.bazel | 2 +- 30 files changed, 98 insertions(+), 87 deletions(-) diff --git a/WORKSPACE b/WORKSPACE index 09fdb0443..798ad38c8 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -20,10 +20,10 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive", "http_jar") http_archive( name = "bazel_skylib", - sha256 = "74d544d96f4a5bb630d465ca8bbcfe231e3594e5aae57e1edbf17a6eb3ca2506", + sha256 = "bc283cdfcd526a52c3201279cda4bc298652efa898b10b4db0837dc51652756f", urls = [ - "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.3.0/bazel-skylib-1.3.0.tar.gz", - "https://github.com/bazelbuild/bazel-skylib/releases/download/1.3.0/bazel-skylib-1.3.0.tar.gz", + "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.7.1/bazel-skylib-1.7.1.tar.gz", + "https://github.com/bazelbuild/bazel-skylib/releases/download/1.7.1/bazel-skylib-1.7.1.tar.gz", ], ) @@ -31,6 +31,18 @@ load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace") bazel_skylib_workspace() +# Transitive dependency required by protobuf v4 https://github.com/protocolbuffers/protobuf/issues/17200 +http_archive( + name = "rules_python", + sha256 = "778aaeab3e6cfd56d681c89f5c10d7ad6bf8d2f1a72de9de55b23081b2d31618", + strip_prefix = "rules_python-0.34.0", + url = "https://github.com/bazelbuild/rules_python/releases/download/0.34.0/rules_python-0.34.0.tar.gz", +) + +load("@rules_python//python:repositories.bzl", "py_repositories") + +py_repositories() + RULES_JVM_EXTERNAL_TAG = "aa44247b3913da0da606e9c522313b6a9396a571" RULES_JVM_EXTERNAL_SHA = "87378580865af690a78230e04eba1cd6d9c60d0db303ea129dc717705d711d9c" @@ -58,15 +70,13 @@ ANTLR4_VERSION = "4.13.1" maven_install( # keep sorted artifacts = [ - "com.google.api.grpc:proto-google-common-protos:2.38.0", "com.google.auto.value:auto-value:1.10.4", "com.google.auto.value:auto-value-annotations:1.10.4", "com.google.code.findbugs:annotations:3.0.1", "com.google.errorprone:error_prone_annotations:2.26.1", "com.google.guava:guava:33.1.0-jre", "com.google.guava:guava-testlib:33.1.0-jre", - "com.google.protobuf:protobuf-java:3.25.3", - "com.google.protobuf:protobuf-java-util:3.25.3", + "com.google.protobuf:protobuf-java-util:4.27.3", "com.google.re2j:re2j:1.7", "com.google.testparameterinjector:test-parameter-injector:1.15", "com.google.truth.extensions:truth-java8-extension:1.4.2", @@ -85,9 +95,9 @@ maven_install( http_archive( name = "com_google_protobuf", - sha256 = "b1d6dd2cbb5d87e17af41cadb720322ce7e13af826268707bd8db47e5654770b", - strip_prefix = "protobuf-21.11", - urls = ["https://github.com/protocolbuffers/protobuf/archive/v21.11.tar.gz"], + sha256 = "1535151efbc7893f38b0578e83cac584f2819974f065698976989ec71c1af84a", + strip_prefix = "protobuf-27.3", + urls = ["https://github.com/protocolbuffers/protobuf/archive/v27.3.tar.gz"], ) # Required by com_google_protobuf diff --git a/bundle/src/main/java/dev/cel/bundle/BUILD.bazel b/bundle/src/main/java/dev/cel/bundle/BUILD.bazel index c2c7d3f10..70744129c 100644 --- a/bundle/src/main/java/dev/cel/bundle/BUILD.bazel +++ b/bundle/src/main/java/dev/cel/bundle/BUILD.bazel @@ -37,10 +37,10 @@ java_library( "//parser:macro", "//parser:parser_builder", "//runtime", + "@@protobuf~//java/core", "@cel_spec//proto/cel/expr:expr_java_proto", "@maven//:com_google_code_findbugs_annotations", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", - "@maven//:com_google_protobuf_protobuf_java", ], ) diff --git a/bundle/src/test/java/dev/cel/bundle/BUILD.bazel b/bundle/src/test/java/dev/cel/bundle/BUILD.bazel index cccfc8eed..f19406eec 100644 --- a/bundle/src/test/java/dev/cel/bundle/BUILD.bazel +++ b/bundle/src/test/java/dev/cel/bundle/BUILD.bazel @@ -36,11 +36,12 @@ java_library( "//parser:macro", "//runtime", "//runtime:unknown_attributes", + "@@protobuf~//java/core", "@cel_spec//proto/cel/expr:expr_java_proto", - "@maven//:com_google_api_grpc_proto_google_common_protos", + "@com_google_googleapis//google/rpc/context:attribute_context_java_proto", + "@com_google_googleapis//google/type:type_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_guava_guava_testlib", - "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_protobuf_protobuf_java_util", "@maven//:com_google_testparameterinjector_test_parameter_injector", "@maven//:com_google_truth_extensions_truth_proto_extension", diff --git a/checker/src/main/java/dev/cel/checker/BUILD.bazel b/checker/src/main/java/dev/cel/checker/BUILD.bazel index 0053d9061..039eb7f6c 100644 --- a/checker/src/main/java/dev/cel/checker/BUILD.bazel +++ b/checker/src/main/java/dev/cel/checker/BUILD.bazel @@ -50,10 +50,10 @@ java_library( "//common/types", "//common/types:cel_types", "//common/types:type_providers", + "@@protobuf~//java/core", "@cel_spec//proto/cel/expr:expr_java_proto", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", - "@maven//:com_google_protobuf_protobuf_java", "@maven//:org_jspecify_jspecify", ], ) @@ -81,10 +81,10 @@ java_library( "//common/types:cel_types", "//common/types:message_type_provider", "//common/types:type_providers", + "@@protobuf~//java/core", "@cel_spec//proto/cel/expr:expr_java_proto", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", - "@maven//:com_google_protobuf_protobuf_java", ], ) @@ -100,9 +100,9 @@ java_library( "//common:compiler_common", "//common:options", "//common/types:type_providers", + "@@protobuf~//java/core", "@cel_spec//proto/cel/expr:expr_java_proto", "@maven//:com_google_errorprone_error_prone_annotations", - "@maven//:com_google_protobuf_protobuf_java", ], ) @@ -113,9 +113,9 @@ java_library( ], deps = [ "//:auto_value", + "@@protobuf~//java/core", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", - "@maven//:com_google_protobuf_protobuf_java", ], ) @@ -180,10 +180,10 @@ java_library( "//common/types:type_providers", "//parser:macro", "//parser:operator", + "@@protobuf~//java/core", "@cel_spec//proto/cel/expr:expr_java_proto", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", - "@maven//:com_google_protobuf_protobuf_java", "@maven//:org_jspecify_jspecify", ], ) diff --git a/checker/src/test/java/dev/cel/checker/BUILD.bazel b/checker/src/test/java/dev/cel/checker/BUILD.bazel index 338dcbb10..52a39a8ae 100644 --- a/checker/src/test/java/dev/cel/checker/BUILD.bazel +++ b/checker/src/test/java/dev/cel/checker/BUILD.bazel @@ -10,6 +10,7 @@ java_library( srcs = glob(["*Test.java"]), resources = ["//checker/src/test/resources:baselines"], deps = [ + "@@protobuf~//java/core", # "//java/com/google/testing/testsize:annotations", "//:auto_value", "//checker", @@ -48,9 +49,8 @@ java_library( "//:java_truth", "@maven//:com_google_truth_extensions_truth_proto_extension", "@cel_spec//proto/cel/expr:expr_java_proto", - "@maven//:com_google_api_grpc_proto_google_common_protos", + "@com_google_googleapis//google/rpc/context:attribute_context_java_proto", "@maven//:com_google_guava_guava", - "@maven//:com_google_protobuf_protobuf_java", ], ) diff --git a/codelab/src/main/codelab/BUILD.bazel b/codelab/src/main/codelab/BUILD.bazel index 6c9f90259..7b3065e47 100644 --- a/codelab/src/main/codelab/BUILD.bazel +++ b/codelab/src/main/codelab/BUILD.bazel @@ -33,9 +33,9 @@ java_library( "//validator/validators:homogeneous_literal", # unuseddeps: keep "//validator/validators:regex", # unuseddeps: keep "//validator/validators:timestamp", # unuseddeps: keep - "@maven//:com_google_api_grpc_proto_google_common_protos", # unuseddeps: keep + "@@protobuf~//java/core", # unuseddeps: keep + "@com_google_googleapis//google/rpc/context:attribute_context_java_proto", # unuseddeps: keep "@maven//:com_google_guava_guava", # unuseddeps: keep - "@maven//:com_google_protobuf_protobuf_java", # unuseddeps: keep "@maven//:com_google_protobuf_protobuf_java_util", # unuseddeps: keep ], ) diff --git a/codelab/src/main/codelab/solutions/BUILD.bazel b/codelab/src/main/codelab/solutions/BUILD.bazel index 44f9632ea..42820a846 100644 --- a/codelab/src/main/codelab/solutions/BUILD.bazel +++ b/codelab/src/main/codelab/solutions/BUILD.bazel @@ -33,9 +33,9 @@ java_library( "//validator/validators:homogeneous_literal", "//validator/validators:regex", "//validator/validators:timestamp", - "@maven//:com_google_api_grpc_proto_google_common_protos", + "@@protobuf~//java/core", + "@com_google_googleapis//google/rpc/context:attribute_context_java_proto", "@maven//:com_google_guava_guava", - "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_protobuf_protobuf_java_util", ], ) diff --git a/codelab/src/test/codelab/BUILD.bazel b/codelab/src/test/codelab/BUILD.bazel index 8772578c1..84363646a 100644 --- a/codelab/src/test/codelab/BUILD.bazel +++ b/codelab/src/test/codelab/BUILD.bazel @@ -27,9 +27,9 @@ java_test( "//codelab", "//common", "//common/types", - "@maven//:com_google_api_grpc_proto_google_common_protos", + "@@protobuf~//java/core", + "@com_google_googleapis//google/rpc/context:attribute_context_java_proto", "@maven//:com_google_guava_guava", - "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_testparameterinjector_test_parameter_injector", "@maven//:junit_junit", ], @@ -58,9 +58,9 @@ java_test( "//:java_truth", "//codelab", "//common", - "@maven//:com_google_api_grpc_proto_google_common_protos", + "@@protobuf~//java/core", + "@com_google_googleapis//google/rpc/context:attribute_context_java_proto", "@maven//:com_google_guava_guava", - "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_testparameterinjector_test_parameter_injector", "@maven//:junit_junit", ], @@ -91,9 +91,9 @@ java_test( "//:java_truth", "//codelab", "//common", - "@maven//:com_google_api_grpc_proto_google_common_protos", + "@@protobuf~//java/core", + "@com_google_googleapis//google/rpc/context:attribute_context_java_proto", "@maven//:com_google_guava_guava", - "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_protobuf_protobuf_java_util", "@maven//:com_google_testparameterinjector_test_parameter_injector", "@maven//:junit_junit", @@ -127,7 +127,7 @@ java_test( "//common:compiler_common", "//parser:unparser", "//runtime", - "@maven//:com_google_api_grpc_proto_google_common_protos", + "@com_google_googleapis//google/rpc/context:attribute_context_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_testparameterinjector_test_parameter_injector", "@maven//:junit_junit", @@ -144,7 +144,7 @@ java_test( "//codelab", "//common", "//common:compiler_common", - "@maven//:com_google_api_grpc_proto_google_common_protos", + "@com_google_googleapis//google/rpc/context:attribute_context_java_proto", "@maven//:com_google_testparameterinjector_test_parameter_injector", "@maven//:junit_junit", ], diff --git a/codelab/src/test/codelab/solutions/BUILD.bazel b/codelab/src/test/codelab/solutions/BUILD.bazel index 0ac187a92..be146d8f9 100644 --- a/codelab/src/test/codelab/solutions/BUILD.bazel +++ b/codelab/src/test/codelab/solutions/BUILD.bazel @@ -25,9 +25,9 @@ java_test( "//codelab:solutions", "//common", "//common/types", - "@maven//:com_google_api_grpc_proto_google_common_protos", + "@@protobuf~//java/core", + "@com_google_googleapis//google/rpc/context:attribute_context_java_proto", "@maven//:com_google_guava_guava", - "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_testparameterinjector_test_parameter_injector", "@maven//:junit_junit", ], @@ -54,9 +54,9 @@ java_test( "//:java_truth", "//codelab:solutions", "//common", - "@maven//:com_google_api_grpc_proto_google_common_protos", + "@@protobuf~//java/core", + "@com_google_googleapis//google/rpc/context:attribute_context_java_proto", "@maven//:com_google_guava_guava", - "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_testparameterinjector_test_parameter_injector", "@maven//:junit_junit", ], @@ -85,9 +85,9 @@ java_test( "//:java_truth", "//codelab:solutions", "//common", - "@maven//:com_google_api_grpc_proto_google_common_protos", + "@@protobuf~//java/core", + "@com_google_googleapis//google/rpc/context:attribute_context_java_proto", "@maven//:com_google_guava_guava", - "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_protobuf_protobuf_java_util", "@maven//:com_google_testparameterinjector_test_parameter_injector", "@maven//:junit_junit", @@ -119,7 +119,7 @@ java_test( "//common:compiler_common", "//parser:unparser", "//runtime", - "@maven//:com_google_api_grpc_proto_google_common_protos", + "@com_google_googleapis//google/rpc/context:attribute_context_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_testparameterinjector_test_parameter_injector", "@maven//:junit_junit", @@ -135,7 +135,7 @@ java_test( "//codelab:solutions", "//common", "//common:compiler_common", - "@maven//:com_google_api_grpc_proto_google_common_protos", + "@com_google_googleapis//google/rpc/context:attribute_context_java_proto", "@maven//:com_google_testparameterinjector_test_parameter_injector", "@maven//:junit_junit", ], diff --git a/common/src/main/java/dev/cel/common/BUILD.bazel b/common/src/main/java/dev/cel/common/BUILD.bazel index dbb8890d5..4706fb93d 100644 --- a/common/src/main/java/dev/cel/common/BUILD.bazel +++ b/common/src/main/java/dev/cel/common/BUILD.bazel @@ -55,10 +55,10 @@ java_library( "//common/types", "//common/types:cel_types", "//common/types:type_providers", + "@@protobuf~//java/core", "@cel_spec//proto/cel/expr:expr_java_proto", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", - "@maven//:com_google_protobuf_protobuf_java", ], ) @@ -178,9 +178,9 @@ java_library( tags = [ ], deps = [ + "@@protobuf~//java/core", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", - "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_protobuf_protobuf_java_util", ], ) diff --git a/common/src/main/java/dev/cel/common/ast/BUILD.bazel b/common/src/main/java/dev/cel/common/ast/BUILD.bazel index c59178bcd..6c1709f1a 100644 --- a/common/src/main/java/dev/cel/common/ast/BUILD.bazel +++ b/common/src/main/java/dev/cel/common/ast/BUILD.bazel @@ -46,9 +46,9 @@ java_library( deps = [ "//:auto_value", "//common/annotations", + "@@protobuf~//java/core", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", - "@maven//:com_google_protobuf_protobuf_java", "@maven//:org_jspecify_jspecify", ], ) @@ -96,8 +96,8 @@ java_library( deps = [ ":ast", "//common/annotations", + "@@protobuf~//java/core", "@maven//:com_google_guava_guava", - "@maven//:com_google_protobuf_protobuf_java", ], ) diff --git a/common/src/main/java/dev/cel/common/internal/BUILD.bazel b/common/src/main/java/dev/cel/common/internal/BUILD.bazel index 0ea165ae1..70a91fc8c 100644 --- a/common/src/main/java/dev/cel/common/internal/BUILD.bazel +++ b/common/src/main/java/dev/cel/common/internal/BUILD.bazel @@ -40,9 +40,9 @@ java_library( "//:auto_value", "//common/annotations", "//common/ast", + "@@protobuf~//java/core", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", - "@maven//:com_google_protobuf_protobuf_java", "@maven//:org_antlr_antlr4_runtime", ], ) @@ -103,8 +103,8 @@ java_library( ], deps = [ "//common/annotations", + "@@protobuf~//java/core", "@maven//:com_google_guava_guava", - "@maven//:com_google_protobuf_protobuf_java", ], ) @@ -124,11 +124,11 @@ java_library( "//common:proto_json_adapter", "//common:runtime_exception", "//common/annotations", + "@@protobuf~//java/core", "@cel_spec//proto/cel/expr:expr_java_proto", "@maven//:com_google_code_findbugs_annotations", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", - "@maven//:com_google_protobuf_protobuf_java", "@maven//:org_jspecify_jspecify", ], ) @@ -142,9 +142,9 @@ java_library( ":dynamic_proto", "//:auto_value", "//common/annotations", + "@@protobuf~//java/core", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", - "@maven//:com_google_protobuf_protobuf_java", "@maven//:org_jspecify_jspecify", ], ) @@ -158,9 +158,9 @@ java_library( ], deps = [ "//:auto_value", + "@@protobuf~//java/core", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", - "@maven//:com_google_protobuf_protobuf_java", ], ) @@ -182,8 +182,8 @@ java_library( ], deps = [ "//common/annotations", + "@@protobuf~//java/core", "@maven//:com_google_guava_guava", - "@maven//:com_google_protobuf_protobuf_java", ], ) @@ -197,7 +197,7 @@ java_library( ":default_instance_message_factory", ":proto_message_factory", "//common/annotations", - "@maven//:com_google_protobuf_protobuf_java", + "@@protobuf~//java/core", ], ) @@ -208,9 +208,9 @@ java_library( ], deps = [ ":cel_descriptor_pools", + "@@protobuf~//java/core", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", - "@maven//:com_google_protobuf_protobuf_java", ], ) @@ -223,9 +223,9 @@ java_library( ":well_known_proto", "//common", "//common/annotations", + "@@protobuf~//java/core", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", - "@maven//:com_google_protobuf_protobuf_java", ], ) diff --git a/common/src/main/java/dev/cel/common/types/BUILD.bazel b/common/src/main/java/dev/cel/common/types/BUILD.bazel index 1a3f3ca0d..19c741e0f 100644 --- a/common/src/main/java/dev/cel/common/types/BUILD.bazel +++ b/common/src/main/java/dev/cel/common/types/BUILD.bazel @@ -73,9 +73,9 @@ java_library( ":type_providers", ":types", "//common/annotations", + "@@protobuf~//java/core", "@cel_spec//proto/cel/expr:expr_java_proto", "@maven//:com_google_guava_guava", - "@maven//:com_google_protobuf_protobuf_java", ], ) @@ -88,9 +88,9 @@ java_library( ":type_providers", ":types", "//common/annotations", + "@@protobuf~//java/core", "@com_google_googleapis//google/api/expr/v1alpha1:expr_java_proto", "@maven//:com_google_guava_guava", - "@maven//:com_google_protobuf_protobuf_java", ], ) @@ -132,8 +132,8 @@ java_library( "//:auto_value", "//common", "//common/internal:file_descriptor_converter", + "@@protobuf~//java/core", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", - "@maven//:com_google_protobuf_protobuf_java", ], ) diff --git a/common/src/main/java/dev/cel/common/values/BUILD.bazel b/common/src/main/java/dev/cel/common/values/BUILD.bazel index 766e22309..fcb1269fa 100644 --- a/common/src/main/java/dev/cel/common/values/BUILD.bazel +++ b/common/src/main/java/dev/cel/common/values/BUILD.bazel @@ -114,9 +114,9 @@ java_library( "//common/types:cel_types", "//common/types:type_providers", "//common/values:cel_byte_string", + "@@protobuf~//java/core", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", - "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_protobuf_protobuf_java_util", "@maven//:org_jspecify_jspecify", ], @@ -137,7 +137,7 @@ java_library( "//common/annotations", "//common/internal:dynamic_proto", "//common/internal:proto_message_factory", + "@@protobuf~//java/core", "@maven//:com_google_errorprone_error_prone_annotations", - "@maven//:com_google_protobuf_protobuf_java", ], ) diff --git a/common/src/test/java/dev/cel/common/BUILD.bazel b/common/src/test/java/dev/cel/common/BUILD.bazel index e7ca691ed..f5c08b3b4 100644 --- a/common/src/test/java/dev/cel/common/BUILD.bazel +++ b/common/src/test/java/dev/cel/common/BUILD.bazel @@ -21,11 +21,11 @@ java_library( "//common/types", "//common/types:cel_types", "//common/types:cel_v1alpha1_types", + "@@protobuf~//java/core", "@cel_spec//proto/cel/expr:expr_java_proto", "@com_google_googleapis//google/api/expr/v1alpha1:expr_java_proto", - "@maven//:com_google_api_grpc_proto_google_common_protos", + "@com_google_googleapis//google/rpc/context:attribute_context_java_proto", "@maven//:com_google_guava_guava", - "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_testparameterinjector_test_parameter_injector", "@maven//:com_google_truth_extensions_truth_proto_extension", "@maven//:junit_junit", diff --git a/common/src/test/java/dev/cel/common/ast/BUILD.bazel b/common/src/test/java/dev/cel/common/ast/BUILD.bazel index 61e6beb11..3f1868156 100644 --- a/common/src/test/java/dev/cel/common/ast/BUILD.bazel +++ b/common/src/test/java/dev/cel/common/ast/BUILD.bazel @@ -29,11 +29,11 @@ java_library( "//extensions:optional_library", "//parser:macro", "//parser:operator", + "@@protobuf~//java/core", "@cel_spec//proto/cel/expr:expr_java_proto", "@com_google_googleapis//google/api/expr/v1alpha1:expr_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_guava_guava_testlib", - "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_testparameterinjector_test_parameter_injector", "@maven//:junit_junit", ], diff --git a/common/src/test/java/dev/cel/common/internal/BUILD.bazel b/common/src/test/java/dev/cel/common/internal/BUILD.bazel index af0a673aa..5109b23ac 100644 --- a/common/src/test/java/dev/cel/common/internal/BUILD.bazel +++ b/common/src/test/java/dev/cel/common/internal/BUILD.bazel @@ -34,9 +34,9 @@ java_library( "//common/src/test/resources:service_conflicting_name_java_proto", "//common/src/test/resources:single_file_java_proto", "//common/testing", - "@maven//:com_google_api_grpc_proto_google_common_protos", + "@@protobuf~//java/core", + "@com_google_googleapis//google/type:type_java_proto", "@maven//:com_google_guava_guava", - "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_testparameterinjector_test_parameter_injector", "@maven//:junit_junit", ], diff --git a/common/src/test/java/dev/cel/common/values/BUILD.bazel b/common/src/test/java/dev/cel/common/values/BUILD.bazel index 5b3ac349c..388e4d6fb 100644 --- a/common/src/test/java/dev/cel/common/values/BUILD.bazel +++ b/common/src/test/java/dev/cel/common/values/BUILD.bazel @@ -27,9 +27,9 @@ java_library( "//common/values:cel_value_provider", "//common/values:proto_message_value", "//common/values:proto_message_value_provider", + "@@protobuf~//java/core", "@maven//:com_google_guava_guava", "@maven//:com_google_guava_guava_testlib", - "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_protobuf_protobuf_java_util", "@maven//:com_google_testparameterinjector_test_parameter_injector", "@maven//:junit_junit", diff --git a/compiler/src/main/java/dev/cel/compiler/BUILD.bazel b/compiler/src/main/java/dev/cel/compiler/BUILD.bazel index fc20e8170..1f58aafe9 100644 --- a/compiler/src/main/java/dev/cel/compiler/BUILD.bazel +++ b/compiler/src/main/java/dev/cel/compiler/BUILD.bazel @@ -42,10 +42,10 @@ java_library( "//parser", "//parser:macro", "//parser:parser_builder", + "@@protobuf~//java/core", "@cel_spec//proto/cel/expr:expr_java_proto", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", - "@maven//:com_google_protobuf_protobuf_java", ], ) @@ -64,8 +64,8 @@ java_library( "//common/types:type_providers", "//parser:macro", "//parser:parser_builder", + "@@protobuf~//java/core", "@cel_spec//proto/cel/expr:expr_java_proto", "@maven//:com_google_errorprone_error_prone_annotations", - "@maven//:com_google_protobuf_protobuf_java", ], ) diff --git a/extensions/src/main/java/dev/cel/extensions/BUILD.bazel b/extensions/src/main/java/dev/cel/extensions/BUILD.bazel index 9cf66cf1e..a6e35911d 100644 --- a/extensions/src/main/java/dev/cel/extensions/BUILD.bazel +++ b/extensions/src/main/java/dev/cel/extensions/BUILD.bazel @@ -101,9 +101,9 @@ java_library( "//common/types", "//compiler:compiler_builder", "//runtime", + "@@protobuf~//java/core", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", - "@maven//:com_google_protobuf_protobuf_java", ], ) @@ -124,8 +124,8 @@ java_library( "//parser:operator", "//parser:parser_builder", "//runtime", + "@@protobuf~//java/core", "@maven//:com_google_guava_guava", - "@maven//:com_google_protobuf_protobuf_java", ], ) diff --git a/extensions/src/test/java/dev/cel/extensions/BUILD.bazel b/extensions/src/test/java/dev/cel/extensions/BUILD.bazel index 1edea7cb0..6cfbe3381 100644 --- a/extensions/src/test/java/dev/cel/extensions/BUILD.bazel +++ b/extensions/src/test/java/dev/cel/extensions/BUILD.bazel @@ -28,9 +28,9 @@ java_library( "//parser:macro", "//runtime", "//runtime:interpreter_util", + "@@protobuf~//java/core", "@cel_spec//proto/cel/expr:expr_java_proto", "@maven//:com_google_guava_guava", - "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_protobuf_protobuf_java_util", "@maven//:com_google_testparameterinjector_test_parameter_injector", "@maven//:junit_junit", diff --git a/parser/src/main/java/dev/cel/parser/BUILD.bazel b/parser/src/main/java/dev/cel/parser/BUILD.bazel index f49628e34..e3d13b92b 100644 --- a/parser/src/main/java/dev/cel/parser/BUILD.bazel +++ b/parser/src/main/java/dev/cel/parser/BUILD.bazel @@ -123,6 +123,6 @@ java_library( "//common", "//common/ast", "//common/ast:cel_expr_visitor", - "@maven//:com_google_protobuf_protobuf_java", + "@@protobuf~//java/core", ], ) diff --git a/parser/src/test/java/dev/cel/parser/BUILD.bazel b/parser/src/test/java/dev/cel/parser/BUILD.bazel index 270c412c5..fe29d5d43 100644 --- a/parser/src/test/java/dev/cel/parser/BUILD.bazel +++ b/parser/src/test/java/dev/cel/parser/BUILD.bazel @@ -25,11 +25,11 @@ java_library( "//parser:unparser", "//testing:adorner", "//testing:baseline_test_case", + "@@protobuf~//java/core", "@cel_spec//proto/cel/expr:expr_java_proto", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", "@maven//:com_google_guava_guava_testlib", - "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_testparameterinjector_test_parameter_injector", "@maven//:junit_junit", ], diff --git a/policy/src/test/java/dev/cel/policy/BUILD.bazel b/policy/src/test/java/dev/cel/policy/BUILD.bazel index 8606ca254..4ae85cb55 100644 --- a/policy/src/test/java/dev/cel/policy/BUILD.bazel +++ b/policy/src/test/java/dev/cel/policy/BUILD.bazel @@ -32,7 +32,7 @@ java_library( "//policy:validation_exception", "//policy:value_string", "//runtime", - "@maven//:com_google_api_grpc_proto_google_common_protos", + "@com_google_googleapis//google/rpc/context:attribute_context_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_testparameterinjector_test_parameter_injector", "@maven//:junit_junit", diff --git a/runtime/src/main/java/dev/cel/runtime/BUILD.bazel b/runtime/src/main/java/dev/cel/runtime/BUILD.bazel index f51706987..20031fc22 100644 --- a/runtime/src/main/java/dev/cel/runtime/BUILD.bazel +++ b/runtime/src/main/java/dev/cel/runtime/BUILD.bazel @@ -54,10 +54,10 @@ java_library( "//common/internal:safe_string_formatter", "//common/types", "//common/types:type_providers", + "@@protobuf~//java/core", "@cel_spec//proto/cel/expr:expr_java_proto", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", - "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_protobuf_protobuf_java_util", "@maven//:com_google_re2j_re2j", "@maven//:org_jspecify_jspecify", @@ -90,11 +90,11 @@ java_library( "//common/internal:proto_message_factory", "//common/types:cel_types", "//common/types:type_providers", + "@@protobuf~//java/core", "@cel_spec//proto/cel/expr:expr_java_proto", "@maven//:com_google_code_findbugs_annotations", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", - "@maven//:com_google_protobuf_protobuf_java", "@maven//:org_jspecify_jspecify", ], ) @@ -117,9 +117,9 @@ java_library( "//common/internal:converter", "//common/internal:dynamic_proto", "//common/internal:proto_equality", + "@@protobuf~//java/core", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", - "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_re2j_re2j", "@maven//:org_threeten_threeten_extra", ], @@ -160,10 +160,10 @@ java_library( "//common/values:cel_value_provider", "//common/values:proto_message_value_provider", "//runtime:interpreter", + "@@protobuf~//java/core", "@maven//:com_google_code_findbugs_annotations", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", - "@maven//:com_google_protobuf_protobuf_java", "@maven//:org_jspecify_jspecify", ], ) diff --git a/runtime/src/test/java/dev/cel/runtime/BUILD.bazel b/runtime/src/test/java/dev/cel/runtime/BUILD.bazel index fea8d6e43..dd188ea28 100644 --- a/runtime/src/test/java/dev/cel/runtime/BUILD.bazel +++ b/runtime/src/test/java/dev/cel/runtime/BUILD.bazel @@ -43,10 +43,10 @@ java_library( "//runtime:runtime_helper", "//runtime:unknown_attributes", "//runtime:unknown_options", + "@@protobuf~//java/core", "@com_google_googleapis//google/api/expr/v1alpha1:expr_java_proto", - "@maven//:com_google_api_grpc_proto_google_common_protos", + "@com_google_googleapis//google/rpc/context:attribute_context_java_proto", "@maven//:com_google_guava_guava", - "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_protobuf_protobuf_java_util", "@maven//:com_google_testparameterinjector_test_parameter_injector", "@maven//:com_google_truth_extensions_truth_proto_extension", diff --git a/testing/src/main/java/dev/cel/testing/BUILD.bazel b/testing/src/main/java/dev/cel/testing/BUILD.bazel index 7e4c69fb9..4643e1272 100644 --- a/testing/src/main/java/dev/cel/testing/BUILD.bazel +++ b/testing/src/main/java/dev/cel/testing/BUILD.bazel @@ -75,9 +75,9 @@ java_library( "//compiler", "//compiler:compiler_builder", "//parser:macro", + "@@protobuf~//java/core", "@cel_spec//proto/cel/expr:expr_java_proto", "@maven//:com_google_guava_guava", - "@maven//:com_google_protobuf_protobuf_java", ], ) @@ -97,8 +97,8 @@ java_library( "//common/values:proto_message_value_provider", "//runtime:interpreter", "//runtime:runtime_type_provider_legacy", + "@@protobuf~//java/core", "@maven//:com_google_guava_guava", - "@maven//:com_google_protobuf_protobuf_java", ], ) @@ -113,8 +113,8 @@ java_library( "//common/internal:cel_descriptor_pools", "//common/internal:default_message_factory", "//runtime:interpreter", + "@@protobuf~//java/core", "@maven//:com_google_guava_guava", - "@maven//:com_google_protobuf_protobuf_java", ], ) @@ -129,9 +129,9 @@ java_library( "//common:options", "//runtime:base", "//runtime:interpreter", + "@@protobuf~//java/core", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", - "@maven//:com_google_protobuf_protobuf_java", ], ) @@ -156,10 +156,10 @@ java_library( "//common/resources/testdata/proto3:test_all_types_java_proto", "//common/types:cel_types", "//runtime:interpreter", + "@@protobuf~//java/core", "@cel_spec//proto/cel/expr:expr_java_proto", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", - "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_protobuf_protobuf_java_util", "@maven//:junit_junit", ], diff --git a/testing/src/test/java/dev/cel/testing/BUILD.bazel b/testing/src/test/java/dev/cel/testing/BUILD.bazel index 4d4a12ec4..6e4980c8a 100644 --- a/testing/src/test/java/dev/cel/testing/BUILD.bazel +++ b/testing/src/test/java/dev/cel/testing/BUILD.bazel @@ -21,9 +21,9 @@ java_library( "//runtime:interpreter", "//testing:line_differ", "//testing:sync", - "@maven//:com_google_api_grpc_proto_google_common_protos", + "@@protobuf~//java/core", + "@com_google_googleapis//google/type:type_java_proto", "@maven//:com_google_guava_guava", - "@maven//:com_google_protobuf_protobuf_java", "@maven//:junit_junit", ], ) diff --git a/validator/src/main/java/dev/cel/validator/validators/BUILD.bazel b/validator/src/main/java/dev/cel/validator/validators/BUILD.bazel index e9c07fb10..d049a3659 100644 --- a/validator/src/main/java/dev/cel/validator/validators/BUILD.bazel +++ b/validator/src/main/java/dev/cel/validator/validators/BUILD.bazel @@ -15,7 +15,7 @@ java_library( ], deps = [ ":literal_validator", - "@maven//:com_google_protobuf_protobuf_java", + "@@protobuf~//java/core", ], ) @@ -28,7 +28,7 @@ java_library( ], deps = [ ":literal_validator", - "@maven//:com_google_protobuf_protobuf_java", + "@@protobuf~//java/core", ], ) diff --git a/validator/src/test/java/dev/cel/validator/validators/BUILD.bazel b/validator/src/test/java/dev/cel/validator/validators/BUILD.bazel index eca252aa9..1f8af4661 100644 --- a/validator/src/test/java/dev/cel/validator/validators/BUILD.bazel +++ b/validator/src/test/java/dev/cel/validator/validators/BUILD.bazel @@ -21,8 +21,8 @@ java_library( "//validator/validators:homogeneous_literal", "//validator/validators:regex", "//validator/validators:timestamp", + "@@protobuf~//java/core", "@maven//:com_google_guava_guava", - "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_protobuf_protobuf_java_util", "@maven//:com_google_testparameterinjector_test_parameter_injector", "@maven//:junit_junit", From 8fe0b7f7fec09eae59202c809fff749992a06a6f Mon Sep 17 00:00:00 2001 From: CEL Dev Team Date: Thu, 8 Aug 2024 09:54:23 -0700 Subject: [PATCH 168/486] No public description PiperOrigin-RevId: 660876414 --- .../dev/cel/common/navigation/ExprPropertyCalculator.java | 4 ++-- policy/src/main/java/dev/cel/policy/CelPolicyConfig.java | 6 +++--- policy/src/main/java/dev/cel/policy/RuleComposer.java | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/common/src/main/java/dev/cel/common/navigation/ExprPropertyCalculator.java b/common/src/main/java/dev/cel/common/navigation/ExprPropertyCalculator.java index c90c1f2f9..be2c07221 100644 --- a/common/src/main/java/dev/cel/common/navigation/ExprPropertyCalculator.java +++ b/common/src/main/java/dev/cel/common/navigation/ExprPropertyCalculator.java @@ -140,9 +140,9 @@ private ExprProperty visitExprList(java.util.List list) { /** Value class to store the height and the max ID at a specific expression ID. */ @AutoValue abstract static class ExprProperty { - abstract Integer height(); + abstract int height(); - abstract Long maxId(); + abstract long maxId(); /** Merges the two {@link ExprProperty}, taking their maximum values from the properties. */ private static ExprProperty merge(ExprProperty e1, ExprProperty e2) { diff --git a/policy/src/main/java/dev/cel/policy/CelPolicyConfig.java b/policy/src/main/java/dev/cel/policy/CelPolicyConfig.java index d3786d512..cf6ca3ec3 100644 --- a/policy/src/main/java/dev/cel/policy/CelPolicyConfig.java +++ b/policy/src/main/java/dev/cel/policy/CelPolicyConfig.java @@ -369,7 +369,7 @@ public abstract static class TypeDecl { public abstract ImmutableList params(); - public abstract Boolean isTypeParam(); + public abstract boolean isTypeParam(); /** Builder for {@link TypeDecl}. */ @AutoValue.Builder @@ -474,7 +474,7 @@ public abstract static class ExtensionConfig { * Version of the extension. Presently, this field is ignored as CEL-Java extensions are not * versioned. */ - public abstract Integer version(); + public abstract int version(); /** Builder for {@link ExtensionConfig}. */ @AutoValue.Builder @@ -486,7 +486,7 @@ public abstract static class Builder implements RequiredFieldsChecker { public abstract Builder setName(String name); - public abstract Builder setVersion(Integer version); + public abstract Builder setVersion(int version); @Override public ImmutableList requiredFields() { diff --git a/policy/src/main/java/dev/cel/policy/RuleComposer.java b/policy/src/main/java/dev/cel/policy/RuleComposer.java index c3b888887..42b1b7af2 100644 --- a/policy/src/main/java/dev/cel/policy/RuleComposer.java +++ b/policy/src/main/java/dev/cel/policy/RuleComposer.java @@ -52,7 +52,7 @@ public OptimizationResult optimize(CelAbstractSyntaxTree ast, Cel cel) { abstract static class RuleOptimizationResult { abstract CelMutableAst ast(); - abstract Boolean isOptionalResult(); + abstract boolean isOptionalResult(); static RuleOptimizationResult create(CelMutableAst ast, boolean isOptionalResult) { return new AutoValue_RuleComposer_RuleOptimizationResult(ast, isOptionalResult); From 06dec78bf83e13e3cb0c7e659b323909e137c56a Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Fri, 9 Aug 2024 10:27:25 -0700 Subject: [PATCH 169/486] Provide an overload to hide all fields on a message with ProtoTypeMask PiperOrigin-RevId: 661315262 --- .../test/java/dev/cel/bundle/CelImplTest.java | 47 +++++++++++++++++++ .../java/dev/cel/checker/ProtoTypeMask.java | 22 +++++++++ .../checker/ProtoTypeMaskTypeProvider.java | 9 +++- .../dev/cel/checker/ProtoTypeMaskTest.java | 8 ++++ .../ProtoTypeMaskTypeProviderTest.java | 40 +++++++++++++++- 5 files changed, 122 insertions(+), 4 deletions(-) diff --git a/bundle/src/test/java/dev/cel/bundle/CelImplTest.java b/bundle/src/test/java/dev/cel/bundle/CelImplTest.java index ef751df18..ecbac380e 100644 --- a/bundle/src/test/java/dev/cel/bundle/CelImplTest.java +++ b/bundle/src/test/java/dev/cel/bundle/CelImplTest.java @@ -579,6 +579,53 @@ public void program_withProtoVars() throws Exception { .isEqualTo(true); } + @Test + public void program_withAllFieldsHidden_emptyMessageConstructionSuccess() throws Exception { + Cel cel = + standardCelBuilderWithMacros() + .addMessageTypes(AttributeContext.getDescriptor()) + .setContainer("google.rpc.context.AttributeContext") + .addProtoTypeMasks( + ProtoTypeMask.ofAllFieldsHidden("google.rpc.context.AttributeContext")) + .build(); + + assertThat(cel.createProgram(cel.compile("AttributeContext{}").getAst()).eval()) + .isEqualTo(AttributeContext.getDefaultInstance()); + } + + @Test + public void compile_withAllFieldsHidden_selectHiddenField_throws() throws Exception { + Cel cel = + standardCelBuilderWithMacros() + .addMessageTypes(AttributeContext.getDescriptor()) + .setContainer("google.rpc.context.AttributeContext") + .addProtoTypeMasks( + ProtoTypeMask.ofAllFieldsHidden("google.rpc.context.AttributeContext")) + .build(); + + CelValidationException e = + assertThrows( + CelValidationException.class, + () -> cel.compile("AttributeContext{ request: AttributeContext.Request{} }").getAst()); + assertThat(e).hasMessageThat().contains("undefined field 'request'"); + } + + @Test + public void compile_withAllFieldsHidden_selectHiddenFieldOnVar_throws() throws Exception { + Cel cel = + standardCelBuilderWithMacros() + .addMessageTypes(AttributeContext.getDescriptor()) + .setContainer("google.rpc.context.AttributeContext") + .addProtoTypeMasks( + ProtoTypeMask.ofAllFieldsHidden("google.rpc.context.AttributeContext")) + .addVar("attr_ctx", StructTypeReference.create("google.rpc.context.AttributeContext")) + .build(); + + CelValidationException e = + assertThrows(CelValidationException.class, () -> cel.compile("attr_ctx.source").getAst()); + assertThat(e).hasMessageThat().contains("undefined field 'source'"); + } + @Test public void program_withNestedRestrictedProtoVars() throws Exception { Cel cel = diff --git a/checker/src/main/java/dev/cel/checker/ProtoTypeMask.java b/checker/src/main/java/dev/cel/checker/ProtoTypeMask.java index 1a129a91f..c019604d5 100644 --- a/checker/src/main/java/dev/cel/checker/ProtoTypeMask.java +++ b/checker/src/main/java/dev/cel/checker/ProtoTypeMask.java @@ -38,6 +38,13 @@ public abstract class ProtoTypeMask { /** WILDCARD_FIELD indicates that all fields within the proto type are visible. */ static final String WILDCARD_FIELD = "*"; + /** HIDDEN_FIELD indicates that all fields within the proto type are not visible. */ + static final String HIDDEN_FIELD = "!"; + + private static final FieldMask HIDDEN_FIELD_MASK = + FieldMask.newBuilder().addPaths(HIDDEN_FIELD).build(); + + private static final FieldPath HIDDEN_FIELD_PATH = FieldPath.of(HIDDEN_FIELD); private static final FieldMask WILDCARD_FIELD_MASK = FieldMask.newBuilder().addPaths(WILDCARD_FIELD).build(); private static final FieldPath WILDCARD_FIELD_PATH = FieldPath.of(WILDCARD_FIELD); @@ -52,6 +59,10 @@ boolean areAllFieldPathsExposed() { return getFieldPathsExposed().stream().allMatch(fp -> fp.equals(WILDCARD_FIELD_PATH)); } + boolean areAllFieldPathsHidden() { + return getFieldPathsExposed().stream().allMatch(fp -> fp.equals(HIDDEN_FIELD_PATH)); + } + public ProtoTypeMask withFieldsAsVariableDeclarations() { return new AutoValue_ProtoTypeMask(getTypeName(), getFieldPathsExposed(), true); } @@ -98,6 +109,17 @@ public static ProtoTypeMask ofAllFields(String fullyQualifiedTypeName) { return of(fullyQualifiedTypeName, WILDCARD_FIELD_MASK); } + /** + * Construct a new {@code ProtoTypeMask} which hides all fields in the given {@code typeName} for + * use within CEL expressions. + * + *

The {@code typeName} should be a fully-qualified path, e.g., {@code + * "google.rpc.context.AttributeContext"}. + */ + public static ProtoTypeMask ofAllFieldsHidden(String fullyQualifiedTypeName) { + return of(fullyQualifiedTypeName, HIDDEN_FIELD_MASK); + } + /** * FieldPath is the equivalent of a field selection represented within a {@link FieldMask#path}. */ diff --git a/checker/src/main/java/dev/cel/checker/ProtoTypeMaskTypeProvider.java b/checker/src/main/java/dev/cel/checker/ProtoTypeMaskTypeProvider.java index 61511c38d..025dfaf1a 100644 --- a/checker/src/main/java/dev/cel/checker/ProtoTypeMaskTypeProvider.java +++ b/checker/src/main/java/dev/cel/checker/ProtoTypeMaskTypeProvider.java @@ -92,11 +92,16 @@ private static ImmutableMap computeVisibleFieldsMap( CelTypeProvider delegateProvider, ImmutableSet protoTypeMasks) { Map> fieldMap = new HashMap<>(); for (ProtoTypeMask typeMask : protoTypeMasks) { - Optional rootType = delegateProvider.findType(typeMask.getTypeName()); - checkArgument(rootType.isPresent(), "message not registered: %s", typeMask.getTypeName()); + String typeName = typeMask.getTypeName(); + Optional rootType = delegateProvider.findType(typeName); + checkArgument(rootType.isPresent(), "message not registered: %s", typeName); if (typeMask.areAllFieldPathsExposed()) { continue; } + if (typeMask.areAllFieldPathsHidden()) { + fieldMap.put(typeName, ImmutableSet.of()); + continue; + } // Unroll the type(messageType) to just messageType. CelType type = rootType.get(); checkArgument(type instanceof ProtoMessageType, "type is not a protobuf: %s", type.name()); diff --git a/checker/src/test/java/dev/cel/checker/ProtoTypeMaskTest.java b/checker/src/test/java/dev/cel/checker/ProtoTypeMaskTest.java index f937dbdc2..89241652c 100644 --- a/checker/src/test/java/dev/cel/checker/ProtoTypeMaskTest.java +++ b/checker/src/test/java/dev/cel/checker/ProtoTypeMaskTest.java @@ -85,6 +85,14 @@ public void ofTypeWithFieldMask_invalidMask() { () -> ProtoTypeMask.of("test", FieldMask.newBuilder().addPaths("").build())); } + @Test + public void ofAllFieldsHidden() { + ProtoTypeMask typeExpr = ProtoTypeMask.ofAllFieldsHidden("google.rpc.context.AttributeContext"); + assertThat(typeExpr.areAllFieldPathsExposed()).isFalse(); + assertThat(typeExpr.getFieldPathsExposed()) + .containsExactly(FieldPath.of(ProtoTypeMask.HIDDEN_FIELD)); + } + @Test public void withFieldsAsVariableDeclarations() { assertThat(ProtoTypeMask.ofAllFields("google.type.Expr").fieldsAreVariableDeclarations()) diff --git a/checker/src/test/java/dev/cel/checker/ProtoTypeMaskTypeProviderTest.java b/checker/src/test/java/dev/cel/checker/ProtoTypeMaskTypeProviderTest.java index bf41c1e20..b4b52bd26 100644 --- a/checker/src/test/java/dev/cel/checker/ProtoTypeMaskTypeProviderTest.java +++ b/checker/src/test/java/dev/cel/checker/ProtoTypeMaskTypeProviderTest.java @@ -28,6 +28,7 @@ import dev.cel.common.types.ProtoMessageType; import dev.cel.common.types.ProtoMessageTypeProvider; import dev.cel.common.types.SimpleType; +import dev.cel.common.types.StructType.Field; import java.util.Arrays; import java.util.Optional; import org.junit.Test; @@ -72,7 +73,7 @@ public void lookupFieldNames_noProtoDecls() { ProtoTypeMaskTypeProvider protoTypeMaskProvider = new ProtoTypeMaskTypeProvider(celTypeProvider, ImmutableSet.of()); ProtoMessageType protoType = assertTypeFound(protoTypeMaskProvider, ATTRIBUTE_CONTEXT_TYPE); - assertThat(protoType.fields().stream().map(f -> f.name()).collect(toImmutableList())) + assertThat(protoType.fields().stream().map(Field::name).collect(toImmutableList())) .containsExactly( "resource", "request", @@ -87,6 +88,41 @@ public void lookupFieldNames_noProtoDecls() { assertThat(protoType).isSameInstanceAs(origProtoType); } + @Test + public void lookupFieldNames_allFieldsHidden() { + CelTypeProvider celTypeProvider = + new ProtoMessageTypeProvider(ImmutableSet.of(AttributeContext.getDescriptor())); + ProtoTypeMaskTypeProvider protoTypeMaskProvider = + new ProtoTypeMaskTypeProvider( + celTypeProvider, + ImmutableSet.of(ProtoTypeMask.ofAllFieldsHidden(ATTRIBUTE_CONTEXT_TYPE))); + + ProtoMessageType protoType = assertTypeFound(protoTypeMaskProvider, ATTRIBUTE_CONTEXT_TYPE); + assertThat(protoType.fieldNames()).isEmpty(); + ProtoMessageType origProtoType = assertTypeFound(celTypeProvider, ATTRIBUTE_CONTEXT_TYPE); + assertThat(protoType).isNotSameInstanceAs(origProtoType); + } + + @Test + public void protoTypeMaskProvider_hiddenFieldSentinelCharOnSubPath_throws() { + CelTypeProvider celTypeProvider = + new ProtoMessageTypeProvider(ImmutableSet.of(AttributeContext.getDescriptor())); + + IllegalArgumentException e = + assertThrows( + IllegalArgumentException.class, + () -> + new ProtoTypeMaskTypeProvider( + celTypeProvider, + ImmutableSet.of( + ProtoTypeMask.of( + "google.rpc.context.AttributeContext", + FieldMask.newBuilder().addPaths("resource.!").build())))); + assertThat(e) + .hasMessageThat() + .contains("message google.rpc.context.AttributeContext.Resource does not declare field: !"); + } + @Test public void lookupFieldNames_fullProtoDecl() { CelTypeProvider celTypeProvider = @@ -263,7 +299,7 @@ private ProtoMessageType assertTypeFound(CelTypeProvider celTypeProvider, String private void assertTypeHasFields(ProtoMessageType protoType, ImmutableSet fields) { ImmutableSet typeFieldNames = - protoType.fields().stream().map(f -> f.name()).collect(toImmutableSet()); + protoType.fields().stream().map(Field::name).collect(toImmutableSet()); assertThat(typeFieldNames).containsExactlyElementsIn(fields); } From 8073b79e02c21a6f934818017054c29ae22d6240 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Mon, 12 Aug 2024 09:56:10 -0700 Subject: [PATCH 170/486] Open source Java conformance tests PiperOrigin-RevId: 662127834 --- .github/workflows/workflow.yml | 4 +- WORKSPACE | 6 +- .../dev/cel/checker/CelProtoExprVisitor.java | 2 +- .../common/CelProtoAbstractSyntaxTree.java | 12 +- .../dev/cel/common/internal/Constants.java | 2 +- .../DefaultInstanceMessageFactory.java | 4 +- .../test/java/dev/cel/conformance/BUILD.bazel | 152 +++++++ .../dev/cel/conformance/ConformanceTest.java | 408 ++++++++++++++++++ .../conformance/ConformanceTestRunner.java | 128 ++++++ .../dev/cel/conformance/ConformanceTests.java | 20 + .../dev/cel/conformance/conformance_test.bzl | 80 ++++ .../dev/cel/conformance/conformance_test.sh | 8 + .../main/java/dev/cel/testing/CelDebug.java | 4 +- 13 files changed, 814 insertions(+), 16 deletions(-) create mode 100644 conformance/src/test/java/dev/cel/conformance/BUILD.bazel create mode 100644 conformance/src/test/java/dev/cel/conformance/ConformanceTest.java create mode 100644 conformance/src/test/java/dev/cel/conformance/ConformanceTestRunner.java create mode 100644 conformance/src/test/java/dev/cel/conformance/ConformanceTests.java create mode 100644 conformance/src/test/java/dev/cel/conformance/conformance_test.bzl create mode 100755 conformance/src/test/java/dev/cel/conformance/conformance_test.sh diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index 16ebd2a5f..4cf231b27 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -32,5 +32,7 @@ jobs: - name: Bazel Output Version run: bazelisk --version - name: Bazel Test - run: bazelisk test ... --deleted_packages=codelab/src/test/codelab --test_output=errors # Exclude codelab exercises as they are intentionally made to fail + # Exclude codelab exercises as they are intentionally made to fail + # Exclude conformance tests for time being until TextFormat.Parser fix is in upstream + run: bazelisk test ... --deleted_packages=//codelab/src/test/codelab,//conformance/src/test/java/dev/cel/conformance --test_output=errors - run: echo "🍏 This job's status is ${{ job.status }}." diff --git a/WORKSPACE b/WORKSPACE index 798ad38c8..04efe6010 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -149,10 +149,10 @@ http_archive( # cel-spec api/expr canonical protos http_archive( name = "cel_spec", - sha256 = "3ee09eb69dbe77722e9dee23dc48dc2cd9f765869fcf5ffb1226587c81791a0b", - strip_prefix = "cel-spec-0.15.0", + sha256 = "65a153c1c4d73a135c364a4955e6aabd1093f0ed291774d3637f350504505085", + strip_prefix = "cel-spec-0789389e13a0626ec3521e4f109acce360565ce6", urls = [ - "https://github.com/google/cel-spec/archive/refs/tags/v0.15.0.tar.gz", + "https://github.com/google/cel-spec/archive/0789389e13a0626ec3521e4f109acce360565ce6.tar.gz", ], ) diff --git a/checker/src/main/java/dev/cel/checker/CelProtoExprVisitor.java b/checker/src/main/java/dev/cel/checker/CelProtoExprVisitor.java index cd5656642..08552d56f 100644 --- a/checker/src/main/java/dev/cel/checker/CelProtoExprVisitor.java +++ b/checker/src/main/java/dev/cel/checker/CelProtoExprVisitor.java @@ -18,7 +18,7 @@ import dev.cel.common.CelProtoAbstractSyntaxTree; /** - * CEL expression visitor implementation based on the {@link com.google.api.expr.Expr} proto. + * CEL expression visitor implementation based on the {@link dev.cel.expr.Expr} proto. * *

Note: Prefer using {@link dev.cel.common.ast.CelExprVisitor} if protobuf support is not * needed. diff --git a/common/src/main/java/dev/cel/common/CelProtoAbstractSyntaxTree.java b/common/src/main/java/dev/cel/common/CelProtoAbstractSyntaxTree.java index ef69c174b..f8374e114 100644 --- a/common/src/main/java/dev/cel/common/CelProtoAbstractSyntaxTree.java +++ b/common/src/main/java/dev/cel/common/CelProtoAbstractSyntaxTree.java @@ -104,12 +104,12 @@ private CelProtoAbstractSyntaxTree(CelAbstractSyntaxTree ast) { this.checkedExpr = checkedExprBuilder.build(); } - /** Construct an abstract syntax tree from a {@link com.google.api.expr.CheckedExpr}. */ + /** Construct an abstract syntax tree from a {@link dev.cel.expr.CheckedExpr}. */ public static CelProtoAbstractSyntaxTree fromCheckedExpr(CheckedExpr checkedExpr) { return new CelProtoAbstractSyntaxTree(checkedExpr); } - /** Construct an abstract syntax tree from a {@link com.google.api.expr.ParsedExpr}. */ + /** Construct an abstract syntax tree from a {@link dev.cel.expr.ParsedExpr}. */ public static CelProtoAbstractSyntaxTree fromParsedExpr(ParsedExpr parsedExpr) { return new CelProtoAbstractSyntaxTree( CheckedExpr.newBuilder() @@ -137,7 +137,7 @@ public CelAbstractSyntaxTree getAst() { } /** - * Returns the underlying {@link com.google.api.expr.Expr} representation of the abstract syntax + * Returns the underlying {@link dev.cel.expr.Expr} representation of the abstract syntax * tree. */ @CheckReturnValue @@ -146,7 +146,7 @@ public Expr getExpr() { } /** - * Returns the underlying {@link com.google.api.expr.CheckedExpr} representation of the abstract + * Returns the underlying {@link dev.cel.expr.CheckedExpr} representation of the abstract * syntax tree. Throws {@link java.lang.IllegalStateException} if {@link * CelAbstractSyntaxTree#isChecked} is false. */ @@ -159,7 +159,7 @@ public CheckedExpr toCheckedExpr() { } /** - * Returns the underlying {@link com.google.api.expr.SourceInfo} representation of the abstract + * Returns the underlying {@link dev.cel.expr.SourceInfo} representation of the abstract * syntax tree. */ @CheckReturnValue @@ -168,7 +168,7 @@ public SourceInfo getSourceInfo() { } /** - * Returns the underlying {@link com.google.api.expr.ParsedExpr} representation of the abstract + * Returns the underlying {@link dev.cel.expr.ParsedExpr} representation of the abstract * syntax tree. */ @CheckReturnValue diff --git a/common/src/main/java/dev/cel/common/internal/Constants.java b/common/src/main/java/dev/cel/common/internal/Constants.java index 0367d879a..528099840 100644 --- a/common/src/main/java/dev/cel/common/internal/Constants.java +++ b/common/src/main/java/dev/cel/common/internal/Constants.java @@ -26,7 +26,7 @@ import java.util.PrimitiveIterator; /** - * Internal utility class for working with {@link com.google.api.expr.Constant}. + * Internal utility class for working with {@link dev.cel.expr.Constant}. * *

CEL Library Internals. Do Not Use. */ diff --git a/common/src/main/java/dev/cel/common/internal/DefaultInstanceMessageFactory.java b/common/src/main/java/dev/cel/common/internal/DefaultInstanceMessageFactory.java index 6466ee9c9..1147da7ad 100644 --- a/common/src/main/java/dev/cel/common/internal/DefaultInstanceMessageFactory.java +++ b/common/src/main/java/dev/cel/common/internal/DefaultInstanceMessageFactory.java @@ -38,7 +38,7 @@ *

CEL Library Internals. Do Not Use. */ @Internal -final class DefaultInstanceMessageFactory { +public final class DefaultInstanceMessageFactory { // Controls how many times we should recursively inspect a nested message for building fully // qualified java class name before aborting. @@ -87,7 +87,7 @@ public Optional getPrototype(Descriptor descriptor) { * Retrieves the full Java class name from the given descriptor * * @return fully qualified class name. - *

Example 1: com.google.api.expr.Value + *

Example 1: dev.cel.expr.Value *

Example 2: com.google.rpc.context.AttributeContext$Resource (Nested classes) *

Example 3: com.google.api.expr.cel.internal.testdata$SingleFileProto$SingleFile$Path * (Nested class with java multiple files disabled) diff --git a/conformance/src/test/java/dev/cel/conformance/BUILD.bazel b/conformance/src/test/java/dev/cel/conformance/BUILD.bazel new file mode 100644 index 000000000..5f1380277 --- /dev/null +++ b/conformance/src/test/java/dev/cel/conformance/BUILD.bazel @@ -0,0 +1,152 @@ +load("//conformance/src/test/java/dev/cel/conformance:conformance_test.bzl", "conformance_test") + +package(default_applicable_licenses = [ + "//:license", +]) + +exports_files([ + "conformance_test.bzl", + "conformance_test.sh", +]) + +java_library( + name = "run", + testonly = True, + srcs = glob(["*.java"]), + deps = [ + "//:java_truth", + "//checker:checker_builder", + "//common", + "//common:compiler_common", + "//common:options", + "//common/internal:default_instance_message_factory", + "//common/types", + "//common/types:type_providers", + "//compiler", + "//extensions", + "//extensions:optional_library", + "//parser", + "//parser:macro", + "//parser:parser_builder", + "//runtime", + "@@protobuf~//java/core", + "@cel_spec//proto/cel/expr:expr_java_proto", + "@cel_spec//proto/test/v1:simple_java_proto", + "@cel_spec//proto/test/v1/proto2:test_all_types_java_proto", + "@cel_spec//proto/test/v1/proto3:test_all_types_java_proto", + "@com_google_googleapis//google/api/expr/v1alpha1:expr_java_proto", + "@maven//:com_google_guava_guava", + "@maven//:com_google_truth_extensions_truth_proto_extension", + "@maven//:junit_junit", + ], +) + +_ALL_TESTS = [ + "@cel_spec//tests/simple:testdata/basic.textproto", + "@cel_spec//tests/simple:testdata/bindings_ext.textproto", + "@cel_spec//tests/simple:testdata/comparisons.textproto", + "@cel_spec//tests/simple:testdata/conversions.textproto", + "@cel_spec//tests/simple:testdata/dynamic.textproto", + "@cel_spec//tests/simple:testdata/encoders_ext.textproto", + "@cel_spec//tests/simple:testdata/enums.textproto", + "@cel_spec//tests/simple:testdata/fields.textproto", + "@cel_spec//tests/simple:testdata/fp_math.textproto", + "@cel_spec//tests/simple:testdata/integer_math.textproto", + "@cel_spec//tests/simple:testdata/lists.textproto", + "@cel_spec//tests/simple:testdata/logic.textproto", + "@cel_spec//tests/simple:testdata/macros.textproto", + "@cel_spec//tests/simple:testdata/math_ext.textproto", + "@cel_spec//tests/simple:testdata/namespace.textproto", + "@cel_spec//tests/simple:testdata/optionals.textproto", + "@cel_spec//tests/simple:testdata/parse.textproto", + "@cel_spec//tests/simple:testdata/plumbing.textproto", + "@cel_spec//tests/simple:testdata/proto2.textproto", + "@cel_spec//tests/simple:testdata/proto3.textproto", + "@cel_spec//tests/simple:testdata/proto2_ext.textproto", + "@cel_spec//tests/simple:testdata/string.textproto", + "@cel_spec//tests/simple:testdata/string_ext.textproto", + "@cel_spec//tests/simple:testdata/timestamps.textproto", + "@cel_spec//tests/simple:testdata/unknowns.textproto", + "@cel_spec//tests/simple:testdata/wrappers.textproto", +] + +_TESTS_TO_SKIP = [ + # Tests which require spec changes. + # TODO: Deprecate Duration.get_milliseconds + "timestamps/duration_converters/get_milliseconds", + + # Broken test cases which should be supported. + # TODO: Invalid bytes to string conversion should error. + "conversions/string/bytes_invalid", + # TODO: Support setting / getting enum values out of the defined enum value range. + "enums/legacy_proto2/select_big,select_neg", + "enums/legacy_proto2/assign_standalone_int_big,assign_standalone_int_neg", + # TODO: Generate errors on enum value assignment overflows for proto3. + "enums/legacy_proto3/assign_standalone_int_too_big,assign_standalone_int_too_neg", + # TODO: Ensure overflow occurs on conversions of double values which might not work properly on all platforms. + "conversions/int/double_int_min_range", + # TODO: Duration and timestamp operations should error on overflow. + "timestamps/duration_range/from_string_under,from_string_over", + "timestamps/timestamp_range/sub_time_duration_over,sub_time_duration_under", + # TODO: Ensure adding negative duration values is appropriately supported. + "timestamps/timestamp_arithmetic/add_time_to_duration_nanos_negative", + + # Skip until fixed. + "wrappers/field_mask/to_json", + "wrappers/empty/to_json", + "wrappers/duration/to_json", + "wrappers/timestamp/to_json", + "fields/qualified_identifier_resolution/map_value_repeat_key_heterogeneous", + # TODO: Add strings.quote. + "string_ext/quote", + + # TODO: Fix null assignment to a field + "proto2/set_null/single_message", + "proto2/set_null/single_duration", + "proto2/set_null/single_timestamp", + "proto3/set_null/single_message", + "proto3/set_null/single_duration", + "proto3/set_null/single_timestamp", + + # Future features for CEL 1.0 + # TODO: Strong typing support for enums, specified but not implemented. + "enums/strong_proto2", + "enums/strong_proto3", + + # com.google.protobuf.TextFormat does not conform to the spec. Unknown enum values are supposed + # to be allowed in proto3. Currently they are rejected. + # "enums/legacy_proto3/select_big", + # "enums/legacy_proto3/select_neg", + # "enums/legacy_proto3/assign_standalone_int_big", + # "enums/legacy_proto3/assign_standalone_int_neg", + + # Not yet implemented. + "math_ext/ceil", + "math_ext/floor", + "math_ext/round", + "math_ext/trunc", + "math_ext/abs", + "math_ext/sign", + "math_ext/isNaN", + "math_ext/isInf", + "math_ext/isFinite", + "math_ext/bit_and", + "math_ext/bit_or", + "math_ext/bit_xor", + "math_ext/bit_not", + "math_ext/bit_shift_left", + "math_ext/bit_shift_right", +] + +conformance_test( + name = "conformance", + dashboard = False, + data = _ALL_TESTS, + skip_tests = _TESTS_TO_SKIP, +) + +conformance_test( + name = "conformance_dashboard", + dashboard = True, + data = _ALL_TESTS, +) diff --git a/conformance/src/test/java/dev/cel/conformance/ConformanceTest.java b/conformance/src/test/java/dev/cel/conformance/ConformanceTest.java new file mode 100644 index 000000000..32c10bf4d --- /dev/null +++ b/conformance/src/test/java/dev/cel/conformance/ConformanceTest.java @@ -0,0 +1,408 @@ +// Copyright 2024 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.conformance; + +import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; + +import dev.cel.expr.Decl; +import com.google.api.expr.test.v1.SimpleProto.SimpleTest; +import com.google.api.expr.test.v1.proto2.TestAllTypesExtensions; +import com.google.api.expr.v1alpha1.ExprValue; +import com.google.api.expr.v1alpha1.ListValue; +import com.google.api.expr.v1alpha1.MapValue; +import com.google.api.expr.v1alpha1.Value; +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.primitives.UnsignedLong; +import com.google.protobuf.Any; +import com.google.protobuf.ByteString; +import com.google.protobuf.Descriptors.Descriptor; +import com.google.protobuf.ExtensionRegistry; +import com.google.protobuf.Message; +import com.google.protobuf.NullValue; +import com.google.protobuf.TypeRegistry; +import dev.cel.checker.CelChecker; +import dev.cel.common.CelDescriptorUtil; +import dev.cel.common.CelDescriptors; +import dev.cel.common.CelOptions; +import dev.cel.common.CelValidationResult; +import dev.cel.common.internal.DefaultInstanceMessageFactory; +import dev.cel.common.types.CelType; +import dev.cel.common.types.ListType; +import dev.cel.common.types.MapType; +import dev.cel.common.types.SimpleType; +import dev.cel.compiler.CelCompilerFactory; +import dev.cel.extensions.CelExtensions; +import dev.cel.extensions.CelOptionalLibrary; +import dev.cel.parser.CelParser; +import dev.cel.parser.CelParserFactory; +import dev.cel.parser.CelStandardMacro; +import dev.cel.runtime.CelEvaluationException; +import dev.cel.runtime.CelRuntime; +import dev.cel.runtime.CelRuntime.Program; +import dev.cel.runtime.CelRuntimeFactory; +import java.util.List; +import java.util.Map; +import java.util.NoSuchElementException; +import org.junit.runners.model.Statement; + +// Qualifying proto2/proto3 TestAllTypes makes it less clear. +@SuppressWarnings("UnnecessarilyFullyQualified") +public final class ConformanceTest extends Statement { + + static final TypeRegistry DEFAULT_TYPE_REGISTRY = newDefaultTypeRegistry(); + static final ExtensionRegistry DEFAULT_EXTENSION_REGISTRY = newDefaultExtensionRegistry(); + + private static ExtensionRegistry newDefaultExtensionRegistry() { + ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance(); + com.google.api.expr.test.v1.proto2.TestAllTypesExtensions.registerAllExtensions( + extensionRegistry); + + return extensionRegistry; + } + + private static TypeRegistry newDefaultTypeRegistry() { + CelDescriptors allDescriptors = + CelDescriptorUtil.getAllDescriptorsFromFileDescriptor( + ImmutableList.of( + com.google.api.expr.test.v1.proto2.TestAllTypesProto.TestAllTypes.getDescriptor() + .getFile(), + com.google.api.expr.test.v1.proto3.TestAllTypesProto.TestAllTypes.getDescriptor() + .getFile(), + com.google.api.expr.test.v1.proto2.TestAllTypesExtensions.getDescriptor() + .getFile())); + + return TypeRegistry.newBuilder().add(allDescriptors.messageTypeDescriptors()).build(); + } + + private static final CelOptions OPTIONS = + CelOptions.current() + .enableTimestampEpoch(true) + .enableUnsignedLongs(true) + .enableHeterogeneousNumericComparisons(true) + .enableProtoDifferencerEquality(true) + .enableOptionalSyntax(true) + .build(); + + private static final CelParser PARSER_WITH_MACROS = + CelParserFactory.standardCelParserBuilder() + .setOptions(OPTIONS) + .addLibraries( + CelExtensions.bindings(), + CelExtensions.encoders(), + CelExtensions.math(OPTIONS), + CelExtensions.protos(), + CelExtensions.sets(), + CelExtensions.strings(), + CelOptionalLibrary.INSTANCE) + .setStandardMacros(CelStandardMacro.STANDARD_MACROS) + .build(); + + private static final CelParser PARSER_WITHOUT_MACROS = + CelParserFactory.standardCelParserBuilder() + .setOptions(OPTIONS) + .addLibraries( + CelExtensions.bindings(), + CelExtensions.encoders(), + CelExtensions.math(OPTIONS), + CelExtensions.protos(), + CelExtensions.sets(), + CelExtensions.strings(), + CelOptionalLibrary.INSTANCE) + .setStandardMacros() + .build(); + + private static CelParser getParser(SimpleTest test) { + return test.getDisableMacros() ? PARSER_WITHOUT_MACROS : PARSER_WITH_MACROS; + } + + private static CelChecker getChecker(SimpleTest test) throws Exception { + ImmutableList.Builder decls = + ImmutableList.builderWithExpectedSize(test.getTypeEnvCount()); + for (com.google.api.expr.v1alpha1.Decl decl : test.getTypeEnvList()) { + decls.add(Decl.parseFrom(decl.toByteArray(), DEFAULT_EXTENSION_REGISTRY)); + } + return CelCompilerFactory.standardCelCheckerBuilder() + .setOptions(OPTIONS) + .setContainer(test.getContainer()) + .addDeclarations(decls.build()) + .addFileTypes(TestAllTypesExtensions.getDescriptor()) + .addLibraries( + CelExtensions.bindings(), + CelExtensions.encoders(), + CelExtensions.math(OPTIONS), + CelExtensions.sets(), + CelExtensions.strings(), + CelOptionalLibrary.INSTANCE) + .addMessageTypes( + com.google.api.expr.test.v1.proto2.TestAllTypesProto.TestAllTypes.getDescriptor()) + .addMessageTypes( + com.google.api.expr.test.v1.proto3.TestAllTypesProto.TestAllTypes.getDescriptor()) + .build(); + } + + private static final CelRuntime RUNTIME = + CelRuntimeFactory.standardCelRuntimeBuilder() + .setOptions(OPTIONS) + .addLibraries( + CelExtensions.encoders(), + CelExtensions.math(OPTIONS), + CelExtensions.sets(), + CelExtensions.strings(), + CelOptionalLibrary.INSTANCE) + .addMessageTypes( + com.google.api.expr.test.v1.proto2.TestAllTypesProto.TestAllTypes.getDescriptor()) + .addMessageTypes( + com.google.api.expr.test.v1.proto3.TestAllTypesProto.TestAllTypes.getDescriptor()) + .build(); + + private static ImmutableMap getBindings(SimpleTest test) throws Exception { + ImmutableMap.Builder bindings = + ImmutableMap.builderWithExpectedSize(test.getBindingsCount()); + for (Map.Entry entry : test.getBindingsMap().entrySet()) { + bindings.put(entry.getKey(), fromExprValue(entry.getValue())); + } + return bindings.buildOrThrow(); + } + + private static Object fromExprValue(ExprValue value) throws Exception { + switch (value.getKindCase()) { + case VALUE: + return fromValue(value.getValue()); + default: + throw new IllegalArgumentException( + String.format("Unexpected binding value kind: %s", value.getKindCase())); + } + } + + private static Object fromValue(Value value) throws Exception { + switch (value.getKindCase()) { + case NULL_VALUE: + return value.getNullValue(); + case BOOL_VALUE: + return value.getBoolValue(); + case INT64_VALUE: + return value.getInt64Value(); + case UINT64_VALUE: + return UnsignedLong.fromLongBits(value.getUint64Value()); + case DOUBLE_VALUE: + return value.getDoubleValue(); + case STRING_VALUE: + return value.getStringValue(); + case BYTES_VALUE: + return value.getBytesValue(); + case ENUM_VALUE: + return value.getEnumValue(); + case OBJECT_VALUE: + { + Any object = value.getObjectValue(); + Descriptor descriptor = + DEFAULT_TYPE_REGISTRY.getDescriptorForTypeUrl(object.getTypeUrl()); + Message prototype = + DefaultInstanceMessageFactory.getInstance() + .getPrototype(descriptor) + .orElseThrow( + () -> + new NoSuchElementException( + "Could not find a default message for: " + descriptor.getFullName())); + return prototype + .getParserForType() + .parseFrom(object.getValue(), DEFAULT_EXTENSION_REGISTRY); + } + case MAP_VALUE: + { + MapValue map = value.getMapValue(); + ImmutableMap.Builder builder = + ImmutableMap.builderWithExpectedSize(map.getEntriesCount()); + for (MapValue.Entry entry : map.getEntriesList()) { + builder.put(fromValue(entry.getKey()), fromValue(entry.getValue())); + } + return builder.buildOrThrow(); + } + case LIST_VALUE: + { + ListValue list = value.getListValue(); + ImmutableList.Builder builder = + ImmutableList.builderWithExpectedSize(list.getValuesCount()); + for (Value element : list.getValuesList()) { + builder.add(fromValue(element)); + } + return builder.build(); + } + case TYPE_VALUE: + return value.getTypeValue(); + default: + throw new IllegalArgumentException( + String.format("Unexpected binding value kind: %s", value.getKindCase())); + } + } + + private static ExprValue toExprValue(Object object, CelType type) throws Exception { + if (object instanceof ExprValue) { + return (ExprValue) object; + } + return ExprValue.newBuilder().setValue(toValue(object, type)).build(); + } + + @SuppressWarnings("unchecked") + private static Value toValue(Object object, CelType type) throws Exception { + if (object == null) { + object = NullValue.NULL_VALUE; + } + if (object instanceof dev.cel.expr.Value) { + object = + Value.parseFrom( + ((dev.cel.expr.Value) object).toByteArray(), DEFAULT_EXTENSION_REGISTRY); + } + if (object instanceof Value) { + return (Value) object; + } + if (object instanceof NullValue) { + return Value.newBuilder().setNullValue((NullValue) object).build(); + } + if (object instanceof Boolean) { + return Value.newBuilder().setBoolValue((Boolean) object).build(); + } + if (object instanceof UnsignedLong) { + switch (type.kind()) { + case UINT: + case DYN: + case ANY: + return Value.newBuilder().setUint64Value(((UnsignedLong) object).longValue()).build(); + default: + throw new IllegalArgumentException(String.format("Unexpected result type: %s", type)); + } + } + if (object instanceof Long) { + switch (type.kind()) { + case INT: + case DYN: + case ANY: + return Value.newBuilder().setInt64Value((Long) object).build(); + case UINT: + return Value.newBuilder().setUint64Value((Long) object).build(); + default: + throw new IllegalArgumentException(String.format("Unexpected result type: %s", type)); + } + } + if (object instanceof Double) { + return Value.newBuilder().setDoubleValue((Double) object).build(); + } + if (object instanceof String) { + switch (type.kind()) { + case TYPE: + return Value.newBuilder().setTypeValue((String) object).build(); + case STRING: + case DYN: + case ANY: + return Value.newBuilder().setStringValue((String) object).build(); + default: + throw new IllegalArgumentException(String.format("Unexpected result type: %s", type)); + } + } + if (object instanceof ByteString) { + return Value.newBuilder().setBytesValue((ByteString) object).build(); + } + if (object instanceof List) { + CelType elemType = type instanceof ListType ? ((ListType) type).elemType() : SimpleType.DYN; + ListValue.Builder builder = ListValue.newBuilder(); + for (Object element : ((List) object)) { + builder.addValues(toValue(element, elemType)); + } + return Value.newBuilder().setListValue(builder.build()).build(); + } + if (object instanceof Map) { + CelType keyType = type instanceof MapType ? ((MapType) type).keyType() : SimpleType.DYN; + CelType valueType = type instanceof MapType ? ((MapType) type).valueType() : SimpleType.DYN; + MapValue.Builder builder = MapValue.newBuilder(); + for (Map.Entry entry : ((Map) object).entrySet()) { + builder.addEntries( + MapValue.Entry.newBuilder() + .setKey(toValue(entry.getKey(), keyType)) + .setValue(toValue(entry.getValue(), valueType)) + .build()); + } + return Value.newBuilder().setMapValue(builder.build()).build(); + } + if (object instanceof Message) { + return Value.newBuilder().setObjectValue(Any.pack((Message) object)).build(); + } + throw new IllegalArgumentException( + String.format("Unexpected result type: %s", object.getClass())); + } + + private static SimpleTest defaultTestMatcherToTrueIfUnset(SimpleTest test) { + if (test.getResultMatcherCase() == SimpleTest.ResultMatcherCase.RESULTMATCHER_NOT_SET) { + return test.toBuilder().setValue(Value.newBuilder().setBoolValue(true).build()).build(); + } + return test; + } + + private final String name; + private final SimpleTest test; + private final boolean skip; + + public ConformanceTest(String name, SimpleTest test, boolean skip) { + this.name = Preconditions.checkNotNull(name); + this.test = + Preconditions.checkNotNull( + defaultTestMatcherToTrueIfUnset(Preconditions.checkNotNull(test))); + this.skip = skip; + } + + public String getName() { + return name; + } + + public boolean shouldSkip() { + return skip; + } + + @Override + public void evaluate() throws Throwable { + CelValidationResult response = getParser(test).parse(test.getExpr(), test.getName()); + assertThat(response.hasError()).isFalse(); + response = getChecker(test).check(response.getAst()); + assertThat(response.hasError()).isFalse(); + Program program = RUNTIME.createProgram(response.getAst()); + ExprValue result = null; + CelEvaluationException error = null; + try { + result = toExprValue(program.eval(getBindings(test)), response.getAst().getResultType()); + } catch (CelEvaluationException e) { + error = e; + } + switch (test.getResultMatcherCase()) { + case VALUE: + assertThat(error).isNull(); + assertThat(result).isNotNull(); + assertThat(result) + .ignoringRepeatedFieldOrderOfFieldDescriptors( + MapValue.getDescriptor().findFieldByName("entries")) + .unpackingAnyUsing(DEFAULT_TYPE_REGISTRY, DEFAULT_EXTENSION_REGISTRY) + .isEqualTo(ExprValue.newBuilder().setValue(test.getValue()).build()); + break; + case EVAL_ERROR: + assertThat(result).isNull(); + assertThat(error).isNotNull(); + break; + default: + throw new IllegalStateException( + String.format("Unexpected matcher kind: %s", test.getResultMatcherCase())); + } + } +} diff --git a/conformance/src/test/java/dev/cel/conformance/ConformanceTestRunner.java b/conformance/src/test/java/dev/cel/conformance/ConformanceTestRunner.java new file mode 100644 index 000000000..a9f41c87f --- /dev/null +++ b/conformance/src/test/java/dev/cel/conformance/ConformanceTestRunner.java @@ -0,0 +1,128 @@ +// Copyright 2024 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.conformance; + +import static dev.cel.conformance.ConformanceTest.DEFAULT_EXTENSION_REGISTRY; +import static dev.cel.conformance.ConformanceTest.DEFAULT_TYPE_REGISTRY; + +import com.google.api.expr.test.v1.SimpleProto.SimpleTest; +import com.google.api.expr.test.v1.SimpleProto.SimpleTestFile; +import com.google.api.expr.test.v1.SimpleProto.SimpleTestSection; +import com.google.common.base.Preconditions; +import com.google.common.base.Splitter; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSortedMap; +import com.google.protobuf.TextFormat; +import java.io.BufferedReader; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import org.junit.runner.Description; +import org.junit.runner.notification.RunNotifier; +import org.junit.runners.ParentRunner; +import org.junit.runners.model.InitializationError; +import org.junit.runners.model.TestClass; + +public final class ConformanceTestRunner extends ParentRunner { + + private static final Splitter SPLITTER = Splitter.on(",").omitEmptyStrings(); + + private final ImmutableSortedMap testFiles; + private final ImmutableList testsToSkip; + + private static ImmutableSortedMap loadTestFiles() { + List testPaths = + SPLITTER.splitToList(System.getProperty("dev.cel.conformance.ConformanceTests.tests")); + try { + TextFormat.Parser parser = + TextFormat.Parser.newBuilder().setTypeRegistry(DEFAULT_TYPE_REGISTRY).build(); + ImmutableSortedMap.Builder testFiles = + ImmutableSortedMap.naturalOrder(); + for (String testPath : testPaths) { + SimpleTestFile.Builder fileBuilder = SimpleTestFile.newBuilder(); + try (BufferedReader input = + Files.newBufferedReader(Paths.get(testPath), StandardCharsets.UTF_8)) { + parser.merge(input, DEFAULT_EXTENSION_REGISTRY, fileBuilder); + } + SimpleTestFile testFile = fileBuilder.build(); + testFiles.put(testFile.getName(), testFile); + } + return testFiles.buildOrThrow(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public ConformanceTestRunner(Class clazz) throws InitializationError { + super(new TestClass(clazz)); + Preconditions.checkArgument(ConformanceTests.class.equals(clazz)); + testFiles = loadTestFiles(); + testsToSkip = + ImmutableList.copyOf( + SPLITTER.splitToList( + System.getProperty("dev.cel.conformance.ConformanceTests.skip_tests"))); + } + + private boolean shouldSkipTest(String name) { + for (String testToSkip : testsToSkip) { + if (name.startsWith(testToSkip)) { + String consumedName = name.substring(testToSkip.length()); + if (consumedName.isEmpty() || consumedName.startsWith("/")) { + return true; + } + } + } + return false; + } + + @Override + protected List getChildren() { + ArrayList tests = new ArrayList<>(); + for (SimpleTestFile testFile : testFiles.values()) { + for (SimpleTestSection testSection : testFile.getSectionList()) { + for (SimpleTest test : testSection.getTestList()) { + String name = + String.format("%s/%s/%s", testFile.getName(), testSection.getName(), test.getName()); + tests.add( + new ConformanceTest(name, test, test.getDisableCheck() || shouldSkipTest(name))); + } + } + } + return tests; + } + + @Override + protected Description describeChild(ConformanceTest child) { + return Description.createTestDescription( + ConformanceTest.class, child.getName(), ConformanceTest.class.getAnnotations()); + } + + @Override + protected void runChild(ConformanceTest child, RunNotifier notifier) { + Description desc = describeChild(child); + if (isIgnored(child)) { + notifier.fireTestIgnored(desc); + } else { + runLeaf(child, desc, notifier); + } + } + + @Override + protected boolean isIgnored(ConformanceTest child) { + return child.shouldSkip(); + } +} diff --git a/conformance/src/test/java/dev/cel/conformance/ConformanceTests.java b/conformance/src/test/java/dev/cel/conformance/ConformanceTests.java new file mode 100644 index 000000000..58de114ba --- /dev/null +++ b/conformance/src/test/java/dev/cel/conformance/ConformanceTests.java @@ -0,0 +1,20 @@ +// Copyright 2024 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.conformance; + +import org.junit.runner.RunWith; + +@RunWith(ConformanceTestRunner.class) +public class ConformanceTests {} diff --git a/conformance/src/test/java/dev/cel/conformance/conformance_test.bzl b/conformance/src/test/java/dev/cel/conformance/conformance_test.bzl new file mode 100644 index 000000000..8201f4ce3 --- /dev/null +++ b/conformance/src/test/java/dev/cel/conformance/conformance_test.bzl @@ -0,0 +1,80 @@ +# Copyright 2024 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. + +""" +This module contains build rules for generating the conformance test targets. +""" + +load("@rules_java//java:defs.bzl", "java_test") + +# Converts the list of tests to skip from the format used by the original Go test runner to a single +# flag value where each test is separated by a comma. It also performs expansion, for example +# `foo/bar,baz` becomes two entries which are `foo/bar` and `foo/baz`. +def _expand_tests_to_skip(tests_to_skip): + result = [] + for test_to_skip in tests_to_skip: + comma = test_to_skip.find(",") + if comma == -1: + result.append(test_to_skip) + continue + slash = test_to_skip.rfind("/", 0, comma) + if slash == -1: + slash = 0 + else: + slash = slash + 1 + for part in test_to_skip[slash:].split(","): + result.append(test_to_skip[0:slash] + part) + return result + +def _conformance_test_args(data, skip_tests): + args = [] + args.append("-Ddev.cel.conformance.ConformanceTests.skip_tests={}".format(",".join(_expand_tests_to_skip(skip_tests)))) + args.append("-Ddev.cel.conformance.ConformanceTests.tests={}".format(",".join(["$(location " + test + ")" for test in data]))) + return args + +def conformance_test(name, data, dashboard, skip_tests = []): + if dashboard: + java_test( + name = "_" + name, + jvm_flags = _conformance_test_args(data, skip_tests), + data = data, + size = "small", + test_class = "dev.cel.conformance.ConformanceTests", + runtime_deps = ["//conformance/src/test/java/dev/cel/conformance:run"], + tags = [ + "manual", + "notap", + ], + ) + native.sh_test( + name = name, + size = "small", + srcs = ["//conformance/src/test/java/dev/cel/conformance:conformance_test.sh"], + args = ["$(location :_" + name + ")"], + data = [":_" + name], + tags = [ + "guitar", + "manual", + "notap", + ], + ) + else: + java_test( + name = name, + jvm_flags = _conformance_test_args(data, skip_tests), + data = data, + size = "small", + test_class = "dev.cel.conformance.ConformanceTests", + runtime_deps = ["//conformance/src/test/java/dev/cel/conformance:run"], + ) diff --git a/conformance/src/test/java/dev/cel/conformance/conformance_test.sh b/conformance/src/test/java/dev/cel/conformance/conformance_test.sh new file mode 100755 index 000000000..c00f21c7a --- /dev/null +++ b/conformance/src/test/java/dev/cel/conformance/conformance_test.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +(exec "$@") +rc = $? +if [ $rc -eq 1 ]; then + rc = 0 +fi +exit $rc diff --git a/testing/src/main/java/dev/cel/testing/CelDebug.java b/testing/src/main/java/dev/cel/testing/CelDebug.java index 58bb2a6b2..f28383614 100644 --- a/testing/src/main/java/dev/cel/testing/CelDebug.java +++ b/testing/src/main/java/dev/cel/testing/CelDebug.java @@ -42,12 +42,12 @@ public String adorn(EntryOrBuilder entry) { } }; - /** Returns the unadorned string representation of {@link com.google.api.expr.ExprOrBuilder}. */ + /** Returns the unadorned string representation of {@link dev.cel.expr.ExprOrBuilder}. */ public static String toDebugString(ExprOrBuilder expr) { return toAdornedDebugString(expr, UNADORNER); } - /** Returns the adorned string representation of {@link com.google.api.expr.ExprOrBuilder}. */ + /** Returns the adorned string representation of {@link dev.cel.expr.ExprOrBuilder}. */ public static String toAdornedDebugString(ExprOrBuilder expr, CelAdorner adorner) { CelDebug debug = new CelDebug(checkNotNull(adorner)); debug.appendExpr(checkNotNull(expr)); From 53a33aa97c4e64b5ddf66d242b80576de822488a Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Tue, 13 Aug 2024 09:20:21 -0700 Subject: [PATCH 171/486] Fix runtime equality behavior for sets extension PiperOrigin-RevId: 662542663 --- .../main/java/dev/cel/extensions/BUILD.bazel | 5 +- .../dev/cel/extensions/CelExtensions.java | 23 +- .../dev/cel/extensions/CelSetsExtensions.java | 121 +++++------ .../cel/extensions/CelSetsExtensionsTest.java | 205 +++++++++++++++++- 4 files changed, 268 insertions(+), 86 deletions(-) diff --git a/extensions/src/main/java/dev/cel/extensions/BUILD.bazel b/extensions/src/main/java/dev/cel/extensions/BUILD.bazel index a6e35911d..b92bd9b54 100644 --- a/extensions/src/main/java/dev/cel/extensions/BUILD.bazel +++ b/extensions/src/main/java/dev/cel/extensions/BUILD.bazel @@ -137,10 +137,13 @@ java_library( deps = [ "//checker:checker_builder", "//common:compiler_common", - "//common/internal:comparison_functions", + "//common:options", + "//common/internal:default_message_factory", + "//common/internal:dynamic_proto", "//common/types", "//compiler:compiler_builder", "//runtime", + "//runtime:runtime_helper", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", ], diff --git a/extensions/src/main/java/dev/cel/extensions/CelExtensions.java b/extensions/src/main/java/dev/cel/extensions/CelExtensions.java index 662246283..353acdad3 100644 --- a/extensions/src/main/java/dev/cel/extensions/CelExtensions.java +++ b/extensions/src/main/java/dev/cel/extensions/CelExtensions.java @@ -34,7 +34,6 @@ public final class CelExtensions { private static final CelProtoExtensions PROTO_EXTENSIONS = new CelProtoExtensions(); private static final CelBindingsExtensions BINDINGS_EXTENSIONS = new CelBindingsExtensions(); private static final CelEncoderExtensions ENCODER_EXTENSIONS = new CelEncoderExtensions(); - private static final CelSetsExtensions SET_EXTENSIONS = new CelSetsExtensions(); /** * Extended functions for string manipulation. @@ -175,6 +174,14 @@ public static CelEncoderExtensions encoders() { return ENCODER_EXTENSIONS; } + /** + * @deprecated Use {@link #sets(CelOptions)} instead. + */ + @Deprecated + public static CelSetsExtensions sets() { + return sets(CelOptions.DEFAULT); + } + /** * Extended functions for Set manipulation. * @@ -184,8 +191,8 @@ public static CelEncoderExtensions encoders() { * future additions. To expose only a subset of functions, use {@link * #sets(CelSetExtensions.Function...)} instead. */ - public static CelSetsExtensions sets() { - return SET_EXTENSIONS; + public static CelSetsExtensions sets(CelOptions celOptions) { + return new CelSetsExtensions(celOptions); } /** @@ -195,8 +202,9 @@ public static CelSetsExtensions sets() { * *

This will include only the specific functions denoted by {@link CelSetsExtensions.Function}. */ - public static CelSetsExtensions sets(CelSetsExtensions.Function... functions) { - return sets(ImmutableSet.copyOf(functions)); + public static CelSetsExtensions sets( + CelOptions celOptions, CelSetsExtensions.Function... functions) { + return sets(celOptions, ImmutableSet.copyOf(functions)); } /** @@ -206,8 +214,9 @@ public static CelSetsExtensions sets(CelSetsExtensions.Function... functions) { * *

This will include only the specific functions denoted by {@link CelSetsExtensions.Function}. */ - public static CelSetsExtensions sets(Set functions) { - return new CelSetsExtensions(functions); + public static CelSetsExtensions sets( + CelOptions celOptions, Set functions) { + return new CelSetsExtensions(celOptions, functions); } /** diff --git a/extensions/src/main/java/dev/cel/extensions/CelSetsExtensions.java b/extensions/src/main/java/dev/cel/extensions/CelSetsExtensions.java index e410edade..1a3cb196a 100644 --- a/extensions/src/main/java/dev/cel/extensions/CelSetsExtensions.java +++ b/extensions/src/main/java/dev/cel/extensions/CelSetsExtensions.java @@ -18,8 +18,10 @@ import com.google.errorprone.annotations.Immutable; import dev.cel.checker.CelCheckerBuilder; import dev.cel.common.CelFunctionDecl; +import dev.cel.common.CelOptions; import dev.cel.common.CelOverloadDecl; -import dev.cel.common.internal.ComparisonFunctions; +import dev.cel.common.internal.DefaultMessageFactory; +import dev.cel.common.internal.DynamicProto; import dev.cel.common.types.ListType; import dev.cel.common.types.SimpleType; import dev.cel.common.types.TypeParamType; @@ -27,9 +29,9 @@ import dev.cel.runtime.CelRuntime; import dev.cel.runtime.CelRuntimeBuilder; import dev.cel.runtime.CelRuntimeLibrary; +import dev.cel.runtime.RuntimeEquality; import java.util.Collection; import java.util.Iterator; -import java.util.List; import java.util.Set; /** @@ -64,6 +66,9 @@ public final class CelSetsExtensions implements CelCompilerLibrary, CelRuntimeLi + " are unique, so size does not factor into the computation. If either list is empty," + " the result will be false."; + private static final RuntimeEquality RUNTIME_EQUALITY = + new RuntimeEquality(DynamicProto.create(DefaultMessageFactory.INSTANCE)); + /** Denotes the set extension function. */ public enum Function { CONTAINS( @@ -74,12 +79,7 @@ public enum Function { SET_CONTAINS_OVERLOAD_DOC, SimpleType.BOOL, ListType.create(TypeParamType.create("T")), - ListType.create(TypeParamType.create("T")))), - CelRuntime.CelFunctionBinding.from( - "list_sets_contains_list", - Collection.class, - Collection.class, - CelSetsExtensions::containsAll)), + ListType.create(TypeParamType.create("T"))))), EQUIVALENT( CelFunctionDecl.newFunctionDeclaration( SET_EQUIVALENT_FUNCTION, @@ -88,12 +88,7 @@ public enum Function { SET_EQUIVALENT_OVERLOAD_DOC, SimpleType.BOOL, ListType.create(TypeParamType.create("T")), - ListType.create(TypeParamType.create("T")))), - CelRuntime.CelFunctionBinding.from( - "list_sets_equivalent_list", - Collection.class, - Collection.class, - (listA, listB) -> containsAll(listA, listB) && containsAll(listB, listA))), + ListType.create(TypeParamType.create("T"))))), INTERSECTS( CelFunctionDecl.newFunctionDeclaration( SET_INTERSECTS_FUNCTION, @@ -102,34 +97,29 @@ public enum Function { SET_INTERSECTS_OVERLOAD_DOC, SimpleType.BOOL, ListType.create(TypeParamType.create("T")), - ListType.create(TypeParamType.create("T")))), - CelRuntime.CelFunctionBinding.from( - "list_sets_intersects_list", - Collection.class, - Collection.class, - CelSetsExtensions::setIntersects)); + ListType.create(TypeParamType.create("T"))))); private final CelFunctionDecl functionDecl; - private final ImmutableSet functionBindings; String getFunction() { return functionDecl.name(); } - Function(CelFunctionDecl functionDecl, CelRuntime.CelFunctionBinding... functionBindings) { + Function(CelFunctionDecl functionDecl) { this.functionDecl = functionDecl; - this.functionBindings = ImmutableSet.copyOf(functionBindings); } } private final ImmutableSet functions; + private final CelOptions celOptions; - CelSetsExtensions() { - this(ImmutableSet.copyOf(Function.values())); + CelSetsExtensions(CelOptions celOptions) { + this(celOptions, ImmutableSet.copyOf(Function.values())); } - CelSetsExtensions(Set functions) { + CelSetsExtensions(CelOptions celOptions, Set functions) { this.functions = ImmutableSet.copyOf(functions); + this.celOptions = celOptions; } @Override @@ -139,7 +129,34 @@ public void setCheckerOptions(CelCheckerBuilder checkerBuilder) { @Override public void setRuntimeOptions(CelRuntimeBuilder runtimeBuilder) { - functions.forEach(function -> runtimeBuilder.addFunctionBindings(function.functionBindings)); + for (Function function : functions) { + switch (function) { + case CONTAINS: + runtimeBuilder.addFunctionBindings( + CelRuntime.CelFunctionBinding.from( + "list_sets_contains_list", + Collection.class, + Collection.class, + this::containsAll)); + break; + case EQUIVALENT: + runtimeBuilder.addFunctionBindings( + CelRuntime.CelFunctionBinding.from( + "list_sets_equivalent_list", + Collection.class, + Collection.class, + (listA, listB) -> containsAll(listA, listB) && containsAll(listB, listA))); + break; + case INTERSECTS: + runtimeBuilder.addFunctionBindings( + CelRuntime.CelFunctionBinding.from( + "list_sets_intersects_list", + Collection.class, + Collection.class, + this::setIntersects)); + break; + } + } } /** @@ -150,9 +167,9 @@ public void setRuntimeOptions(CelRuntimeBuilder runtimeBuilder) { *

This is picked verbatim as implemented in the Java standard library * Collections.containsAll() method. * - * @see #contains(Object) + * @see #contains(Object, Collection) */ - private static boolean containsAll(Collection list, Collection subList) { + private boolean containsAll(Collection list, Collection subList) { for (T e : subList) { if (!contains(e, list)) { return false; @@ -171,7 +188,7 @@ private static boolean containsAll(Collection list, Collection subList *

Source: * https://hg.openjdk.org/jdk8u/jdk8u-dev/jdk/file/c5d02f908fb2/src/share/classes/java/util/AbstractCollection.java#l98 */ - private static boolean contains(Object o, Collection list) { + private boolean contains(Object o, Collection list) { Iterator it = list.iterator(); if (o == null) { while (it.hasNext()) { @@ -182,7 +199,7 @@ private static boolean contains(Object o, Collection list) { } else { while (it.hasNext()) { Object item = it.next(); - if (objectsEquals(item, o)) { // TODO: Support Maps. + if (objectsEquals(item, o)) { return true; } } @@ -190,47 +207,11 @@ private static boolean contains(Object o, Collection list) { return false; } - private static boolean objectsEquals(Object o1, Object o2) { - if (o1 == o2) { - return true; - } - if (o1 == null || o2 == null) { - return false; - } - if (isNumeric(o1) && isNumeric(o2)) { - if (o1.getClass().equals(o2.getClass())) { - return o1.equals(o2); - } - return ComparisonFunctions.numericEquals((Number) o1, (Number) o2); - } - if (isList(o1) && isList(o2)) { - Collection list1 = (Collection) o1; - Collection list2 = (Collection) o2; - if (list1.size() != list2.size()) { - return false; - } - Iterator iterator1 = list1.iterator(); - Iterator iterator2 = list2.iterator(); - boolean result = true; - while (iterator1.hasNext() && iterator2.hasNext()) { - Object p1 = iterator1.next(); - Object p2 = iterator2.next(); - result = result && objectsEquals(p1, p2); - } - return result; - } - return o1.equals(o2); - } - - private static boolean isNumeric(Object o) { - return o instanceof Number; - } - - private static boolean isList(Object o) { - return o instanceof List; + private boolean objectsEquals(Object o1, Object o2) { + return RUNTIME_EQUALITY.objectEquals(o1, o2, celOptions); } - private static boolean setIntersects(Collection listA, Collection listB) { + private boolean setIntersects(Collection listA, Collection listB) { if (listA.isEmpty() || listB.isEmpty()) { return false; } diff --git a/extensions/src/test/java/dev/cel/extensions/CelSetsExtensionsTest.java b/extensions/src/test/java/dev/cel/extensions/CelSetsExtensionsTest.java index 70396ee45..120ac25d6 100644 --- a/extensions/src/test/java/dev/cel/extensions/CelSetsExtensionsTest.java +++ b/extensions/src/test/java/dev/cel/extensions/CelSetsExtensionsTest.java @@ -22,6 +22,9 @@ import com.google.testing.junit.testparameterinjector.TestParameterInjector; import com.google.testing.junit.testparameterinjector.TestParameters; import dev.cel.common.CelAbstractSyntaxTree; +import dev.cel.common.CelFunctionDecl; +import dev.cel.common.CelOptions; +import dev.cel.common.CelOverloadDecl; import dev.cel.common.CelValidationException; import dev.cel.common.CelValidationResult; import dev.cel.common.types.ListType; @@ -31,22 +34,44 @@ import dev.cel.extensions.CelSetsExtensions.Function; import dev.cel.runtime.CelEvaluationException; import dev.cel.runtime.CelRuntime; +import dev.cel.runtime.CelRuntime.CelFunctionBinding; import dev.cel.runtime.CelRuntimeFactory; +import dev.cel.testing.testdata.proto3.TestAllTypesProto.TestAllTypes; import java.util.List; import org.junit.Test; import org.junit.runner.RunWith; @RunWith(TestParameterInjector.class) public final class CelSetsExtensionsTest { + private static final CelOptions CEL_OPTIONS = + CelOptions.current().enableUnsignedLongs(true).build(); private static final CelCompiler COMPILER = CelCompilerFactory.standardCelCompilerBuilder() - .addLibraries(CelExtensions.sets()) + .addMessageTypes(TestAllTypes.getDescriptor()) + .setOptions(CEL_OPTIONS) + .setContainer("dev.cel.testing.testdata.proto3") + .addLibraries(CelExtensions.sets(CEL_OPTIONS)) .addVar("list", ListType.create(SimpleType.INT)) .addVar("subList", ListType.create(SimpleType.INT)) + .addFunctionDeclarations( + CelFunctionDecl.newFunctionDeclaration( + "new_int", + CelOverloadDecl.newGlobalOverload( + "new_int_int64", SimpleType.INT, SimpleType.INT))) .build(); private static final CelRuntime RUNTIME = - CelRuntimeFactory.standardCelRuntimeBuilder().addLibraries(CelExtensions.sets()).build(); + CelRuntimeFactory.standardCelRuntimeBuilder() + .addMessageTypes(TestAllTypes.getDescriptor()) + .addLibraries(CelExtensions.sets(CEL_OPTIONS)) + .setOptions(CEL_OPTIONS) + .addFunctionBindings( + CelFunctionBinding.from( + "new_int_int64", + Long.class, + // Intentionally return java.lang.Integer to test primitive type adaptation + Math::toIntExact)) + .build(); @Test public void contains_integerListWithSameValue_succeeds() throws Exception { @@ -70,6 +95,42 @@ public void contains_integerListAsExpression_succeeds() throws Exception { assertThat(result).isEqualTo(true); } + @Test + @TestParameters( + "{expression: 'sets.contains([TestAllTypes{}], [TestAllTypes{}])', expected: true}") + @TestParameters( + "{expression: 'sets.contains([TestAllTypes{single_int64: 1, single_uint64: 2u}]," + + " [TestAllTypes{single_int64: 1, single_uint64: 2u}])', expected: true}") + @TestParameters( + "{expression: 'sets.contains([TestAllTypes{single_any: [1.0, 2u, 3]}]," + + " [TestAllTypes{single_any: [1u, 2, 3.0]}])', expected: true}") + @TestParameters( + "{expression: 'sets.contains([TestAllTypes{single_int64: 1, single_uint64: 2u}]," + + " [TestAllTypes{single_int64: 2, single_uint64: 3u}])', expected: false}") + public void contains_withProtoMessage_succeeds(String expression, boolean expected) + throws Exception { + CelAbstractSyntaxTree ast = COMPILER.compile(expression).getAst(); + CelRuntime.Program program = RUNTIME.createProgram(ast); + + boolean result = (boolean) program.eval(); + + assertThat(result).isEqualTo(expected); + } + + @Test + @TestParameters("{expression: 'sets.contains([new_int(1)], [1])', expected: true}") + @TestParameters("{expression: 'sets.contains([new_int(1)], [1.0, 1u])', expected: true}") + @TestParameters("{expression: 'sets.contains([new_int(2)], [1])', expected: false}") + public void contains_withFunctionReturningInteger_succeeds(String expression, boolean expected) + throws Exception { + CelAbstractSyntaxTree ast = COMPILER.compile(expression).getAst(); + CelRuntime.Program program = RUNTIME.createProgram(ast); + + boolean result = (boolean) program.eval(); + + assertThat(result).isEqualTo(expected); + } + @Test @TestParameters("{list: [1, 2, 3, 4], subList: [1, 2, 3, 4], expected: true}") @TestParameters("{list: [5, 4, 3, 2, 1], subList: [1, 2, 3], expected: true}") @@ -186,6 +247,26 @@ public void contains_withMultiLevelNestedList_succeeds(String expression, boolea assertThat(result).isEqualTo(expected); } + @Test + @TestParameters("{expression: 'sets.contains([{1: 1}], [{1: 1}])', expected: true}") + @TestParameters("{expression: 'sets.contains([{1: 1}], [{1u: 1}, {1: 1.0}])', expected: true}") + @TestParameters( + "{expression: 'sets.contains([{\"a\": \"b\"}, {\"c\": \"d\"}], [{\"a\": \"b\"}])', expected:" + + " true}") + @TestParameters("{expression: 'sets.contains([{2: 1}], [{1: 1}])', expected: false}") + @TestParameters( + "{expression: 'sets.contains([{\"a\": \"b\"}], [{\"a\": \"b\"}, {\"c\": \"d\"}])', expected:" + + " false}") + public void contains_withMapValues_succeeds(String expression, boolean expected) + throws Exception { + CelAbstractSyntaxTree ast = COMPILER.compile(expression).getAst(); + CelRuntime.Program program = RUNTIME.createProgram(ast); + + boolean result = (boolean) program.eval(); + + assertThat(result).isEqualTo(expected); + } + @Test @TestParameters("{expression: 'sets.equivalent([], [])', expected: true}") @TestParameters("{expression: 'sets.equivalent([1], [1])', expected: true}") @@ -212,6 +293,7 @@ public void equivalent_withIntTypes_succeeds(String expression, boolean expected @TestParameters("{expression: 'sets.equivalent([1], [1u, 1.0])', expected: true}") @TestParameters( "{expression: 'sets.equivalent([[1.0], [2, 3]], [[1], [2, 3.0]])', expected: true}") + @TestParameters("{expression: 'sets.equivalent([1, 2.0, 3], [1, 2])', expected: false}") @TestParameters("{expression: 'sets.equivalent([1, 2], [2u, 2, 2.0])', expected: false}") @TestParameters("{expression: 'sets.equivalent([1, 2], [1u, 2, 2.3])', expected: false}") public void equivalent_withMixedTypes_succeeds(String expression, boolean expected) @@ -224,6 +306,59 @@ public void equivalent_withMixedTypes_succeeds(String expression, boolean expect assertThat(result).isEqualTo(expected); } + @Test + @TestParameters( + "{expression: 'sets.equivalent([TestAllTypes{}, TestAllTypes{}], [TestAllTypes{}])'," + + " expected: true}") + @TestParameters( + "{expression: 'sets.equivalent([TestAllTypes{}], [TestAllTypes{}, TestAllTypes{}])'," + + " expected: true}") + @TestParameters( + "{expression: 'sets.equivalent([TestAllTypes{single_int64: 1, single_uint64: 2u}]," + + " [TestAllTypes{single_int64: 1, single_uint64: 2u}])', expected: true}") + @TestParameters( + "{expression: 'sets.equivalent([TestAllTypes{single_any: [1.0, 2u, 3]}]," + + " [TestAllTypes{single_any: [1u, 2, 3.0]}])', expected: true}") + @TestParameters( + "{expression: 'sets.equivalent([TestAllTypes{single_any: [1.0, 2u, 3]}," + + " TestAllTypes{single_any: [2,3,4]}], [TestAllTypes{single_any: [1u, 2, 3.0]}])'," + + " expected: false}") + @TestParameters( + "{expression: 'sets.equivalent([TestAllTypes{single_int64: 1, single_uint64: 2u}]," + + " [TestAllTypes{single_int64: 2, single_uint64: 3u}])', expected: false}") + public void equivalent_withProtoMessage_succeeds(String expression, boolean expected) + throws Exception { + CelAbstractSyntaxTree ast = COMPILER.compile(expression).getAst(); + CelRuntime.Program program = RUNTIME.createProgram(ast); + + boolean result = (boolean) program.eval(); + + assertThat(result).isEqualTo(expected); + } + + @Test + @TestParameters("{expression: 'sets.equivalent([{1: 1}], [{1: 1}, {1: 1}])', expected: true}") + @TestParameters("{expression: 'sets.equivalent([{1: 1}, {1: 1}], [{1: 1}])', expected: true}") + @TestParameters("{expression: 'sets.equivalent([{1: 1}], [{1: 1u}, {1: 1.0}])', expected: true}") + @TestParameters( + "{expression: 'sets.equivalent([{1: 1}, {1u: 1}], [{1u: 1}, {1: 1.0}])', expected: true}") + @TestParameters( + "{expression: 'sets.equivalent([{\"a\": \"b\"}, {\"a\": \"b\"}], [{\"a\": \"b\"}])'," + + " expected: true}") + @TestParameters("{expression: 'sets.equivalent([{2: 1}], [{1: 1}])', expected: false}") + @TestParameters( + "{expression: 'sets.equivalent([{\"a\": \"b\"}], [{\"a\": \"b\"}, {\"c\": \"d\"}])'," + + " expected: false}") + public void equivalent_withMapValues_succeeds(String expression, boolean expected) + throws Exception { + CelAbstractSyntaxTree ast = COMPILER.compile(expression).getAst(); + CelRuntime.Program program = RUNTIME.createProgram(ast); + + boolean result = (boolean) program.eval(); + + assertThat(result).isEqualTo(expected); + } + @Test @TestParameters("{expression: 'sets.intersects([], [])', expected: false}") @TestParameters("{expression: 'sets.intersects([1], [])', expected: false}") @@ -254,9 +389,62 @@ public void intersects_withMixedTypes_succeeds(String expression, boolean expect assertThat(result).isEqualTo(expected); } + @Test + @TestParameters("{expression: 'sets.intersects([{1: 1}], [{1: 1}, {1: 1}])', expected: true}") + @TestParameters("{expression: 'sets.intersects([{1: 1}, {1: 1}], [{1: 1}])', expected: true}") + @TestParameters("{expression: 'sets.intersects([{1: 1}], [{1: 1u}, {1: 1.0}])', expected: true}") + @TestParameters( + "{expression: 'sets.intersects([{1: 1}, {1u: 1}], [{1.0: 1u}, {1u: 1.0}])', expected: true}") + @TestParameters("{expression: 'sets.intersects([{1:2}], [{1:2}, {2:3}])', expected: true}") + @TestParameters( + "{expression: 'sets.intersects([{\"a\": \"b\"}, {\"a\": \"b\"}], [{\"a\": \"b\"}])'," + + " expected: true}") + @TestParameters( + "{expression: 'sets.intersects([{\"a\": \"b\"}], [{\"c\": \"d\"}])', expected: false}") + @TestParameters("{expression: 'sets.intersects([{2: 1}], [{1: 1}])', expected: false}") + public void intersects_withMapValues_succeeds(String expression, boolean expected) + throws Exception { + CelAbstractSyntaxTree ast = COMPILER.compile(expression).getAst(); + CelRuntime.Program program = RUNTIME.createProgram(ast); + + boolean result = (boolean) program.eval(); + + assertThat(result).isEqualTo(expected); + } + + @Test + @TestParameters( + "{expression: 'sets.intersects([TestAllTypes{}, TestAllTypes{}], [TestAllTypes{}])'," + + " expected: true}") + @TestParameters( + "{expression: 'sets.intersects([TestAllTypes{}], [TestAllTypes{}, TestAllTypes{}])'," + + " expected: true}") + @TestParameters( + "{expression: 'sets.intersects([TestAllTypes{single_int64: 1, single_uint64: 2u}]," + + " [TestAllTypes{single_int64: 1, single_uint64: 2u}])', expected: true}") + @TestParameters( + "{expression: 'sets.intersects([TestAllTypes{single_any: [1.0, 2u, 3]}]," + + " [TestAllTypes{single_any: [1u, 2, 3.0]}])', expected: true}") + @TestParameters( + "{expression: 'sets.intersects([TestAllTypes{single_any: [1, 2, 3.5]}," + + " TestAllTypes{single_any: [2,3,4]}], [TestAllTypes{single_any: [1u, 2, 3.0]}])'," + + " expected: false}") + @TestParameters( + "{expression: 'sets.intersects([TestAllTypes{single_int64: 1, single_uint64: 2u}]," + + " [TestAllTypes{single_int64: 2, single_uint64: 3u}])', expected: false}") + public void intersects_withProtoMessage_succeeds(String expression, boolean expected) + throws Exception { + CelAbstractSyntaxTree ast = COMPILER.compile(expression).getAst(); + CelRuntime.Program program = RUNTIME.createProgram(ast); + + boolean result = (boolean) program.eval(); + + assertThat(result).isEqualTo(expected); + } + @Test public void setsExtension_containsFunctionSubset_succeeds() throws Exception { - CelSetsExtensions setsExtensions = CelExtensions.sets(Function.CONTAINS); + CelSetsExtensions setsExtensions = CelExtensions.sets(CelOptions.DEFAULT, Function.CONTAINS); CelCompiler celCompiler = CelCompilerFactory.standardCelCompilerBuilder().addLibraries(setsExtensions).build(); CelRuntime celRuntime = @@ -270,7 +458,7 @@ public void setsExtension_containsFunctionSubset_succeeds() throws Exception { @Test public void setsExtension_equivalentFunctionSubset_succeeds() throws Exception { - CelSetsExtensions setsExtensions = CelExtensions.sets(Function.EQUIVALENT); + CelSetsExtensions setsExtensions = CelExtensions.sets(CelOptions.DEFAULT, Function.EQUIVALENT); CelCompiler celCompiler = CelCompilerFactory.standardCelCompilerBuilder().addLibraries(setsExtensions).build(); CelRuntime celRuntime = @@ -286,7 +474,7 @@ public void setsExtension_equivalentFunctionSubset_succeeds() throws Exception { @Test public void setsExtension_intersectsFunctionSubset_succeeds() throws Exception { - CelSetsExtensions setsExtensions = CelExtensions.sets(Function.INTERSECTS); + CelSetsExtensions setsExtensions = CelExtensions.sets(CelOptions.DEFAULT, Function.INTERSECTS); CelCompiler celCompiler = CelCompilerFactory.standardCelCompilerBuilder().addLibraries(setsExtensions).build(); CelRuntime celRuntime = @@ -302,7 +490,7 @@ public void setsExtension_intersectsFunctionSubset_succeeds() throws Exception { @Test public void setsExtension_compileUnallowedFunction_throws() { - CelSetsExtensions setsExtensions = CelExtensions.sets(Function.EQUIVALENT); + CelSetsExtensions setsExtensions = CelExtensions.sets(CelOptions.DEFAULT, Function.EQUIVALENT); CelCompiler celCompiler = CelCompilerFactory.standardCelCompilerBuilder().addLibraries(setsExtensions).build(); @@ -313,12 +501,13 @@ public void setsExtension_compileUnallowedFunction_throws() { @Test public void setsExtension_evaluateUnallowedFunction_throws() throws Exception { - CelSetsExtensions setsExtensions = CelExtensions.sets(Function.CONTAINS, Function.EQUIVALENT); + CelSetsExtensions setsExtensions = + CelExtensions.sets(CelOptions.DEFAULT, Function.CONTAINS, Function.EQUIVALENT); CelCompiler celCompiler = CelCompilerFactory.standardCelCompilerBuilder().addLibraries(setsExtensions).build(); CelRuntime celRuntime = CelRuntimeFactory.standardCelRuntimeBuilder() - .addLibraries(CelExtensions.sets(Function.EQUIVALENT)) + .addLibraries(CelExtensions.sets(CelOptions.DEFAULT, Function.EQUIVALENT)) .build(); CelAbstractSyntaxTree ast = celCompiler.compile("sets.contains([1, 2], [2])").getAst(); From 396ddcd66d7b1553c3630d7c17701eedfa87dc76 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Tue, 13 Aug 2024 09:26:17 -0700 Subject: [PATCH 172/486] Reduce count of errors joined together during parsing error PiperOrigin-RevId: 662544661 --- common/src/main/java/dev/cel/common/CelValidationException.java | 2 +- .../test/java/dev/cel/common/CelValidationExceptionTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/common/src/main/java/dev/cel/common/CelValidationException.java b/common/src/main/java/dev/cel/common/CelValidationException.java index 522706e83..953f5b152 100644 --- a/common/src/main/java/dev/cel/common/CelValidationException.java +++ b/common/src/main/java/dev/cel/common/CelValidationException.java @@ -22,7 +22,7 @@ public final class CelValidationException extends CelException { // Truncates all errors beyond this limit in the message. - private static final int MAX_ERRORS_TO_REPORT = 1000; + private static final int MAX_ERRORS_TO_REPORT = 500; private final CelSource source; private final ImmutableList errors; diff --git a/common/src/test/java/dev/cel/common/CelValidationExceptionTest.java b/common/src/test/java/dev/cel/common/CelValidationExceptionTest.java index be428a64c..8768616ea 100644 --- a/common/src/test/java/dev/cel/common/CelValidationExceptionTest.java +++ b/common/src/test/java/dev/cel/common/CelValidationExceptionTest.java @@ -37,6 +37,6 @@ public void construct_withLargeErrorCount() { assertThat(celValidationException.getErrors()).hasSize(1500); assertThat(celValidationException) .hasMessageThat() - .endsWith("...and 500 more errors (truncated)"); + .endsWith("...and 1000 more errors (truncated)"); } } From 233fda4b13e65494b6b2f8c2abb4fd02c671e75a Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Tue, 13 Aug 2024 10:25:49 -0700 Subject: [PATCH 173/486] Truncate joined compilation errors further to 100 PiperOrigin-RevId: 662565735 --- common/src/main/java/dev/cel/common/CelValidationException.java | 2 +- .../test/java/dev/cel/common/CelValidationExceptionTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/common/src/main/java/dev/cel/common/CelValidationException.java b/common/src/main/java/dev/cel/common/CelValidationException.java index 953f5b152..18bec2fe6 100644 --- a/common/src/main/java/dev/cel/common/CelValidationException.java +++ b/common/src/main/java/dev/cel/common/CelValidationException.java @@ -22,7 +22,7 @@ public final class CelValidationException extends CelException { // Truncates all errors beyond this limit in the message. - private static final int MAX_ERRORS_TO_REPORT = 500; + private static final int MAX_ERRORS_TO_REPORT = 100; private final CelSource source; private final ImmutableList errors; diff --git a/common/src/test/java/dev/cel/common/CelValidationExceptionTest.java b/common/src/test/java/dev/cel/common/CelValidationExceptionTest.java index 8768616ea..703531d81 100644 --- a/common/src/test/java/dev/cel/common/CelValidationExceptionTest.java +++ b/common/src/test/java/dev/cel/common/CelValidationExceptionTest.java @@ -37,6 +37,6 @@ public void construct_withLargeErrorCount() { assertThat(celValidationException.getErrors()).hasSize(1500); assertThat(celValidationException) .hasMessageThat() - .endsWith("...and 1000 more errors (truncated)"); + .endsWith("...and 1400 more errors (truncated)"); } } From 041886e2e9c3f85d89d5629bd318b67d1d8fe4b8 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Tue, 13 Aug 2024 11:56:11 -0700 Subject: [PATCH 174/486] Import only. PiperOrigin-RevId: 662600683 --- conformance/src/test/java/dev/cel/conformance/BUILD.bazel | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/conformance/src/test/java/dev/cel/conformance/BUILD.bazel b/conformance/src/test/java/dev/cel/conformance/BUILD.bazel index 5f1380277..6b60d77d4 100644 --- a/conformance/src/test/java/dev/cel/conformance/BUILD.bazel +++ b/conformance/src/test/java/dev/cel/conformance/BUILD.bazel @@ -97,8 +97,10 @@ _TESTS_TO_SKIP = [ "wrappers/duration/to_json", "wrappers/timestamp/to_json", "fields/qualified_identifier_resolution/map_value_repeat_key_heterogeneous", - # TODO: Add strings.quote. + # TODO: Add strings.format and strings.quote. "string_ext/quote", + "string_ext/format", + "string_ext/format_errors", # TODO: Fix null assignment to a field "proto2/set_null/single_message", From 595eccda94886956322be02ba6a88f1269f00148 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Tue, 13 Aug 2024 13:32:56 -0700 Subject: [PATCH 175/486] Change cel_spec repo url to 0.16.0 in WORKSPACE PiperOrigin-RevId: 662633046 --- WORKSPACE | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/WORKSPACE b/WORKSPACE index 04efe6010..9ba1c3f0c 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -149,10 +149,10 @@ http_archive( # cel-spec api/expr canonical protos http_archive( name = "cel_spec", - sha256 = "65a153c1c4d73a135c364a4955e6aabd1093f0ed291774d3637f350504505085", - strip_prefix = "cel-spec-0789389e13a0626ec3521e4f109acce360565ce6", + sha256 = "b4efed0586004c538fe2be4f0472a1e2483790895493502fcab58f56060f6d37", + strip_prefix = "cel-spec-0.16.0", urls = [ - "https://github.com/google/cel-spec/archive/0789389e13a0626ec3521e4f109acce360565ce6.tar.gz", + "https://github.com/google/cel-spec/archive/refs/tags/v0.16.0.tar.gz", ], ) From 83fe5a312bc60539d5072840c2bb817034391c12 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Wed, 14 Aug 2024 10:42:21 -0700 Subject: [PATCH 176/486] Parse explanations in match blocks PiperOrigin-RevId: 662975534 --- .../main/java/dev/cel/policy/CelPolicy.java | 7 ++++ .../dev/cel/policy/CelPolicyYamlParser.java | 18 +++++++++ .../cel/policy/CelPolicyYamlParserTest.java | 38 +++++++++++++++++++ .../test/resources/nested_rule/policy.yaml | 2 +- 4 files changed, 64 insertions(+), 1 deletion(-) diff --git a/policy/src/main/java/dev/cel/policy/CelPolicy.java b/policy/src/main/java/dev/cel/policy/CelPolicy.java index 45a2c666c..0f2f5d1a8 100644 --- a/policy/src/main/java/dev/cel/policy/CelPolicy.java +++ b/policy/src/main/java/dev/cel/policy/CelPolicy.java @@ -159,6 +159,9 @@ public abstract static class Match { public abstract Result result(); + /** Explanation returns the explanation expression, or empty expression if output is not set. */ + public abstract Optional explanation(); + /** Encapsulates the result of this match when condition is met. (either an output or a rule) */ @AutoOneOf(Match.Result.Kind.class) public abstract static class Result { @@ -191,8 +194,12 @@ public abstract static class Builder implements RequiredFieldsChecker { public abstract Builder setResult(Result result); + public abstract Builder setExplanation(ValueString explanation); + abstract Optional result(); + abstract Optional explanation(); + @Override public ImmutableList requiredFields() { return ImmutableList.of(RequiredField.of("output or a rule", this::result)); diff --git a/policy/src/main/java/dev/cel/policy/CelPolicyYamlParser.java b/policy/src/main/java/dev/cel/policy/CelPolicyYamlParser.java index 541dfdfb3..1327fbcef 100644 --- a/policy/src/main/java/dev/cel/policy/CelPolicyYamlParser.java +++ b/policy/src/main/java/dev/cel/policy/CelPolicyYamlParser.java @@ -202,12 +202,30 @@ public CelPolicy.Match parseMatch( result -> ctx.reportError(tagId, "Only the rule or the output may be set")); matchBuilder.setResult(Match.Result.ofOutput(ctx.newValueString(value))); break; + case "explanation": + matchBuilder + .result() + .filter(result -> result.kind().equals(Match.Result.Kind.RULE)) + .ifPresent( + result -> + ctx.reportError( + tagId, + "Explanation can only be set on output match cases, not nested rules")); + matchBuilder.setExplanation(ctx.newValueString(value)); + break; case "rule": matchBuilder .result() .filter(result -> result.kind().equals(Match.Result.Kind.OUTPUT)) .ifPresent( result -> ctx.reportError(tagId, "Only the rule or the output may be set")); + matchBuilder + .explanation() + .ifPresent( + result -> + ctx.reportError( + result.id(), + "Explanation can only be set on output match cases, not nested rules")); matchBuilder.setResult(Match.Result.ofRule(parseRule(ctx, policyBuilder, value))); break; default: diff --git a/policy/src/test/java/dev/cel/policy/CelPolicyYamlParserTest.java b/policy/src/test/java/dev/cel/policy/CelPolicyYamlParserTest.java index 5bc90cfb9..c648d3ac3 100644 --- a/policy/src/test/java/dev/cel/policy/CelPolicyYamlParserTest.java +++ b/policy/src/test/java/dev/cel/policy/CelPolicyYamlParserTest.java @@ -17,6 +17,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertThrows; +import com.google.common.collect.Iterables; import com.google.testing.junit.testparameterinjector.TestParameter; import com.google.testing.junit.testparameterinjector.TestParameterInjector; import dev.cel.policy.PolicyTestHelper.K8sTagHandler; @@ -42,6 +43,21 @@ public void parseYamlPolicy_success(@TestParameter TestYamlPolicy yamlPolicy) th assertThat(policy.policySource().getDescription()).isEqualTo(description); } + @Test + public void parseYamlPolicy_withExplanation() throws Exception { + String policySource = + "rule:\n" + + " match:\n" + + " - output: 'true'\n" + + " explanation: \"'custom explanation'\""; + + CelPolicy policy = POLICY_PARSER.parse(policySource); + + assertThat(policy.rule().matches()).hasSize(1); + assertThat(Iterables.getOnlyElement(policy.rule().matches()).explanation()) + .hasValue(ValueString.of(11, "'custom explanation'")); + } + @Test public void parseYamlPolicy_errors(@TestParameter PolicyParseErrorTestCase testCase) { CelPolicyValidationException e = @@ -197,6 +213,28 @@ private enum PolicyParseErrorTestCase { "ERROR: :7:7: Only the rule or the output may be set\n" + " | output: \"world\"\n" + " | ......^"), + MATCH_NESTED_RULE_SET_THEN_EXPLANATION( + "rule:\n" + + " match:\n" + + " - condition: \"true\"\n" + + " rule:\n" + + " match:\n" + + " - output: \"hello\"\n" + + " explanation: \"foo\"", + "ERROR: :7:7: Explanation can only be set on output match cases, not nested rules\n" + + " | explanation: \"foo\"\n" + + " | ......^"), + MATCH_EXPLANATION_SET_THEN_NESTED_RULE( + "rule:\n" + + " match:\n" + + " - condition: \"true\"\n" + + " explanation: \"foo\"\n" + + " rule:\n" + + " match:\n" + + " - output: \"hello\"\n", + "ERROR: :4:21: Explanation can only be set on output match cases, not nested rules\n" + + " | explanation: \"foo\"\n" + + " | ....................^"), INVALID_ROOT_NODE_TYPE( "- rule:\n" + " id: a", "ERROR: :1:1: Got yaml node type tag:yaml.org,2002:seq, wanted type(s)" diff --git a/policy/src/test/resources/nested_rule/policy.yaml b/policy/src/test/resources/nested_rule/policy.yaml index bbbfe0fc1..2fc566b85 100644 --- a/policy/src/test/resources/nested_rule/policy.yaml +++ b/policy/src/test/resources/nested_rule/policy.yaml @@ -35,4 +35,4 @@ rule: - condition: resource.origin in variables.permitted_regions output: "{'banned': false}" - output: "{'banned': true}" - + explanation: "'resource is in the banned region ' + resource.origin" \ No newline at end of file From 80d29a99886eeb04536ba6279c4e412fa4fd36cf Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Wed, 14 Aug 2024 17:42:09 -0700 Subject: [PATCH 177/486] Improved support for nested rules PiperOrigin-RevId: 663114054 --- .../src/main/java/dev/cel/policy/BUILD.bazel | 2 +- .../java/dev/cel/policy/CelCompiledRule.java | 30 ++++++++++++ .../java/dev/cel/policy/RuleComposer.java | 28 +++++++---- .../java/dev/cel/policy/PolicyTestHelper.java | 20 ++++++++ .../test/resources/nested_rule2/config.yaml | 22 +++++++++ .../test/resources/nested_rule2/policy.yaml | 40 ++++++++++++++++ .../test/resources/nested_rule2/tests.yaml | 48 +++++++++++++++++++ .../test/resources/nested_rule3/config.yaml | 22 +++++++++ .../test/resources/nested_rule3/policy.yaml | 39 +++++++++++++++ .../test/resources/nested_rule3/tests.yaml | 48 +++++++++++++++++++ 10 files changed, 288 insertions(+), 11 deletions(-) create mode 100644 policy/src/test/resources/nested_rule2/config.yaml create mode 100644 policy/src/test/resources/nested_rule2/policy.yaml create mode 100644 policy/src/test/resources/nested_rule2/tests.yaml create mode 100644 policy/src/test/resources/nested_rule3/config.yaml create mode 100644 policy/src/test/resources/nested_rule3/policy.yaml create mode 100644 policy/src/test/resources/nested_rule3/tests.yaml diff --git a/policy/src/main/java/dev/cel/policy/BUILD.bazel b/policy/src/main/java/dev/cel/policy/BUILD.bazel index 15e2977c2..ea3f4353c 100644 --- a/policy/src/main/java/dev/cel/policy/BUILD.bazel +++ b/policy/src/main/java/dev/cel/policy/BUILD.bazel @@ -227,6 +227,7 @@ java_library( "//bundle:cel", "//common", "//common:compiler_common", + "//common/ast", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", ], @@ -304,7 +305,6 @@ java_library( "//common", "//common:compiler_common", "//common:mutable_ast", - "//common/ast", "//extensions:optional_library", "//optimizer:ast_optimizer", "//optimizer:mutable_ast", diff --git a/policy/src/main/java/dev/cel/policy/CelCompiledRule.java b/policy/src/main/java/dev/cel/policy/CelCompiledRule.java index 3c5893dfb..a055cc4d3 100644 --- a/policy/src/main/java/dev/cel/policy/CelCompiledRule.java +++ b/policy/src/main/java/dev/cel/policy/CelCompiledRule.java @@ -20,6 +20,8 @@ import dev.cel.bundle.Cel; import dev.cel.common.CelAbstractSyntaxTree; import dev.cel.common.CelVarDecl; +import dev.cel.common.ast.CelConstant; +import dev.cel.common.ast.CelExpr; import java.util.Optional; /** @@ -36,6 +38,28 @@ public abstract class CelCompiledRule { public abstract Cel cel(); + /** + * HasOptionalOutput returns whether the rule returns a concrete or optional value. The rule may + * return an optional value if all match expressions under the rule are conditional. + */ + public boolean hasOptionalOutput() { + boolean isOptionalOutput = false; + for (CelCompiledMatch match : matches()) { + if (match.result().kind().equals(CelCompiledMatch.Result.Kind.RULE) + && match.result().rule().hasOptionalOutput()) { + return true; + } + + if (match.isConditionLiteral()) { + return false; + } + + isOptionalOutput = true; + } + + return isOptionalOutput; + } + /** * A compiled policy variable (ex: variables.foo). Note that this is not the same thing as the * variables declared in the config. @@ -63,6 +87,12 @@ public abstract static class CelCompiledMatch { public abstract Result result(); + public boolean isConditionLiteral() { + CelExpr celExpr = condition().getExpr(); + return celExpr.constantOrDefault().getKind().equals(CelConstant.Kind.BOOLEAN_VALUE) + && celExpr.constant().booleanValue(); + } + /** Encapsulates the result of this match when condition is met. (either an output or a rule) */ @AutoOneOf(CelCompiledMatch.Result.Kind.class) public abstract static class Result { diff --git a/policy/src/main/java/dev/cel/policy/RuleComposer.java b/policy/src/main/java/dev/cel/policy/RuleComposer.java index 42b1b7af2..e53c5f34d 100644 --- a/policy/src/main/java/dev/cel/policy/RuleComposer.java +++ b/policy/src/main/java/dev/cel/policy/RuleComposer.java @@ -24,7 +24,6 @@ import dev.cel.common.CelAbstractSyntaxTree; import dev.cel.common.CelMutableAst; import dev.cel.common.CelValidationException; -import dev.cel.common.ast.CelConstant.Kind; import dev.cel.extensions.CelOptionalLibrary.Function; import dev.cel.optimizer.AstMutator; import dev.cel.optimizer.CelAstOptimizer; @@ -75,10 +74,14 @@ private RuleOptimizationResult optimizeRule(Cel cel, CelCompiledRule compiledRul long lastOutputId = 0; for (CelCompiledMatch match : Lists.reverse(compiledRule.matches())) { CelAbstractSyntaxTree conditionAst = match.condition(); - boolean isTriviallyTrue = - conditionAst.getExpr().constantOrDefault().getKind().equals(Kind.BOOLEAN_VALUE) - && conditionAst.getExpr().constant().booleanValue(); + // If the condition is trivially true, none of the matches in the rule causes the result + // to become optional, and the rule is not the last match, then this will introduce + // unreachable outputs or rules. + boolean isTriviallyTrue = match.isConditionLiteral(); + switch (match.result().kind()) { + // For the match's output, determine whether the output should be wrapped + // into an optional value, a conditional, or both. case OUTPUT: OutputValue matchOutput = match.result().output(); CelMutableAst outAst = CelMutableAst.fromCelAst(matchOutput.ast()); @@ -107,21 +110,25 @@ private RuleOptimizationResult optimizeRule(Cel cel, CelCompiledRule compiledRul lastOutputId = matchOutput.sourceId(); continue; case RULE: + // If the match has a nested rule, then compute the rule and whether it has + // an optional return value. CelCompiledRule matchNestedRule = match.result().rule(); RuleOptimizationResult nestedRule = optimizeRule(cel, matchNestedRule); + boolean nestedHasOptional = matchNestedRule.hasOptionalOutput(); CelMutableAst nestedRuleAst = nestedRule.ast(); - if (isOptionalResult && !nestedRule.isOptionalResult()) { + if (isOptionalResult && !nestedHasOptional) { nestedRuleAst = astMutator.newGlobalCall(Function.OPTIONAL_OF.getFunction(), nestedRuleAst); } - if (!isOptionalResult && nestedRule.isOptionalResult()) { + if (!isOptionalResult && nestedHasOptional) { matchAst = astMutator.newGlobalCall(Function.OPTIONAL_OF.getFunction(), matchAst); isOptionalResult = true; } - if (!isOptionalResult && !nestedRule.isOptionalResult()) { - throw new IllegalArgumentException("Subrule early terminates policy"); - } - if (isTriviallyTrue) { + // If either the nested rule or current condition output are optional then + // use optional.or() to specify the combination of the first and second results + // Note, the argument order is reversed due to the traversal of matches in + // reverse order. + if (isOptionalResult && isTriviallyTrue) { matchAst = astMutator.newMemberCall(nestedRuleAst, Function.OR.getFunction(), matchAst); } else { matchAst = @@ -131,6 +138,7 @@ private RuleOptimizationResult optimizeRule(Cel cel, CelCompiledRule compiledRul nestedRuleAst, matchAst); } + assertComposedAstIsValid( cel, matchAst, diff --git a/policy/src/test/java/dev/cel/policy/PolicyTestHelper.java b/policy/src/test/java/dev/cel/policy/PolicyTestHelper.java index a41f398d1..e0c490f03 100644 --- a/policy/src/test/java/dev/cel/policy/PolicyTestHelper.java +++ b/policy/src/test/java/dev/cel/policy/PolicyTestHelper.java @@ -48,6 +48,26 @@ enum TestYamlPolicy { + "? optional.of({\"banned\": true}) : optional.none()).or(" + "optional.of((resource.origin in variables.permitted_regions)" + " ? {\"banned\": false} : {\"banned\": true})))"), + NESTED_RULE2( + "nested_rule2", + false, + "cel.bind(variables.permitted_regions, [\"us\", \"uk\", \"es\"]," + + " resource.?user.orValue(\"\").startsWith(\"bad\") ?" + + " cel.bind(variables.banned_regions, {\"us\": false, \"ru\": false, \"ir\": false}," + + " (resource.origin in variables.banned_regions && !(resource.origin in" + + " variables.permitted_regions)) ? {\"banned\": \"restricted_region\"} : {\"banned\":" + + " \"bad_actor\"}) : (!(resource.origin in variables.permitted_regions) ? {\"banned\":" + + " \"unconfigured_region\"} : {}))"), + NESTED_RULE3( + "nested_rule3", + true, + "cel.bind(variables.permitted_regions, [\"us\", \"uk\", \"es\"]," + + " resource.?user.orValue(\"\").startsWith(\"bad\") ?" + + " optional.of(cel.bind(variables.banned_regions, {\"us\": false, \"ru\": false," + + " \"ir\": false}, (resource.origin in variables.banned_regions && !(resource.origin" + + " in variables.permitted_regions)) ? {\"banned\": \"restricted_region\"} :" + + " {\"banned\": \"bad_actor\"})) : (!(resource.origin in variables.permitted_regions)" + + " ? optional.of({\"banned\": \"unconfigured_region\"}) : optional.none()))"), REQUIRED_LABELS( "required_labels", true, diff --git a/policy/src/test/resources/nested_rule2/config.yaml b/policy/src/test/resources/nested_rule2/config.yaml new file mode 100644 index 000000000..9ee6f0e49 --- /dev/null +++ b/policy/src/test/resources/nested_rule2/config.yaml @@ -0,0 +1,22 @@ +# Copyright 2024 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. + +name: "nested_rule2" +variables: +- name: "resource" + type: + type_name: "map" + params: + - type_name: "string" + - type_name: "dyn" \ No newline at end of file diff --git a/policy/src/test/resources/nested_rule2/policy.yaml b/policy/src/test/resources/nested_rule2/policy.yaml new file mode 100644 index 000000000..fef91869f --- /dev/null +++ b/policy/src/test/resources/nested_rule2/policy.yaml @@ -0,0 +1,40 @@ +# Copyright 2024 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. + +name: nested_rule2 +rule: + variables: + - name: "permitted_regions" + expression: "['us', 'uk', 'es']" + match: + - condition: resource.?user.orValue("").startsWith("bad") + rule: + id: "banned regions" + description: > + determine whether the resource origin is in the banned + list. If the region is also in the permitted list, the + ban has no effect. + variables: + - name: "banned_regions" + expression: "{'us': false, 'ru': false, 'ir': false}" + match: + - condition: | + resource.origin in variables.banned_regions && + !(resource.origin in variables.permitted_regions) + output: "{'banned': 'restricted_region'}" + explanation: "'resource is in the banned region ' + resource.origin" + - output: "{'banned': 'bad_actor'}" + - condition: "!(resource.origin in variables.permitted_regions)" + output: "{'banned': 'unconfigured_region'}" + - output: "{}" \ No newline at end of file diff --git a/policy/src/test/resources/nested_rule2/tests.yaml b/policy/src/test/resources/nested_rule2/tests.yaml new file mode 100644 index 000000000..b5fbba745 --- /dev/null +++ b/policy/src/test/resources/nested_rule2/tests.yaml @@ -0,0 +1,48 @@ +# Copyright 2024 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. + +description: Nested rule conformance tests +section: +- name: "banned" + tests: + - name: "restricted_origin" + input: + resource: + value: + user: "bad-user" + origin: "ir" + output: "{'banned': 'restricted_region'}" + - name: "by_default" + input: + resource: + value: + user: "bad-user" + origin: "de" + output: "{'banned': 'bad_actor'}" + - name: "unconfigured_region" + input: + resource: + value: + user: "good-user" + origin: "de" + output: "{'banned': 'unconfigured_region'}" +- name: "permitted" + tests: + - name: "valid_origin" + input: + resource: + value: + user: "good-user" + origin: "uk" + output: "{}" \ No newline at end of file diff --git a/policy/src/test/resources/nested_rule3/config.yaml b/policy/src/test/resources/nested_rule3/config.yaml new file mode 100644 index 000000000..d9360d5c9 --- /dev/null +++ b/policy/src/test/resources/nested_rule3/config.yaml @@ -0,0 +1,22 @@ +# Copyright 2024 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. + +name: "nested_rule3" +variables: +- name: "resource" + type: + type_name: "map" + params: + - type_name: "string" + - type_name: "dyn" \ No newline at end of file diff --git a/policy/src/test/resources/nested_rule3/policy.yaml b/policy/src/test/resources/nested_rule3/policy.yaml new file mode 100644 index 000000000..4ad765c8d --- /dev/null +++ b/policy/src/test/resources/nested_rule3/policy.yaml @@ -0,0 +1,39 @@ +# Copyright 2024 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. + +name: nested_rule3 +rule: + variables: + - name: "permitted_regions" + expression: "['us', 'uk', 'es']" + match: + - condition: resource.?user.orValue("").startsWith("bad") + rule: + id: "banned regions" + description: > + determine whether the resource origin is in the banned + list. If the region is also in the permitted list, the + ban has no effect. + variables: + - name: "banned_regions" + expression: "{'us': false, 'ru': false, 'ir': false}" + match: + - condition: | + resource.origin in variables.banned_regions && + !(resource.origin in variables.permitted_regions) + output: "{'banned': 'restricted_region'}" + explanation: "'resource is in the banned region ' + resource.origin" + - output: "{'banned': 'bad_actor'}" + - condition: "!(resource.origin in variables.permitted_regions)" + output: "{'banned': 'unconfigured_region'}" \ No newline at end of file diff --git a/policy/src/test/resources/nested_rule3/tests.yaml b/policy/src/test/resources/nested_rule3/tests.yaml new file mode 100644 index 000000000..b10785d0c --- /dev/null +++ b/policy/src/test/resources/nested_rule3/tests.yaml @@ -0,0 +1,48 @@ +# Copyright 2024 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. + +description: Nested rule conformance tests +section: +- name: "banned" + tests: + - name: "restricted_origin" + input: + resource: + value: + user: "bad-user" + origin: "ir" + output: "{'banned': 'restricted_region'}" + - name: "by_default" + input: + resource: + value: + user: "bad-user" + origin: "de" + output: "{'banned': 'bad_actor'}" + - name: "unconfigured_region" + input: + resource: + value: + user: "good-user" + origin: "de" + output: "{'banned': 'unconfigured_region'}" +- name: "permitted" + tests: + - name: "valid_origin" + input: + resource: + value: + user: "good-user" + origin: "uk" + output: "optional.none()" \ No newline at end of file From 89ea79c14d06146ff088a12f0fd6dd0b0c762ebf Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Wed, 14 Aug 2024 18:08:41 -0700 Subject: [PATCH 178/486] Add unreachable checks in policies PiperOrigin-RevId: 663120461 --- .../java/dev/cel/policy/CelCompiledRule.java | 22 +++++--- .../main/java/dev/cel/policy/CelPolicy.java | 21 +++++--- .../dev/cel/policy/CelPolicyCompilerImpl.java | 34 +++++++++++- .../dev/cel/policy/CelPolicyYamlParser.java | 8 +-- .../java/dev/cel/policy/RuleComposer.java | 4 +- .../cel/policy/CelPolicyCompilerImplTest.java | 3 +- .../resources/errors_unreachable/config.yaml | 54 +++++++++++++++++++ .../expected_errors.baseline | 6 +++ .../resources/errors_unreachable/policy.yaml | 39 ++++++++++++++ 9 files changed, 169 insertions(+), 22 deletions(-) create mode 100644 policy/src/test/resources/errors_unreachable/config.yaml create mode 100644 policy/src/test/resources/errors_unreachable/expected_errors.baseline create mode 100644 policy/src/test/resources/errors_unreachable/policy.yaml diff --git a/policy/src/main/java/dev/cel/policy/CelCompiledRule.java b/policy/src/main/java/dev/cel/policy/CelCompiledRule.java index a055cc4d3..57914232f 100644 --- a/policy/src/main/java/dev/cel/policy/CelCompiledRule.java +++ b/policy/src/main/java/dev/cel/policy/CelCompiledRule.java @@ -30,7 +30,11 @@ */ @AutoValue public abstract class CelCompiledRule { - public abstract Optional id(); + + /** Source metadata identifier associated with the compiled rule. */ + public abstract long sourceId(); + + public abstract Optional ruleId(); public abstract ImmutableList variables(); @@ -50,7 +54,7 @@ public boolean hasOptionalOutput() { return true; } - if (match.isConditionLiteral()) { + if (match.isConditionTriviallyTrue()) { return false; } @@ -83,11 +87,14 @@ static CelCompiledVariable create( /** A compiled Match. */ @AutoValue public abstract static class CelCompiledMatch { + /** Source metadata identifier associated with the compiled match. */ + public abstract long sourceId(); + public abstract CelAbstractSyntaxTree condition(); public abstract Result result(); - public boolean isConditionLiteral() { + public boolean isConditionTriviallyTrue() { CelExpr celExpr = condition().getExpr(); return celExpr.constantOrDefault().getKind().equals(CelConstant.Kind.BOOLEAN_VALUE) && celExpr.constant().booleanValue(); @@ -136,16 +143,17 @@ public static OutputValue create(long id, CelAbstractSyntaxTree ast) { } static CelCompiledMatch create( - CelAbstractSyntaxTree condition, CelCompiledMatch.Result result) { - return new AutoValue_CelCompiledRule_CelCompiledMatch(condition, result); + long sourceId, CelAbstractSyntaxTree condition, CelCompiledMatch.Result result) { + return new AutoValue_CelCompiledRule_CelCompiledMatch(sourceId, condition, result); } } static CelCompiledRule create( - Optional id, + long sourceId, + Optional ruleId, ImmutableList variables, ImmutableList matches, Cel cel) { - return new AutoValue_CelCompiledRule(id, variables, matches, cel); + return new AutoValue_CelCompiledRule(sourceId, ruleId, variables, matches, cel); } } diff --git a/policy/src/main/java/dev/cel/policy/CelPolicy.java b/policy/src/main/java/dev/cel/policy/CelPolicy.java index 0f2f5d1a8..33940c692 100644 --- a/policy/src/main/java/dev/cel/policy/CelPolicy.java +++ b/policy/src/main/java/dev/cel/policy/CelPolicy.java @@ -45,7 +45,7 @@ public abstract class CelPolicy { public static Builder newBuilder() { return new AutoValue_CelPolicy.Builder() .setName(ValueString.of(0, "")) - .setRule(Rule.newBuilder().build()) + .setRule(Rule.newBuilder(0).build()) .setMetadata(ImmutableMap.of()); } @@ -86,8 +86,9 @@ public Builder putMetadata(Map map) { */ @AutoValue public abstract static class Rule { + public abstract long id(); - public abstract Optional id(); + public abstract Optional ruleId(); public abstract Optional description(); @@ -96,8 +97,9 @@ public abstract static class Rule { public abstract ImmutableSet matches(); /** Builder for {@link Rule}. */ - public static Builder newBuilder() { + public static Builder newBuilder(long id) { return new AutoValue_CelPolicy_Rule.Builder() + .setId(id) .setVariables(ImmutableSet.of()) .setMatches(ImmutableSet.of()); } @@ -106,7 +108,7 @@ public static Builder newBuilder() { @AutoValue.Builder public abstract static class Builder { - public abstract Rule.Builder setId(ValueString id); + public abstract Rule.Builder setRuleId(ValueString id); public abstract Rule.Builder setDescription(ValueString description); @@ -118,6 +120,8 @@ public abstract static class Builder { abstract ImmutableSet.Builder matchesBuilder(); + abstract Builder setId(long value); + @CanIgnoreReturnValue public Builder addVariables(Variable... variables) { return addVariables(Arrays.asList(variables)); @@ -159,6 +163,8 @@ public abstract static class Match { public abstract Result result(); + public abstract long id(); + /** Explanation returns the explanation expression, or empty expression if output is not set. */ public abstract Optional explanation(); @@ -189,6 +195,7 @@ public enum Kind { /** Builder for {@link Match}. */ @AutoValue.Builder public abstract static class Builder implements RequiredFieldsChecker { + public abstract Builder setId(long value); public abstract Builder setCondition(ValueString condition); @@ -196,6 +203,8 @@ public abstract static class Builder implements RequiredFieldsChecker { public abstract Builder setExplanation(ValueString explanation); + abstract Optional id(); + abstract Optional result(); abstract Optional explanation(); @@ -209,8 +218,8 @@ public ImmutableList requiredFields() { } /** Creates a new builder to construct a {@link Match} instance. */ - public static Builder newBuilder() { - return new AutoValue_CelPolicy_Match.Builder(); + public static Builder newBuilder(long id) { + return new AutoValue_CelPolicy_Match.Builder().setId(id); } } diff --git a/policy/src/main/java/dev/cel/policy/CelPolicyCompilerImpl.java b/policy/src/main/java/dev/cel/policy/CelPolicyCompilerImpl.java index 8ca38dad4..b7d1377b1 100644 --- a/policy/src/main/java/dev/cel/policy/CelPolicyCompilerImpl.java +++ b/policy/src/main/java/dev/cel/policy/CelPolicyCompilerImpl.java @@ -35,6 +35,7 @@ import dev.cel.optimizer.CelOptimizerFactory; import dev.cel.policy.CelCompiledRule.CelCompiledMatch; import dev.cel.policy.CelCompiledRule.CelCompiledMatch.Result; +import dev.cel.policy.CelCompiledRule.CelCompiledMatch.Result.Kind; import dev.cel.policy.CelCompiledRule.CelCompiledVariable; import dev.cel.policy.CelPolicy.Match; import dev.cel.policy.CelPolicy.Variable; @@ -167,10 +168,39 @@ private CelCompiledRule compileRuleImpl( throw new IllegalArgumentException("Unexpected kind: " + match.result().kind()); } - matchBuilder.add(CelCompiledMatch.create(conditionAst, matchResult)); + matchBuilder.add(CelCompiledMatch.create(match.id(), conditionAst, matchResult)); } - return CelCompiledRule.create(rule.id(), variableBuilder.build(), matchBuilder.build(), cel); + CelCompiledRule compiledRule = + CelCompiledRule.create( + rule.id(), rule.ruleId(), variableBuilder.build(), matchBuilder.build(), cel); + + // Validate that all branches in the policy are reachable + checkUnreachableCode(compiledRule, compilerContext); + + return compiledRule; + } + + private void checkUnreachableCode(CelCompiledRule compiledRule, CompilerContext compilerContext) { + boolean ruleHasOptional = compiledRule.hasOptionalOutput(); + ImmutableList compiledMatches = compiledRule.matches(); + int matchCount = compiledMatches.size(); + for (int i = matchCount - 1; i >= 0; i--) { + CelCompiledMatch compiledMatch = compiledMatches.get(i); + boolean isTriviallyTrue = compiledMatch.isConditionTriviallyTrue(); + + if (isTriviallyTrue && !ruleHasOptional && i != matchCount - 1) { + if (compiledMatch.result().kind().equals(Kind.OUTPUT)) { + compilerContext.addIssue( + compiledMatch.sourceId(), + CelIssue.formatError(1, 0, "Match creates unreachable outputs")); + } else { + compilerContext.addIssue( + compiledMatch.result().rule().sourceId(), + CelIssue.formatError(1, 0, "Rule creates unreachable outputs")); + } + } + } } private static CelAbstractSyntaxTree newErrorAst() { diff --git a/policy/src/main/java/dev/cel/policy/CelPolicyYamlParser.java b/policy/src/main/java/dev/cel/policy/CelPolicyYamlParser.java index 1327fbcef..318f44fbc 100644 --- a/policy/src/main/java/dev/cel/policy/CelPolicyYamlParser.java +++ b/policy/src/main/java/dev/cel/policy/CelPolicyYamlParser.java @@ -40,7 +40,7 @@ final class CelPolicyYamlParser implements CelPolicyParser { // Sentinel values for parsing errors private static final ValueString ERROR_VALUE = ValueString.newBuilder().setValue(ERROR).build(); private static final Match ERROR_MATCH = - Match.newBuilder().setCondition(ERROR_VALUE).setResult(Result.ofOutput(ERROR_VALUE)).build(); + Match.newBuilder(0).setCondition(ERROR_VALUE).setResult(Result.ofOutput(ERROR_VALUE)).build(); private static final Variable ERROR_VARIABLE = Variable.newBuilder().setExpression(ERROR_VALUE).setName(ERROR_VALUE).build(); @@ -122,7 +122,7 @@ public CelPolicy parsePolicy(PolicyParserContext ctx, Node node) { public CelPolicy.Rule parseRule( PolicyParserContext ctx, CelPolicy.Builder policyBuilder, Node node) { long valueId = ctx.collectMetadata(node); - CelPolicy.Rule.Builder ruleBuilder = CelPolicy.Rule.newBuilder(); + CelPolicy.Rule.Builder ruleBuilder = CelPolicy.Rule.newBuilder(valueId); if (!assertYamlType(ctx, valueId, node, YamlNodeType.MAP)) { return ruleBuilder.build(); } @@ -137,7 +137,7 @@ public CelPolicy.Rule parseRule( Node value = nodeTuple.getValueNode(); switch (fieldName) { case "id": - ruleBuilder.setId(ctx.newValueString(value)); + ruleBuilder.setRuleId(ctx.newValueString(value)); break; case "description": ruleBuilder.setDescription(ctx.newValueString(value)); @@ -181,7 +181,7 @@ public CelPolicy.Match parseMatch( } MappingNode matchNode = (MappingNode) node; CelPolicy.Match.Builder matchBuilder = - CelPolicy.Match.newBuilder().setCondition(ValueString.of(ctx.nextId(), "true")); + CelPolicy.Match.newBuilder(nodeId).setCondition(ValueString.of(ctx.nextId(), "true")); for (NodeTuple nodeTuple : matchNode.getValue()) { Node key = nodeTuple.getKeyNode(); long tagId = ctx.collectMetadata(key); diff --git a/policy/src/main/java/dev/cel/policy/RuleComposer.java b/policy/src/main/java/dev/cel/policy/RuleComposer.java index e53c5f34d..814dc8f8a 100644 --- a/policy/src/main/java/dev/cel/policy/RuleComposer.java +++ b/policy/src/main/java/dev/cel/policy/RuleComposer.java @@ -77,7 +77,7 @@ private RuleOptimizationResult optimizeRule(Cel cel, CelCompiledRule compiledRul // If the condition is trivially true, none of the matches in the rule causes the result // to become optional, and the rule is not the last match, then this will introduce // unreachable outputs or rules. - boolean isTriviallyTrue = match.isConditionLiteral(); + boolean isTriviallyTrue = match.isConditionTriviallyTrue(); switch (match.result().kind()) { // For the match's output, determine whether the output should be wrapped @@ -144,7 +144,7 @@ private RuleOptimizationResult optimizeRule(Cel cel, CelCompiledRule compiledRul matchAst, String.format( "failed composing the subrule '%s' due to conflicting output types.", - matchNestedRule.id().map(ValueString::value).orElse("")), + matchNestedRule.ruleId().map(ValueString::value).orElse("")), lastOutputId); break; } diff --git a/policy/src/test/java/dev/cel/policy/CelPolicyCompilerImplTest.java b/policy/src/test/java/dev/cel/policy/CelPolicyCompilerImplTest.java index 30915be4a..7d4bb85d1 100644 --- a/policy/src/test/java/dev/cel/policy/CelPolicyCompilerImplTest.java +++ b/policy/src/test/java/dev/cel/policy/CelPolicyCompilerImplTest.java @@ -308,7 +308,8 @@ private enum MultilineErrorTest { private enum TestErrorYamlPolicy { COMPILE_ERRORS("compile_errors"), COMPOSE_ERRORS_CONFLICTING_OUTPUT("compose_errors_conflicting_output"), - COMPOSE_ERRORS_CONFLICTING_SUBRULE("compose_errors_conflicting_subrule"); + COMPOSE_ERRORS_CONFLICTING_SUBRULE("compose_errors_conflicting_subrule"), + ERRORS_UNREACHABLE("errors_unreachable"); private final String name; private final String policyFilePath; diff --git a/policy/src/test/resources/errors_unreachable/config.yaml b/policy/src/test/resources/errors_unreachable/config.yaml new file mode 100644 index 000000000..8f79bb763 --- /dev/null +++ b/policy/src/test/resources/errors_unreachable/config.yaml @@ -0,0 +1,54 @@ +# Copyright 2024 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. + +name: "errors_unreachable" +extensions: +- name: "sets" +- name: "strings" + version: "latest" +variables: +- name: "destination.ip" + type: + type_name: "string" +- name: "origin.ip" + type: + type_name: "string" +- name: "spec.restricted_destinations" + type: + type_name: "list" + params: + - type_name: "string" +- name: "spec.origin" + type: + type_name: "string" +- name: "request" + type: + type_name: "map" + params: + - type_name: "string" + - type_name: "dyn" +- name: "resource" + type: + type_name: "map" + params: + - type_name: "string" + - type_name: "dyn" +functions: +- name: "locationCode" + overloads: + - id: "locationCode_string" + args: + - type_name: "string" + return: + type_name: "string" diff --git a/policy/src/test/resources/errors_unreachable/expected_errors.baseline b/policy/src/test/resources/errors_unreachable/expected_errors.baseline new file mode 100644 index 000000000..f5f24acbe --- /dev/null +++ b/policy/src/test/resources/errors_unreachable/expected_errors.baseline @@ -0,0 +1,6 @@ +ERROR: errors_unreachable/policy.yaml:36:9: Match creates unreachable outputs + | - output: | + | ........^ +ERROR: errors_unreachable/policy.yaml:28:7: Rule creates unreachable outputs + | match: + | ......^ \ No newline at end of file diff --git a/policy/src/test/resources/errors_unreachable/policy.yaml b/policy/src/test/resources/errors_unreachable/policy.yaml new file mode 100644 index 000000000..f43fd62c7 --- /dev/null +++ b/policy/src/test/resources/errors_unreachable/policy.yaml @@ -0,0 +1,39 @@ +# Copyright 2024 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. + +name: "errors_unreachable" +rule: + variables: + - name: want + expression: request.labels + - name: missing + expression: variables.want.filter(l, !(l in resource.labels)) + - name: invalid + expression: > + resource.labels.filter(l, + l in variables.want && variables.want[l] != resource.labels[l]) + match: + - rule: + match: + - output: "''" + - condition: variables.missing.size() > 0 + output: | + "missing one or more required labels: [\"" + variables.missing.join(',') + "\"]" + - condition: variables.invalid.size() > 0 + rule: + match: + - output: | + "invalid values provided on one or more labels: [\"" + variables.invalid.join(',') + "\"]" + - condition: "false" + output: "'unreachable'" From 12d777fda94c6cf63a547ff360c42c39b5583f46 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Wed, 14 Aug 2024 19:45:09 -0700 Subject: [PATCH 179/486] Add a validator for enforcing AST depth limit PiperOrigin-RevId: 663141870 --- .../validators/AstDepthLimitValidator.java | 69 +++++++++++ .../dev/cel/validator/validators/BUILD.bazel | 15 +++ .../AstDepthLimitValidatorTest.java | 112 ++++++++++++++++++ .../dev/cel/validator/validators/BUILD.bazel | 2 + validator/validators/BUILD.bazel | 5 + 5 files changed, 203 insertions(+) create mode 100644 validator/src/main/java/dev/cel/validator/validators/AstDepthLimitValidator.java create mode 100644 validator/src/test/java/dev/cel/validator/validators/AstDepthLimitValidatorTest.java diff --git a/validator/src/main/java/dev/cel/validator/validators/AstDepthLimitValidator.java b/validator/src/main/java/dev/cel/validator/validators/AstDepthLimitValidator.java new file mode 100644 index 000000000..c255624e5 --- /dev/null +++ b/validator/src/main/java/dev/cel/validator/validators/AstDepthLimitValidator.java @@ -0,0 +1,69 @@ +// Copyright 2024 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.validator.validators; + +import static com.google.common.base.Preconditions.checkArgument; + +import dev.cel.bundle.Cel; +import dev.cel.common.navigation.CelNavigableAst; +import dev.cel.validator.CelAstValidator; + +/** Enforces a compiled AST to stay below the configured depth limit. */ +public final class AstDepthLimitValidator implements CelAstValidator { + + // Protobuf imposes a default parse-depth limit of 100. We set it to half here because navigable + // expr does not include operands in the depth calculation. + // As an example, an expression 'x.y' has a depth of 2 in NavigableExpr, but the ParsedExpr has a + // depth of 4 as illustrated below: + // + // expr { + // id: 2 + // select_expr { + // operand { + // id: 1 + // ident_expr { + // name: "x" + // } + // } + // field: "y" + // } + // } + static final int DEFAULT_DEPTH_LIMIT = 50; + + public static final AstDepthLimitValidator DEFAULT = newInstance(DEFAULT_DEPTH_LIMIT); + private final int maxDepth; + + /** + * Constructs a new instance of {@link AstDepthLimitValidator} with the configured maxDepth as its + * limit. + */ + public static AstDepthLimitValidator newInstance(int maxDepth) { + checkArgument(maxDepth > 0); + return new AstDepthLimitValidator(maxDepth); + } + + @Override + public void validate(CelNavigableAst navigableAst, Cel cel, IssuesFactory issuesFactory) { + if (navigableAst.getRoot().height() >= maxDepth) { + issuesFactory.addError( + navigableAst.getRoot().id(), + String.format("AST's depth exceeds the configured limit: %s.", maxDepth)); + } + } + + private AstDepthLimitValidator(int maxDepth) { + this.maxDepth = maxDepth; + } +} diff --git a/validator/src/main/java/dev/cel/validator/validators/BUILD.bazel b/validator/src/main/java/dev/cel/validator/validators/BUILD.bazel index d049a3659..3362f14be 100644 --- a/validator/src/main/java/dev/cel/validator/validators/BUILD.bazel +++ b/validator/src/main/java/dev/cel/validator/validators/BUILD.bazel @@ -67,6 +67,21 @@ java_library( ], ) +java_library( + name = "ast_depth_limit_validator", + srcs = [ + "AstDepthLimitValidator.java", + ], + tags = [ + ], + deps = [ + "//bundle:cel", + "//common/navigation", + "//validator:ast_validator", + "@maven//:com_google_guava_guava", + ], +) + java_library( name = "literal_validator", srcs = [ diff --git a/validator/src/test/java/dev/cel/validator/validators/AstDepthLimitValidatorTest.java b/validator/src/test/java/dev/cel/validator/validators/AstDepthLimitValidatorTest.java new file mode 100644 index 000000000..acc2544c7 --- /dev/null +++ b/validator/src/test/java/dev/cel/validator/validators/AstDepthLimitValidatorTest.java @@ -0,0 +1,112 @@ +// Copyright 2024 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.validator.validators; + +import static com.google.common.truth.Truth.assertThat; +import static dev.cel.common.CelFunctionDecl.newFunctionDeclaration; +import static dev.cel.common.CelOverloadDecl.newGlobalOverload; +import static dev.cel.validator.validators.AstDepthLimitValidator.DEFAULT_DEPTH_LIMIT; +import static org.junit.Assert.assertThrows; + +import dev.cel.expr.CheckedExpr; +import com.google.protobuf.ByteString; +import com.google.protobuf.ExtensionRegistryLite; +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.testing.junit.testparameterinjector.TestParameter; +import com.google.testing.junit.testparameterinjector.TestParameterInjector; +import dev.cel.bundle.Cel; +import dev.cel.bundle.CelFactory; +import dev.cel.common.CelAbstractSyntaxTree; +import dev.cel.common.CelIssue.Severity; +import dev.cel.common.CelProtoAbstractSyntaxTree; +import dev.cel.common.CelValidationResult; +import dev.cel.common.types.SimpleType; +import dev.cel.validator.CelValidator; +import dev.cel.validator.CelValidatorFactory; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(TestParameterInjector.class) +public class AstDepthLimitValidatorTest { + + private static final Cel CEL = + CelFactory.standardCelBuilder() + .addVar("x", SimpleType.DYN) + .addFunctionDeclarations( + newFunctionDeclaration( + "f", newGlobalOverload("f_int64", SimpleType.INT, SimpleType.INT))) + .build(); + + private static final CelValidator CEL_VALIDATOR = + CelValidatorFactory.standardCelValidatorBuilder(CEL) + .addAstValidators(AstDepthLimitValidator.DEFAULT) + .build(); + + private enum DefaultTestCase { + NESTED_SELECTS( + "x.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y"), + NESTED_CALCS( + "0+1+2+3+4+5+6+7+8+9+10+11+12+13+14+15+16+17+18+19+20+21+22+23+24+25+26+27+28+29+30+31+32+33+34+35+36+37+38+39+40+41+42+43+44+45+46+47+48+49+50"), + NESTED_FUNCS( + "f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(0)))))))))))))))))))))))))))))))))))))))))))))))))))"); + + private final String expression; + + DefaultTestCase(String expression) { + this.expression = expression; + } + } + + @Test + public void astExceedsDefaultDepthLimit_populatesErrors(@TestParameter DefaultTestCase testCase) + throws Exception { + CelAbstractSyntaxTree ast = CEL.compile(testCase.expression).getAst(); + + CelValidationResult result = CEL_VALIDATOR.validate(ast); + + assertThat(result.hasError()).isTrue(); + assertThat(result.getAllIssues()).hasSize(1); + assertThat(result.getAllIssues().get(0).getSeverity()).isEqualTo(Severity.ERROR); + assertThat(result.getAllIssues().get(0).toDisplayString(ast.getSource())) + .contains("AST's depth exceeds the configured limit: 50."); + assertThrows(InvalidProtocolBufferException.class, () -> verifyProtoAstRoundTrips(ast)); + } + + @Test + public void astIsUnderDepthLimit_noErrors() throws Exception { + StringBuilder sb = new StringBuilder().append("x"); + for (int i = 0; i < DEFAULT_DEPTH_LIMIT - 1; i++) { + sb.append(".y"); + } + // Depth level of 49 + CelAbstractSyntaxTree ast = CEL.compile(sb.toString()).getAst(); + + CelValidationResult result = CEL_VALIDATOR.validate(ast); + + assertThat(result.hasError()).isFalse(); + assertThat(result.getAllIssues()).isEmpty(); + verifyProtoAstRoundTrips(ast); + } + + private void verifyProtoAstRoundTrips(CelAbstractSyntaxTree ast) throws Exception { + CheckedExpr checkedExpr = CelProtoAbstractSyntaxTree.fromCelAst(ast).toCheckedExpr(); + ByteString serialized = checkedExpr.toByteString(); + CheckedExpr deserializedCheckedExpr = + CheckedExpr.parseFrom(serialized, ExtensionRegistryLite.getEmptyRegistry()); + if (!checkedExpr.equals(deserializedCheckedExpr)) { + throw new IllegalStateException("Expected checked expressions to round trip!"); + } + } +} diff --git a/validator/src/test/java/dev/cel/validator/validators/BUILD.bazel b/validator/src/test/java/dev/cel/validator/validators/BUILD.bazel index 1f8af4661..a04ee6d1e 100644 --- a/validator/src/test/java/dev/cel/validator/validators/BUILD.bazel +++ b/validator/src/test/java/dev/cel/validator/validators/BUILD.bazel @@ -17,11 +17,13 @@ java_library( "//runtime", "//validator", "//validator:validator_builder", + "//validator/validators:ast_depth_limit_validator", "//validator/validators:duration", "//validator/validators:homogeneous_literal", "//validator/validators:regex", "//validator/validators:timestamp", "@@protobuf~//java/core", + "@cel_spec//proto/cel/expr:expr_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java_util", "@maven//:com_google_testparameterinjector_test_parameter_injector", diff --git a/validator/validators/BUILD.bazel b/validator/validators/BUILD.bazel index e4f9ea54b..a34f03049 100644 --- a/validator/validators/BUILD.bazel +++ b/validator/validators/BUILD.bazel @@ -22,3 +22,8 @@ java_library( name = "homogeneous_literal", exports = ["//validator/src/main/java/dev/cel/validator/validators:homogeneous_literal"], ) + +java_library( + name = "ast_depth_limit_validator", + exports = ["//validator/src/main/java/dev/cel/validator/validators:ast_depth_limit_validator"], +) From 80baca4ff2f4960401013e8831632ae8b3d7f2a3 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Thu, 15 Aug 2024 10:40:18 -0700 Subject: [PATCH 180/486] Enforce composed AST stays below the configured depth limit PiperOrigin-RevId: 663361547 --- .../src/main/java/dev/cel/policy/BUILD.bazel | 4 ++ .../cel/policy/CelPolicyCompilerBuilder.java | 7 +++ .../dev/cel/policy/CelPolicyCompilerImpl.java | 49 +++++++++++++++++-- .../cel/policy/CelPolicyCompilerImplTest.java | 36 ++++++++++++++ .../dev/cel/validator/CelAstValidator.java | 10 +++- 5 files changed, 101 insertions(+), 5 deletions(-) diff --git a/policy/src/main/java/dev/cel/policy/BUILD.bazel b/policy/src/main/java/dev/cel/policy/BUILD.bazel index ea3f4353c..bdb651d0d 100644 --- a/policy/src/main/java/dev/cel/policy/BUILD.bazel +++ b/policy/src/main/java/dev/cel/policy/BUILD.bazel @@ -257,6 +257,10 @@ java_library( "//optimizer", "//optimizer:optimization_exception", "//optimizer:optimizer_builder", + "//validator", + "//validator:ast_validator", + "//validator:validator_builder", + "//validator/validators:ast_depth_limit_validator", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", ], diff --git a/policy/src/main/java/dev/cel/policy/CelPolicyCompilerBuilder.java b/policy/src/main/java/dev/cel/policy/CelPolicyCompilerBuilder.java index 13bac2885..592a0120d 100644 --- a/policy/src/main/java/dev/cel/policy/CelPolicyCompilerBuilder.java +++ b/policy/src/main/java/dev/cel/policy/CelPolicyCompilerBuilder.java @@ -31,6 +31,13 @@ public interface CelPolicyCompilerBuilder { @CanIgnoreReturnValue CelPolicyCompilerBuilder setIterationLimit(int iterationLimit); + /** + * Enforces the composed AST to stay below the configured depth limit. An exception is thrown if + * the depth exceeds the configured limit. Setting a negative value disables this check. + */ + @CanIgnoreReturnValue + CelPolicyCompilerBuilder setAstDepthLimit(int iterationLimit); + @CheckReturnValue CelPolicyCompiler build(); } diff --git a/policy/src/main/java/dev/cel/policy/CelPolicyCompilerImpl.java b/policy/src/main/java/dev/cel/policy/CelPolicyCompilerImpl.java index b7d1377b1..ca1be9f46 100644 --- a/policy/src/main/java/dev/cel/policy/CelPolicyCompilerImpl.java +++ b/policy/src/main/java/dev/cel/policy/CelPolicyCompilerImpl.java @@ -25,6 +25,7 @@ import dev.cel.common.CelSource; import dev.cel.common.CelSourceLocation; import dev.cel.common.CelValidationException; +import dev.cel.common.CelValidationResult; import dev.cel.common.CelVarDecl; import dev.cel.common.ast.CelConstant; import dev.cel.common.ast.CelExpr; @@ -40,6 +41,10 @@ import dev.cel.policy.CelPolicy.Match; import dev.cel.policy.CelPolicy.Variable; import dev.cel.policy.RuleComposer.RuleCompositionException; +import dev.cel.validator.CelAstValidator; +import dev.cel.validator.CelValidator; +import dev.cel.validator.CelValidatorFactory; +import dev.cel.validator.validators.AstDepthLimitValidator; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -52,6 +57,7 @@ final class CelPolicyCompilerImpl implements CelPolicyCompiler { private final Cel cel; private final String variablesPrefix; private final int iterationLimit; + private final Optional astDepthValidator; @Override public CelCompiledRule compileRule(CelPolicy policy) throws CelPolicyValidationException { @@ -67,8 +73,9 @@ public CelCompiledRule compileRule(CelPolicy policy) throws CelPolicyValidationE @Override public CelAbstractSyntaxTree compose(CelPolicy policy, CelCompiledRule compiledRule) throws CelPolicyValidationException { + Cel cel = compiledRule.cel(); CelOptimizer optimizer = - CelOptimizerFactory.standardCelOptimizerBuilder(compiledRule.cel()) + CelOptimizerFactory.standardCelOptimizerBuilder(cel) .addAstOptimizers( RuleComposer.newInstance(compiledRule, variablesPrefix, iterationLimit)) .build(); @@ -105,9 +112,26 @@ public CelAbstractSyntaxTree compose(CelPolicy policy, CelCompiledRule compiledR throw new CelPolicyValidationException("Unexpected error while composing rules.", e); } + assertAstDepthIsSafe(ast, cel); + return ast; } + private void assertAstDepthIsSafe(CelAbstractSyntaxTree ast, Cel cel) + throws CelPolicyValidationException { + if (!astDepthValidator.isPresent()) { + return; + } + CelValidator celValidator = + CelValidatorFactory.standardCelValidatorBuilder(cel) + .addAstValidators(astDepthValidator.get()) + .build(); + CelValidationResult result = celValidator.validate(ast); + if (result.hasError()) { + throw new CelPolicyValidationException(result.getErrorString()); + } + } + private CelCompiledRule compileRuleImpl( CelPolicy.Rule rule, Cel ruleCel, CompilerContext compilerContext) { ImmutableList.Builder variableBuilder = ImmutableList.builder(); @@ -262,9 +286,11 @@ static final class Builder implements CelPolicyCompilerBuilder { private final Cel cel; private String variablesPrefix; private int iterationLimit; + private Optional astDepthLimitValidator; private Builder(Cel cel) { this.cel = cel; + this.astDepthLimitValidator = Optional.of(AstDepthLimitValidator.DEFAULT); } @Override @@ -281,9 +307,21 @@ public Builder setIterationLimit(int iterationLimit) { return this; } + @Override + @CanIgnoreReturnValue + public CelPolicyCompilerBuilder setAstDepthLimit(int astDepthLimit) { + if (astDepthLimit < 0) { + astDepthLimitValidator = Optional.empty(); + } else { + astDepthLimitValidator = Optional.of(AstDepthLimitValidator.newInstance(astDepthLimit)); + } + return this; + } + @Override public CelPolicyCompiler build() { - return new CelPolicyCompilerImpl(cel, this.variablesPrefix, this.iterationLimit); + return new CelPolicyCompilerImpl( + cel, this.variablesPrefix, this.iterationLimit, astDepthLimitValidator); } } @@ -293,9 +331,14 @@ static Builder newBuilder(Cel cel) { .setIterationLimit(DEFAULT_ITERATION_LIMIT); } - private CelPolicyCompilerImpl(Cel cel, String variablesPrefix, int iterationLimit) { + private CelPolicyCompilerImpl( + Cel cel, + String variablesPrefix, + int iterationLimit, + Optional astDepthValidator) { this.cel = checkNotNull(cel); this.variablesPrefix = checkNotNull(variablesPrefix); this.iterationLimit = iterationLimit; + this.astDepthValidator = astDepthValidator; } } diff --git a/policy/src/test/java/dev/cel/policy/CelPolicyCompilerImplTest.java b/policy/src/test/java/dev/cel/policy/CelPolicyCompilerImplTest.java index 7d4bb85d1..bf435f90a 100644 --- a/policy/src/test/java/dev/cel/policy/CelPolicyCompilerImplTest.java +++ b/policy/src/test/java/dev/cel/policy/CelPolicyCompilerImplTest.java @@ -105,6 +105,42 @@ public void compileYamlPolicy_multilineContainsError_throws( assertThat(e).hasMessageThat().isEqualTo(testCase.expected); } + @Test + public void compileYamlPolicy_exceedsDefaultAstDepthLimit_throws() throws Exception { + String longExpr = + "0+1+2+3+4+5+6+7+8+9+10+11+12+13+14+15+16+17+18+19+20+21+22+23+24+25+26+27+28+29+30+31+32+33+34+35+36+37+38+39+40+41+42+43+44+45+46+47+48+49+50"; + String policyContent = + String.format( + "name: deeply_nested_ast\n" + "rule:\n" + " match:\n" + " - output: %s", longExpr); + CelPolicy policy = POLICY_PARSER.parse(policyContent); + + CelPolicyValidationException e = + assertThrows( + CelPolicyValidationException.class, + () -> CelPolicyCompilerFactory.newPolicyCompiler(newCel()).build().compile(policy)); + + assertThat(e) + .hasMessageThat() + .isEqualTo("ERROR: :-1:0: AST's depth exceeds the configured limit: 50."); + } + + @Test + public void compileYamlPolicy_astDepthLimitCheckDisabled_doesNotThrow() throws Exception { + String longExpr = + "0+1+2+3+4+5+6+7+8+9+10+11+12+13+14+15+16+17+18+19+20+21+22+23+24+25+26+27+28+29+30+31+32+33+34+35+36+37+38+39+40+41+42+43+44+45+46+47+48+49+50"; + String policyContent = + String.format( + "name: deeply_nested_ast\n" + "rule:\n" + " match:\n" + " - output: %s", longExpr); + CelPolicy policy = POLICY_PARSER.parse(policyContent); + + CelAbstractSyntaxTree ast = + CelPolicyCompilerFactory.newPolicyCompiler(newCel()) + .setAstDepthLimit(-1) + .build() + .compile(policy); + assertThat(ast).isNotNull(); + } + @Test @SuppressWarnings("unchecked") public void evaluateYamlPolicy_withCanonicalTestData( diff --git a/validator/src/main/java/dev/cel/validator/CelAstValidator.java b/validator/src/main/java/dev/cel/validator/CelAstValidator.java index ca316019a..d3b046686 100644 --- a/validator/src/main/java/dev/cel/validator/CelAstValidator.java +++ b/validator/src/main/java/dev/cel/validator/CelAstValidator.java @@ -19,7 +19,9 @@ import dev.cel.common.CelIssue; import dev.cel.common.CelIssue.Severity; import dev.cel.common.CelSource; +import dev.cel.common.CelSourceLocation; import dev.cel.common.navigation.CelNavigableAst; +import java.util.Optional; /** Public interface for performing a single, custom validation on an AST. */ public interface CelAstValidator { @@ -53,12 +55,16 @@ public void addInfo(long exprId, String message) { private void add(long exprId, String message, Severity severity) { CelSource source = navigableAst.getAst().getSource(); - int position = source.getPositionsMap().get(exprId); + int position = Optional.ofNullable(source.getPositionsMap().get(exprId)).orElse(-1); + CelSourceLocation sourceLocation = CelSourceLocation.NONE; + if (position >= 0) { + sourceLocation = source.getOffsetLocation(position).get(); + } issuesBuilder.add( CelIssue.newBuilder() .setSeverity(severity) .setMessage(message) - .setSourceLocation(source.getOffsetLocation(position).get()) + .setSourceLocation(sourceLocation) .build()); } From c1a05d69a72acec9f5c75bcd02f35ecf90593729 Mon Sep 17 00:00:00 2001 From: Justin King Date: Fri, 16 Aug 2024 10:03:58 -0700 Subject: [PATCH 181/486] Add a test case showing adjacent comprehensions PiperOrigin-RevId: 663765762 --- .../SubexpressionOptimizerBaselineTest.java | 2 + ...old_before_subexpression_unparsed.baseline | 16 ++ ...ion_ast_block_common_subexpr_only.baseline | 190 ++++++++++++++++ ...ssion_ast_block_recursion_depth_1.baseline | 208 +++++++++++++++++ ...ssion_ast_block_recursion_depth_2.baseline | 214 ++++++++++++++++++ ...ssion_ast_block_recursion_depth_3.baseline | 202 +++++++++++++++++ ...ssion_ast_block_recursion_depth_4.baseline | 196 ++++++++++++++++ ...ssion_ast_block_recursion_depth_5.baseline | 196 ++++++++++++++++ ...ssion_ast_block_recursion_depth_6.baseline | 196 ++++++++++++++++ ...ssion_ast_block_recursion_depth_7.baseline | 196 ++++++++++++++++ ...ssion_ast_block_recursion_depth_8.baseline | 190 ++++++++++++++++ ...ssion_ast_block_recursion_depth_9.baseline | 190 ++++++++++++++++ .../subexpression_ast_cascaded_binds.baseline | 203 +++++++++++++++++ .../resources/subexpression_unparsed.baseline | 16 ++ 14 files changed, 2215 insertions(+) diff --git a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerBaselineTest.java b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerBaselineTest.java index f5a1c4086..2cb3df813 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerBaselineTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerBaselineTest.java @@ -461,6 +461,8 @@ private enum CseTestCase { + " 1)"), NESTED_MACROS("[1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [[2, 3, 4], [2, 3, 4], [2, 3, 4]]"), NESTED_MACROS_2("[1, 2].map(y, [1, 2, 3].filter(x, x == y)) == [[1], [2]]"), + ADJACENT_NESTED_MACROS( + "[1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [1,2,3].map(j, [1, 2, 3].map(j, j + 1))"), INCLUSION_LIST("1 in [1,2,3] && 2 in [1,2,3] && 3 in [3, [1,2,3]] && 1 in [1,2,3]"), INCLUSION_MAP("2 in {'a': 1, 2: {true: false}, 3: {true: false}}"), MACRO_ITER_VAR_NOT_REFERENCED( diff --git a/optimizer/src/test/resources/constfold_before_subexpression_unparsed.baseline b/optimizer/src/test/resources/constfold_before_subexpression_unparsed.baseline index b18460018..897b4d775 100644 --- a/optimizer/src/test/resources/constfold_before_subexpression_unparsed.baseline +++ b/optimizer/src/test/resources/constfold_before_subexpression_unparsed.baseline @@ -350,6 +350,22 @@ Result: true [BLOCK_RECURSION_DEPTH_8]: true [BLOCK_RECURSION_DEPTH_9]: true +Test case: ADJACENT_NESTED_MACROS +Source: [1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [1,2,3].map(j, [1, 2, 3].map(j, j + 1)) +=====> +Result: true +[CASCADED_BINDS]: true +[BLOCK_COMMON_SUBEXPR_ONLY]: true +[BLOCK_RECURSION_DEPTH_1]: true +[BLOCK_RECURSION_DEPTH_2]: true +[BLOCK_RECURSION_DEPTH_3]: true +[BLOCK_RECURSION_DEPTH_4]: true +[BLOCK_RECURSION_DEPTH_5]: true +[BLOCK_RECURSION_DEPTH_6]: true +[BLOCK_RECURSION_DEPTH_7]: true +[BLOCK_RECURSION_DEPTH_8]: true +[BLOCK_RECURSION_DEPTH_9]: true + Test case: INCLUSION_LIST Source: 1 in [1,2,3] && 2 in [1,2,3] && 3 in [3, [1,2,3]] && 1 in [1,2,3] =====> diff --git a/optimizer/src/test/resources/subexpression_ast_block_common_subexpr_only.baseline b/optimizer/src/test/resources/subexpression_ast_block_common_subexpr_only.baseline index c1ad64871..d2267c0d8 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_common_subexpr_only.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_common_subexpr_only.baseline @@ -2151,6 +2151,196 @@ CALL [31] { } } } +Test case: ADJACENT_NESTED_MACROS +Source: [1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [1,2,3].map(j, [1, 2, 3].map(j, j + 1)) +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + CONSTANT [6] { value: 3 } + } + } + } + } + CALL [7] { + function: _==_ + args: { + COMPREHENSION [8] { + iter_var: @c:1 + iter_range: { + IDENT [9] { + name: @index0 + } + } + accu_var: @x:1 + accu_init: { + LIST [10] { + elements: { + } + } + } + loop_condition: { + CONSTANT [11] { value: true } + } + loop_step: { + CALL [12] { + function: _+_ + args: { + IDENT [13] { + name: @x:1 + } + LIST [14] { + elements: { + COMPREHENSION [15] { + iter_var: @c:0 + iter_range: { + IDENT [16] { + name: @index0 + } + } + accu_var: @x:0 + accu_init: { + LIST [17] { + elements: { + } + } + } + loop_condition: { + CONSTANT [18] { value: true } + } + loop_step: { + CALL [19] { + function: _+_ + args: { + IDENT [20] { + name: @x:0 + } + LIST [21] { + elements: { + CALL [22] { + function: _+_ + args: { + IDENT [23] { + name: @c:0 + } + CONSTANT [24] { value: 1 } + } + } + } + } + } + } + } + result: { + IDENT [25] { + name: @x:0 + } + } + } + } + } + } + } + } + result: { + IDENT [26] { + name: @x:1 + } + } + } + COMPREHENSION [27] { + iter_var: @c:3 + iter_range: { + IDENT [28] { + name: @index0 + } + } + accu_var: @x:3 + accu_init: { + LIST [29] { + elements: { + } + } + } + loop_condition: { + CONSTANT [30] { value: true } + } + loop_step: { + CALL [31] { + function: _+_ + args: { + IDENT [32] { + name: @x:3 + } + LIST [33] { + elements: { + COMPREHENSION [34] { + iter_var: @c:2 + iter_range: { + IDENT [35] { + name: @index0 + } + } + accu_var: @x:2 + accu_init: { + LIST [36] { + elements: { + } + } + } + loop_condition: { + CONSTANT [37] { value: true } + } + loop_step: { + CALL [38] { + function: _+_ + args: { + IDENT [39] { + name: @x:2 + } + LIST [40] { + elements: { + CALL [41] { + function: _+_ + args: { + IDENT [42] { + name: @c:2 + } + CONSTANT [43] { value: 1 } + } + } + } + } + } + } + } + result: { + IDENT [44] { + name: @x:2 + } + } + } + } + } + } + } + } + result: { + IDENT [45] { + name: @x:3 + } + } + } + } + } + } +} Test case: INCLUSION_LIST Source: 1 in [1,2,3] && 2 in [1,2,3] && 3 in [3, [1,2,3]] && 1 in [1,2,3] =====> diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_1.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_1.baseline index 1b081c43c..bcfc70fb1 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_1.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_1.baseline @@ -2592,6 +2592,214 @@ CALL [1] { } } } +Test case: ADJACENT_NESTED_MACROS +Source: [1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [1,2,3].map(j, [1, 2, 3].map(j, j + 1)) +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + CONSTANT [6] { value: 3 } + } + } + CALL [7] { + function: _+_ + args: { + IDENT [8] { + name: @c:0 + } + CONSTANT [9] { value: 1 } + } + } + LIST [10] { + elements: { + IDENT [11] { + name: @index1 + } + } + } + CALL [12] { + function: _+_ + args: { + IDENT [13] { + name: @x:0 + } + IDENT [14] { + name: @index2 + } + } + } + CALL [15] { + function: _+_ + args: { + IDENT [16] { + name: @c:2 + } + CONSTANT [17] { value: 1 } + } + } + LIST [18] { + elements: { + IDENT [19] { + name: @index4 + } + } + } + CALL [20] { + function: _+_ + args: { + IDENT [21] { + name: @x:2 + } + IDENT [22] { + name: @index5 + } + } + } + } + } + CALL [23] { + function: _==_ + args: { + COMPREHENSION [24] { + iter_var: @c:1 + iter_range: { + IDENT [25] { + name: @index0 + } + } + accu_var: @x:1 + accu_init: { + LIST [26] { + elements: { + } + } + } + loop_condition: { + CONSTANT [27] { value: true } + } + loop_step: { + CALL [28] { + function: _+_ + args: { + IDENT [29] { + name: @x:1 + } + LIST [30] { + elements: { + COMPREHENSION [31] { + iter_var: @c:0 + iter_range: { + IDENT [32] { + name: @index0 + } + } + accu_var: @x:0 + accu_init: { + LIST [33] { + elements: { + } + } + } + loop_condition: { + CONSTANT [34] { value: true } + } + loop_step: { + IDENT [35] { + name: @index3 + } + } + result: { + IDENT [36] { + name: @x:0 + } + } + } + } + } + } + } + } + result: { + IDENT [37] { + name: @x:1 + } + } + } + COMPREHENSION [38] { + iter_var: @c:3 + iter_range: { + IDENT [39] { + name: @index0 + } + } + accu_var: @x:3 + accu_init: { + LIST [40] { + elements: { + } + } + } + loop_condition: { + CONSTANT [41] { value: true } + } + loop_step: { + CALL [42] { + function: _+_ + args: { + IDENT [43] { + name: @x:3 + } + LIST [44] { + elements: { + COMPREHENSION [45] { + iter_var: @c:2 + iter_range: { + IDENT [46] { + name: @index0 + } + } + accu_var: @x:2 + accu_init: { + LIST [47] { + elements: { + } + } + } + loop_condition: { + CONSTANT [48] { value: true } + } + loop_step: { + IDENT [49] { + name: @index6 + } + } + result: { + IDENT [50] { + name: @x:2 + } + } + } + } + } + } + } + } + result: { + IDENT [51] { + name: @x:3 + } + } + } + } + } + } +} Test case: INCLUSION_LIST Source: 1 in [1,2,3] && 2 in [1,2,3] && 3 in [3, [1,2,3]] && 1 in [1,2,3] =====> diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_2.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_2.baseline index 1d3045ff6..7a46177d8 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_2.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_2.baseline @@ -2368,6 +2368,220 @@ CALL [1] { } } } +Test case: ADJACENT_NESTED_MACROS +Source: [1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [1,2,3].map(j, [1, 2, 3].map(j, j + 1)) +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + CONSTANT [6] { value: 3 } + } + } + LIST [7] { + elements: { + CALL [8] { + function: _+_ + args: { + IDENT [9] { + name: @c:0 + } + CONSTANT [10] { value: 1 } + } + } + } + } + COMPREHENSION [11] { + iter_var: @c:0 + iter_range: { + IDENT [12] { + name: @index0 + } + } + accu_var: @x:0 + accu_init: { + LIST [13] { + elements: { + } + } + } + loop_condition: { + CONSTANT [14] { value: true } + } + loop_step: { + CALL [15] { + function: _+_ + args: { + IDENT [16] { + name: @x:0 + } + IDENT [17] { + name: @index1 + } + } + } + } + result: { + IDENT [18] { + name: @x:0 + } + } + } + CALL [19] { + function: _+_ + args: { + IDENT [20] { + name: @x:1 + } + LIST [21] { + elements: { + IDENT [22] { + name: @index2 + } + } + } + } + } + COMPREHENSION [23] { + iter_var: @c:1 + iter_range: { + IDENT [24] { + name: @index0 + } + } + accu_var: @x:1 + accu_init: { + LIST [25] { + elements: { + } + } + } + loop_condition: { + CONSTANT [26] { value: true } + } + loop_step: { + IDENT [27] { + name: @index3 + } + } + result: { + IDENT [28] { + name: @x:1 + } + } + } + LIST [29] { + elements: { + CALL [30] { + function: _+_ + args: { + IDENT [31] { + name: @c:2 + } + CONSTANT [32] { value: 1 } + } + } + } + } + COMPREHENSION [33] { + iter_var: @c:2 + iter_range: { + IDENT [34] { + name: @index0 + } + } + accu_var: @x:2 + accu_init: { + LIST [35] { + elements: { + } + } + } + loop_condition: { + CONSTANT [36] { value: true } + } + loop_step: { + CALL [37] { + function: _+_ + args: { + IDENT [38] { + name: @x:2 + } + IDENT [39] { + name: @index5 + } + } + } + } + result: { + IDENT [40] { + name: @x:2 + } + } + } + CALL [41] { + function: _+_ + args: { + IDENT [42] { + name: @x:3 + } + LIST [43] { + elements: { + IDENT [44] { + name: @index6 + } + } + } + } + } + COMPREHENSION [45] { + iter_var: @c:3 + iter_range: { + IDENT [46] { + name: @index0 + } + } + accu_var: @x:3 + accu_init: { + LIST [47] { + elements: { + } + } + } + loop_condition: { + CONSTANT [48] { value: true } + } + loop_step: { + IDENT [49] { + name: @index7 + } + } + result: { + IDENT [50] { + name: @x:3 + } + } + } + } + } + CALL [51] { + function: _==_ + args: { + IDENT [52] { + name: @index4 + } + IDENT [53] { + name: @index8 + } + } + } + } +} Test case: INCLUSION_LIST Source: 1 in [1,2,3] && 2 in [1,2,3] && 3 in [3, [1,2,3]] && 1 in [1,2,3] =====> diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_3.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_3.baseline index f9c1f2a42..6ecc6d04a 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_3.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_3.baseline @@ -2303,6 +2303,208 @@ CALL [1] { } } } +Test case: ADJACENT_NESTED_MACROS +Source: [1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [1,2,3].map(j, [1, 2, 3].map(j, j + 1)) +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + CONSTANT [6] { value: 3 } + } + } + CALL [7] { + function: _+_ + args: { + IDENT [8] { + name: @x:0 + } + LIST [9] { + elements: { + CALL [10] { + function: _+_ + args: { + IDENT [11] { + name: @c:0 + } + CONSTANT [12] { value: 1 } + } + } + } + } + } + } + LIST [13] { + elements: { + COMPREHENSION [14] { + iter_var: @c:0 + iter_range: { + IDENT [15] { + name: @index0 + } + } + accu_var: @x:0 + accu_init: { + LIST [16] { + elements: { + } + } + } + loop_condition: { + CONSTANT [17] { value: true } + } + loop_step: { + IDENT [18] { + name: @index1 + } + } + result: { + IDENT [19] { + name: @x:0 + } + } + } + } + } + CALL [20] { + function: _+_ + args: { + IDENT [21] { + name: @x:2 + } + LIST [22] { + elements: { + CALL [23] { + function: _+_ + args: { + IDENT [24] { + name: @c:2 + } + CONSTANT [25] { value: 1 } + } + } + } + } + } + } + LIST [26] { + elements: { + COMPREHENSION [27] { + iter_var: @c:2 + iter_range: { + IDENT [28] { + name: @index0 + } + } + accu_var: @x:2 + accu_init: { + LIST [29] { + elements: { + } + } + } + loop_condition: { + CONSTANT [30] { value: true } + } + loop_step: { + IDENT [31] { + name: @index3 + } + } + result: { + IDENT [32] { + name: @x:2 + } + } + } + } + } + } + } + CALL [33] { + function: _==_ + args: { + COMPREHENSION [34] { + iter_var: @c:1 + iter_range: { + IDENT [35] { + name: @index0 + } + } + accu_var: @x:1 + accu_init: { + LIST [36] { + elements: { + } + } + } + loop_condition: { + CONSTANT [37] { value: true } + } + loop_step: { + CALL [38] { + function: _+_ + args: { + IDENT [39] { + name: @x:1 + } + IDENT [40] { + name: @index2 + } + } + } + } + result: { + IDENT [41] { + name: @x:1 + } + } + } + COMPREHENSION [42] { + iter_var: @c:3 + iter_range: { + IDENT [43] { + name: @index0 + } + } + accu_var: @x:3 + accu_init: { + LIST [44] { + elements: { + } + } + } + loop_condition: { + CONSTANT [45] { value: true } + } + loop_step: { + CALL [46] { + function: _+_ + args: { + IDENT [47] { + name: @x:3 + } + IDENT [48] { + name: @index4 + } + } + } + } + result: { + IDENT [49] { + name: @x:3 + } + } + } + } + } + } +} Test case: INCLUSION_LIST Source: 1 in [1,2,3] && 2 in [1,2,3] && 3 in [3, [1,2,3]] && 1 in [1,2,3] =====> diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_4.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_4.baseline index a640f81da..0bfb05eaf 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_4.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_4.baseline @@ -2252,6 +2252,202 @@ CALL [1] { } } } +Test case: ADJACENT_NESTED_MACROS +Source: [1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [1,2,3].map(j, [1, 2, 3].map(j, j + 1)) +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + CONSTANT [6] { value: 3 } + } + } + COMPREHENSION [7] { + iter_var: @c:0 + iter_range: { + IDENT [8] { + name: @index0 + } + } + accu_var: @x:0 + accu_init: { + LIST [9] { + elements: { + } + } + } + loop_condition: { + CONSTANT [10] { value: true } + } + loop_step: { + CALL [11] { + function: _+_ + args: { + IDENT [12] { + name: @x:0 + } + LIST [13] { + elements: { + CALL [14] { + function: _+_ + args: { + IDENT [15] { + name: @c:0 + } + CONSTANT [16] { value: 1 } + } + } + } + } + } + } + } + result: { + IDENT [17] { + name: @x:0 + } + } + } + COMPREHENSION [18] { + iter_var: @c:2 + iter_range: { + IDENT [19] { + name: @index0 + } + } + accu_var: @x:2 + accu_init: { + LIST [20] { + elements: { + } + } + } + loop_condition: { + CONSTANT [21] { value: true } + } + loop_step: { + CALL [22] { + function: _+_ + args: { + IDENT [23] { + name: @x:2 + } + LIST [24] { + elements: { + CALL [25] { + function: _+_ + args: { + IDENT [26] { + name: @c:2 + } + CONSTANT [27] { value: 1 } + } + } + } + } + } + } + } + result: { + IDENT [28] { + name: @x:2 + } + } + } + } + } + CALL [29] { + function: _==_ + args: { + COMPREHENSION [30] { + iter_var: @c:1 + iter_range: { + IDENT [31] { + name: @index0 + } + } + accu_var: @x:1 + accu_init: { + LIST [32] { + elements: { + } + } + } + loop_condition: { + CONSTANT [33] { value: true } + } + loop_step: { + CALL [34] { + function: _+_ + args: { + IDENT [35] { + name: @x:1 + } + LIST [36] { + elements: { + IDENT [37] { + name: @index1 + } + } + } + } + } + } + result: { + IDENT [38] { + name: @x:1 + } + } + } + COMPREHENSION [39] { + iter_var: @c:3 + iter_range: { + IDENT [40] { + name: @index0 + } + } + accu_var: @x:3 + accu_init: { + LIST [41] { + elements: { + } + } + } + loop_condition: { + CONSTANT [42] { value: true } + } + loop_step: { + CALL [43] { + function: _+_ + args: { + IDENT [44] { + name: @x:3 + } + LIST [45] { + elements: { + IDENT [46] { + name: @index2 + } + } + } + } + } + } + result: { + IDENT [47] { + name: @x:3 + } + } + } + } + } + } +} Test case: INCLUSION_LIST Source: 1 in [1,2,3] && 2 in [1,2,3] && 3 in [3, [1,2,3]] && 1 in [1,2,3] =====> diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_5.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_5.baseline index ba9b61292..ed7daab1e 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_5.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_5.baseline @@ -2222,6 +2222,202 @@ CALL [1] { } } } +Test case: ADJACENT_NESTED_MACROS +Source: [1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [1,2,3].map(j, [1, 2, 3].map(j, j + 1)) +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + CONSTANT [6] { value: 3 } + } + } + LIST [7] { + elements: { + COMPREHENSION [8] { + iter_var: @c:0 + iter_range: { + IDENT [9] { + name: @index0 + } + } + accu_var: @x:0 + accu_init: { + LIST [10] { + elements: { + } + } + } + loop_condition: { + CONSTANT [11] { value: true } + } + loop_step: { + CALL [12] { + function: _+_ + args: { + IDENT [13] { + name: @x:0 + } + LIST [14] { + elements: { + CALL [15] { + function: _+_ + args: { + IDENT [16] { + name: @c:0 + } + CONSTANT [17] { value: 1 } + } + } + } + } + } + } + } + result: { + IDENT [18] { + name: @x:0 + } + } + } + } + } + LIST [19] { + elements: { + COMPREHENSION [20] { + iter_var: @c:2 + iter_range: { + IDENT [21] { + name: @index0 + } + } + accu_var: @x:2 + accu_init: { + LIST [22] { + elements: { + } + } + } + loop_condition: { + CONSTANT [23] { value: true } + } + loop_step: { + CALL [24] { + function: _+_ + args: { + IDENT [25] { + name: @x:2 + } + LIST [26] { + elements: { + CALL [27] { + function: _+_ + args: { + IDENT [28] { + name: @c:2 + } + CONSTANT [29] { value: 1 } + } + } + } + } + } + } + } + result: { + IDENT [30] { + name: @x:2 + } + } + } + } + } + } + } + CALL [31] { + function: _==_ + args: { + COMPREHENSION [32] { + iter_var: @c:1 + iter_range: { + IDENT [33] { + name: @index0 + } + } + accu_var: @x:1 + accu_init: { + LIST [34] { + elements: { + } + } + } + loop_condition: { + CONSTANT [35] { value: true } + } + loop_step: { + CALL [36] { + function: _+_ + args: { + IDENT [37] { + name: @x:1 + } + IDENT [38] { + name: @index1 + } + } + } + } + result: { + IDENT [39] { + name: @x:1 + } + } + } + COMPREHENSION [40] { + iter_var: @c:3 + iter_range: { + IDENT [41] { + name: @index0 + } + } + accu_var: @x:3 + accu_init: { + LIST [42] { + elements: { + } + } + } + loop_condition: { + CONSTANT [43] { value: true } + } + loop_step: { + CALL [44] { + function: _+_ + args: { + IDENT [45] { + name: @x:3 + } + IDENT [46] { + name: @index2 + } + } + } + } + result: { + IDENT [47] { + name: @x:3 + } + } + } + } + } + } +} Test case: INCLUSION_LIST Source: 1 in [1,2,3] && 2 in [1,2,3] && 3 in [3, [1,2,3]] && 1 in [1,2,3] =====> diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_6.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_6.baseline index b68e6eaf1..0172a0726 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_6.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_6.baseline @@ -2207,6 +2207,202 @@ CALL [1] { } } } +Test case: ADJACENT_NESTED_MACROS +Source: [1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [1,2,3].map(j, [1, 2, 3].map(j, j + 1)) +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + CONSTANT [6] { value: 3 } + } + } + CALL [7] { + function: _+_ + args: { + IDENT [8] { + name: @x:1 + } + LIST [9] { + elements: { + COMPREHENSION [10] { + iter_var: @c:0 + iter_range: { + IDENT [11] { + name: @index0 + } + } + accu_var: @x:0 + accu_init: { + LIST [12] { + elements: { + } + } + } + loop_condition: { + CONSTANT [13] { value: true } + } + loop_step: { + CALL [14] { + function: _+_ + args: { + IDENT [15] { + name: @x:0 + } + LIST [16] { + elements: { + CALL [17] { + function: _+_ + args: { + IDENT [18] { + name: @c:0 + } + CONSTANT [19] { value: 1 } + } + } + } + } + } + } + } + result: { + IDENT [20] { + name: @x:0 + } + } + } + } + } + } + } + CALL [21] { + function: _+_ + args: { + IDENT [22] { + name: @x:3 + } + LIST [23] { + elements: { + COMPREHENSION [24] { + iter_var: @c:2 + iter_range: { + IDENT [25] { + name: @index0 + } + } + accu_var: @x:2 + accu_init: { + LIST [26] { + elements: { + } + } + } + loop_condition: { + CONSTANT [27] { value: true } + } + loop_step: { + CALL [28] { + function: _+_ + args: { + IDENT [29] { + name: @x:2 + } + LIST [30] { + elements: { + CALL [31] { + function: _+_ + args: { + IDENT [32] { + name: @c:2 + } + CONSTANT [33] { value: 1 } + } + } + } + } + } + } + } + result: { + IDENT [34] { + name: @x:2 + } + } + } + } + } + } + } + } + } + CALL [35] { + function: _==_ + args: { + COMPREHENSION [36] { + iter_var: @c:1 + iter_range: { + IDENT [37] { + name: @index0 + } + } + accu_var: @x:1 + accu_init: { + LIST [38] { + elements: { + } + } + } + loop_condition: { + CONSTANT [39] { value: true } + } + loop_step: { + IDENT [40] { + name: @index1 + } + } + result: { + IDENT [41] { + name: @x:1 + } + } + } + COMPREHENSION [42] { + iter_var: @c:3 + iter_range: { + IDENT [43] { + name: @index0 + } + } + accu_var: @x:3 + accu_init: { + LIST [44] { + elements: { + } + } + } + loop_condition: { + CONSTANT [45] { value: true } + } + loop_step: { + IDENT [46] { + name: @index2 + } + } + result: { + IDENT [47] { + name: @x:3 + } + } + } + } + } + } +} Test case: INCLUSION_LIST Source: 1 in [1,2,3] && 2 in [1,2,3] && 3 in [3, [1,2,3]] && 1 in [1,2,3] =====> diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_7.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_7.baseline index 410c1ff1a..5fa185080 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_7.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_7.baseline @@ -2198,6 +2198,202 @@ CALL [1] { } } } +Test case: ADJACENT_NESTED_MACROS +Source: [1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [1,2,3].map(j, [1, 2, 3].map(j, j + 1)) +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + CONSTANT [6] { value: 3 } + } + } + COMPREHENSION [7] { + iter_var: @c:1 + iter_range: { + IDENT [8] { + name: @index0 + } + } + accu_var: @x:1 + accu_init: { + LIST [9] { + elements: { + } + } + } + loop_condition: { + CONSTANT [10] { value: true } + } + loop_step: { + CALL [11] { + function: _+_ + args: { + IDENT [12] { + name: @x:1 + } + LIST [13] { + elements: { + COMPREHENSION [14] { + iter_var: @c:0 + iter_range: { + IDENT [15] { + name: @index0 + } + } + accu_var: @x:0 + accu_init: { + LIST [16] { + elements: { + } + } + } + loop_condition: { + CONSTANT [17] { value: true } + } + loop_step: { + CALL [18] { + function: _+_ + args: { + IDENT [19] { + name: @x:0 + } + LIST [20] { + elements: { + CALL [21] { + function: _+_ + args: { + IDENT [22] { + name: @c:0 + } + CONSTANT [23] { value: 1 } + } + } + } + } + } + } + } + result: { + IDENT [24] { + name: @x:0 + } + } + } + } + } + } + } + } + result: { + IDENT [25] { + name: @x:1 + } + } + } + COMPREHENSION [26] { + iter_var: @c:3 + iter_range: { + IDENT [27] { + name: @index0 + } + } + accu_var: @x:3 + accu_init: { + LIST [28] { + elements: { + } + } + } + loop_condition: { + CONSTANT [29] { value: true } + } + loop_step: { + CALL [30] { + function: _+_ + args: { + IDENT [31] { + name: @x:3 + } + LIST [32] { + elements: { + COMPREHENSION [33] { + iter_var: @c:2 + iter_range: { + IDENT [34] { + name: @index0 + } + } + accu_var: @x:2 + accu_init: { + LIST [35] { + elements: { + } + } + } + loop_condition: { + CONSTANT [36] { value: true } + } + loop_step: { + CALL [37] { + function: _+_ + args: { + IDENT [38] { + name: @x:2 + } + LIST [39] { + elements: { + CALL [40] { + function: _+_ + args: { + IDENT [41] { + name: @c:2 + } + CONSTANT [42] { value: 1 } + } + } + } + } + } + } + } + result: { + IDENT [43] { + name: @x:2 + } + } + } + } + } + } + } + } + result: { + IDENT [44] { + name: @x:3 + } + } + } + } + } + CALL [45] { + function: _==_ + args: { + IDENT [46] { + name: @index1 + } + IDENT [47] { + name: @index2 + } + } + } + } +} Test case: INCLUSION_LIST Source: 1 in [1,2,3] && 2 in [1,2,3] && 3 in [3, [1,2,3]] && 1 in [1,2,3] =====> diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_8.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_8.baseline index d8c949600..9da40d283 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_8.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_8.baseline @@ -2180,6 +2180,196 @@ CALL [31] { } } } +Test case: ADJACENT_NESTED_MACROS +Source: [1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [1,2,3].map(j, [1, 2, 3].map(j, j + 1)) +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + CONSTANT [6] { value: 3 } + } + } + } + } + CALL [7] { + function: _==_ + args: { + COMPREHENSION [8] { + iter_var: @c:1 + iter_range: { + IDENT [9] { + name: @index0 + } + } + accu_var: @x:1 + accu_init: { + LIST [10] { + elements: { + } + } + } + loop_condition: { + CONSTANT [11] { value: true } + } + loop_step: { + CALL [12] { + function: _+_ + args: { + IDENT [13] { + name: @x:1 + } + LIST [14] { + elements: { + COMPREHENSION [15] { + iter_var: @c:0 + iter_range: { + IDENT [16] { + name: @index0 + } + } + accu_var: @x:0 + accu_init: { + LIST [17] { + elements: { + } + } + } + loop_condition: { + CONSTANT [18] { value: true } + } + loop_step: { + CALL [19] { + function: _+_ + args: { + IDENT [20] { + name: @x:0 + } + LIST [21] { + elements: { + CALL [22] { + function: _+_ + args: { + IDENT [23] { + name: @c:0 + } + CONSTANT [24] { value: 1 } + } + } + } + } + } + } + } + result: { + IDENT [25] { + name: @x:0 + } + } + } + } + } + } + } + } + result: { + IDENT [26] { + name: @x:1 + } + } + } + COMPREHENSION [27] { + iter_var: @c:3 + iter_range: { + IDENT [28] { + name: @index0 + } + } + accu_var: @x:3 + accu_init: { + LIST [29] { + elements: { + } + } + } + loop_condition: { + CONSTANT [30] { value: true } + } + loop_step: { + CALL [31] { + function: _+_ + args: { + IDENT [32] { + name: @x:3 + } + LIST [33] { + elements: { + COMPREHENSION [34] { + iter_var: @c:2 + iter_range: { + IDENT [35] { + name: @index0 + } + } + accu_var: @x:2 + accu_init: { + LIST [36] { + elements: { + } + } + } + loop_condition: { + CONSTANT [37] { value: true } + } + loop_step: { + CALL [38] { + function: _+_ + args: { + IDENT [39] { + name: @x:2 + } + LIST [40] { + elements: { + CALL [41] { + function: _+_ + args: { + IDENT [42] { + name: @c:2 + } + CONSTANT [43] { value: 1 } + } + } + } + } + } + } + } + result: { + IDENT [44] { + name: @x:2 + } + } + } + } + } + } + } + } + result: { + IDENT [45] { + name: @x:3 + } + } + } + } + } + } +} Test case: INCLUSION_LIST Source: 1 in [1,2,3] && 2 in [1,2,3] && 3 in [3, [1,2,3]] && 1 in [1,2,3] =====> diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_9.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_9.baseline index b9bccc56c..025cd4769 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_9.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_9.baseline @@ -2165,6 +2165,196 @@ CALL [31] { } } } +Test case: ADJACENT_NESTED_MACROS +Source: [1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [1,2,3].map(j, [1, 2, 3].map(j, j + 1)) +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + CONSTANT [6] { value: 3 } + } + } + } + } + CALL [7] { + function: _==_ + args: { + COMPREHENSION [8] { + iter_var: @c:1 + iter_range: { + IDENT [9] { + name: @index0 + } + } + accu_var: @x:1 + accu_init: { + LIST [10] { + elements: { + } + } + } + loop_condition: { + CONSTANT [11] { value: true } + } + loop_step: { + CALL [12] { + function: _+_ + args: { + IDENT [13] { + name: @x:1 + } + LIST [14] { + elements: { + COMPREHENSION [15] { + iter_var: @c:0 + iter_range: { + IDENT [16] { + name: @index0 + } + } + accu_var: @x:0 + accu_init: { + LIST [17] { + elements: { + } + } + } + loop_condition: { + CONSTANT [18] { value: true } + } + loop_step: { + CALL [19] { + function: _+_ + args: { + IDENT [20] { + name: @x:0 + } + LIST [21] { + elements: { + CALL [22] { + function: _+_ + args: { + IDENT [23] { + name: @c:0 + } + CONSTANT [24] { value: 1 } + } + } + } + } + } + } + } + result: { + IDENT [25] { + name: @x:0 + } + } + } + } + } + } + } + } + result: { + IDENT [26] { + name: @x:1 + } + } + } + COMPREHENSION [27] { + iter_var: @c:3 + iter_range: { + IDENT [28] { + name: @index0 + } + } + accu_var: @x:3 + accu_init: { + LIST [29] { + elements: { + } + } + } + loop_condition: { + CONSTANT [30] { value: true } + } + loop_step: { + CALL [31] { + function: _+_ + args: { + IDENT [32] { + name: @x:3 + } + LIST [33] { + elements: { + COMPREHENSION [34] { + iter_var: @c:2 + iter_range: { + IDENT [35] { + name: @index0 + } + } + accu_var: @x:2 + accu_init: { + LIST [36] { + elements: { + } + } + } + loop_condition: { + CONSTANT [37] { value: true } + } + loop_step: { + CALL [38] { + function: _+_ + args: { + IDENT [39] { + name: @x:2 + } + LIST [40] { + elements: { + CALL [41] { + function: _+_ + args: { + IDENT [42] { + name: @c:2 + } + CONSTANT [43] { value: 1 } + } + } + } + } + } + } + } + result: { + IDENT [44] { + name: @x:2 + } + } + } + } + } + } + } + } + result: { + IDENT [45] { + name: @x:3 + } + } + } + } + } + } +} Test case: INCLUSION_LIST Source: 1 in [1,2,3] && 2 in [1,2,3] && 3 in [3, [1,2,3]] && 1 in [1,2,3] =====> diff --git a/optimizer/src/test/resources/subexpression_ast_cascaded_binds.baseline b/optimizer/src/test/resources/subexpression_ast_cascaded_binds.baseline index 5d09067b9..14ec4f9e6 100644 --- a/optimizer/src/test/resources/subexpression_ast_cascaded_binds.baseline +++ b/optimizer/src/test/resources/subexpression_ast_cascaded_binds.baseline @@ -2697,6 +2697,209 @@ CALL [31] { } } } +Test case: ADJACENT_NESTED_MACROS +Source: [1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [1,2,3].map(j, [1, 2, 3].map(j, j + 1)) +=====> +COMPREHENSION [1] { + iter_var: #unused + iter_range: { + LIST [2] { + elements: { + } + } + } + accu_var: @r0 + accu_init: { + LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + CONSTANT [6] { value: 3 } + } + } + } + loop_condition: { + CONSTANT [7] { value: false } + } + loop_step: { + IDENT [8] { + name: @r0 + } + } + result: { + CALL [9] { + function: _==_ + args: { + COMPREHENSION [10] { + iter_var: @c:1 + iter_range: { + IDENT [11] { + name: @r0 + } + } + accu_var: @x:1 + accu_init: { + LIST [12] { + elements: { + } + } + } + loop_condition: { + CONSTANT [13] { value: true } + } + loop_step: { + CALL [14] { + function: _+_ + args: { + IDENT [15] { + name: @x:1 + } + LIST [16] { + elements: { + COMPREHENSION [17] { + iter_var: @c:0 + iter_range: { + IDENT [18] { + name: @r0 + } + } + accu_var: @x:0 + accu_init: { + LIST [19] { + elements: { + } + } + } + loop_condition: { + CONSTANT [20] { value: true } + } + loop_step: { + CALL [21] { + function: _+_ + args: { + IDENT [22] { + name: @x:0 + } + LIST [23] { + elements: { + CALL [24] { + function: _+_ + args: { + IDENT [25] { + name: @c:0 + } + CONSTANT [26] { value: 1 } + } + } + } + } + } + } + } + result: { + IDENT [27] { + name: @x:0 + } + } + } + } + } + } + } + } + result: { + IDENT [28] { + name: @x:1 + } + } + } + COMPREHENSION [29] { + iter_var: @c:3 + iter_range: { + IDENT [30] { + name: @r0 + } + } + accu_var: @x:3 + accu_init: { + LIST [31] { + elements: { + } + } + } + loop_condition: { + CONSTANT [32] { value: true } + } + loop_step: { + CALL [33] { + function: _+_ + args: { + IDENT [34] { + name: @x:3 + } + LIST [35] { + elements: { + COMPREHENSION [36] { + iter_var: @c:2 + iter_range: { + IDENT [37] { + name: @r0 + } + } + accu_var: @x:2 + accu_init: { + LIST [38] { + elements: { + } + } + } + loop_condition: { + CONSTANT [39] { value: true } + } + loop_step: { + CALL [40] { + function: _+_ + args: { + IDENT [41] { + name: @x:2 + } + LIST [42] { + elements: { + CALL [43] { + function: _+_ + args: { + IDENT [44] { + name: @c:2 + } + CONSTANT [45] { value: 1 } + } + } + } + } + } + } + } + result: { + IDENT [46] { + name: @x:2 + } + } + } + } + } + } + } + } + result: { + IDENT [47] { + name: @x:3 + } + } + } + } + } + } +} Test case: INCLUSION_LIST Source: 1 in [1,2,3] && 2 in [1,2,3] && 3 in [3, [1,2,3]] && 1 in [1,2,3] =====> diff --git a/optimizer/src/test/resources/subexpression_unparsed.baseline b/optimizer/src/test/resources/subexpression_unparsed.baseline index 831290039..9675f3b3a 100644 --- a/optimizer/src/test/resources/subexpression_unparsed.baseline +++ b/optimizer/src/test/resources/subexpression_unparsed.baseline @@ -350,6 +350,22 @@ Result: true [BLOCK_RECURSION_DEPTH_8]: [1, 2].map(@c:1, [1, 2, 3].filter(@c:0, @c:0 == @c:1)) == [[1], [2]] [BLOCK_RECURSION_DEPTH_9]: [1, 2].map(@c:1, [1, 2, 3].filter(@c:0, @c:0 == @c:1)) == [[1], [2]] +Test case: ADJACENT_NESTED_MACROS +Source: [1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [1,2,3].map(j, [1, 2, 3].map(j, j + 1)) +=====> +Result: true +[CASCADED_BINDS]: cel.bind(@r0, [1, 2, 3], @r0.map(@c:1, @r0.map(@c:0, @c:0 + 1)) == @r0.map(@c:3, @r0.map(@c:2, @c:2 + 1))) +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([[1, 2, 3]], @index0.map(@c:1, @index0.map(@c:0, @c:0 + 1)) == @index0.map(@c:3, @index0.map(@c:2, @c:2 + 1))) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([[1, 2, 3], @c:0 + 1, [@index1], @x:0 + @index2, @c:2 + 1, [@index4], @x:2 + @index5], @index0.map(@c:1, @index0.map(@c:0, @index1)) == @index0.map(@c:3, @index0.map(@c:2, @index4))) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([[1, 2, 3], [@c:0 + 1], @index0.map(@c:0, @c:0 + 1), @x:1 + [@index2], @index0.map(@c:1, @index2), [@c:2 + 1], @index0.map(@c:2, @c:2 + 1), @x:3 + [@index6], @index0.map(@c:3, @index6)], @index4 == @index8) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([[1, 2, 3], @x:0 + [@c:0 + 1], [@index0.map(@c:0, @c:0 + 1)], @x:2 + [@c:2 + 1], [@index0.map(@c:2, @c:2 + 1)]], @index0.map(@c:1) == @index0.map(@c:3)) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([[1, 2, 3], @index0.map(@c:0, @c:0 + 1), @index0.map(@c:2, @c:2 + 1)], @index0.map(@c:1, @index1) == @index0.map(@c:3, @index2)) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([[1, 2, 3], [@index0.map(@c:0, @c:0 + 1)], [@index0.map(@c:2, @c:2 + 1)]], @index0.map(@c:1) == @index0.map(@c:3)) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([[1, 2, 3], @x:1 + [@index0.map(@c:0, @c:0 + 1)], @x:3 + [@index0.map(@c:2, @c:2 + 1)]], @index0.map(@c:1) == @index0.map(@c:3)) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([[1, 2, 3], @index0.map(@c:1, @index0.map(@c:0, @c:0 + 1)), @index0.map(@c:3, @index0.map(@c:2, @c:2 + 1))], @index1 == @index2) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([[1, 2, 3]], @index0.map(@c:1, @index0.map(@c:0, @c:0 + 1)) == @index0.map(@c:3, @index0.map(@c:2, @c:2 + 1))) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([[1, 2, 3]], @index0.map(@c:1, @index0.map(@c:0, @c:0 + 1)) == @index0.map(@c:3, @index0.map(@c:2, @c:2 + 1))) + Test case: INCLUSION_LIST Source: 1 in [1,2,3] && 2 in [1,2,3] && 3 in [3, [1,2,3]] && 1 in [1,2,3] =====> From c3c493ab76dc44305cecb0e2fd2aa062915aa906 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Mon, 19 Aug 2024 14:02:31 -0700 Subject: [PATCH 182/486] Improve CSE for comprehensions by taking into their nesting level and types into account PiperOrigin-RevId: 664968878 --- .../java/dev/cel/optimizer/AstMutator.java | 89 +- .../optimizers/SubexpressionOptimizer.java | 14 +- .../dev/cel/optimizer/AstMutatorTest.java | 93 +- ...old_before_subexpression_unparsed.baseline | 22 +- .../large_expressions_bind_cascaded.baseline | 2 +- ..._expressions_block_common_subexpr.baseline | 2 +- ...pressions_block_recursion_depth_1.baseline | 2 +- ...pressions_block_recursion_depth_2.baseline | 2 +- ...pressions_block_recursion_depth_3.baseline | 2 +- ...ion_ast_block_common_subexpr_only.baseline | 1130 ++++++---------- ...ssion_ast_block_recursion_depth_1.baseline | 799 +++++------- ...ssion_ast_block_recursion_depth_2.baseline | 897 +++++-------- ...ssion_ast_block_recursion_depth_3.baseline | 1009 +++++---------- ...ssion_ast_block_recursion_depth_4.baseline | 1000 +++++--------- ...ssion_ast_block_recursion_depth_5.baseline | 1089 +++++----------- ...ssion_ast_block_recursion_depth_6.baseline | 1132 ++++++---------- ...ssion_ast_block_recursion_depth_7.baseline | 1145 ++++++---------- ...ssion_ast_block_recursion_depth_8.baseline | 1152 ++++++----------- ...ssion_ast_block_recursion_depth_9.baseline | 1149 ++++++---------- .../subexpression_ast_cascaded_binds.baseline | 274 ++-- .../resources/subexpression_unparsed.baseline | 198 +-- 21 files changed, 4029 insertions(+), 7173 deletions(-) diff --git a/optimizer/src/main/java/dev/cel/optimizer/AstMutator.java b/optimizer/src/main/java/dev/cel/optimizer/AstMutator.java index aa90f1528..a731ac21e 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/AstMutator.java +++ b/optimizer/src/main/java/dev/cel/optimizer/AstMutator.java @@ -21,7 +21,9 @@ import com.google.auto.value.AutoValue; import com.google.common.base.Preconditions; import com.google.common.base.Strings; +import com.google.common.collect.HashBasedTable; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Table; import com.google.errorprone.annotations.Immutable; import dev.cel.common.CelAbstractSyntaxTree; import dev.cel.common.CelMutableAst; @@ -270,17 +272,22 @@ public CelMutableAst renumberIdsConsecutively(CelMutableAst mutableAst) { * @param ast AST containing type-checked references * @param newIterVarPrefix Prefix to use for new iteration variable identifier name. For example, * providing @c will produce @c0:0, @c0:1, @c1:0, @c2:0... as new names. - * @param newResultPrefix Prefix to use for new comprehensin result identifier names. + * @param newAccuVarPrefix Prefix to use for new accumulation variable identifier name. + * @param incrementSerially If true, indices for the mangled variables are incremented serially + * per occurrence regardless of their nesting level or its types. */ public MangledComprehensionAst mangleComprehensionIdentifierNames( - CelMutableAst ast, String newIterVarPrefix, String newResultPrefix) { + CelMutableAst ast, + String newIterVarPrefix, + String newAccuVarPrefix, + boolean incrementSerially) { CelNavigableMutableAst navigableMutableAst = CelNavigableMutableAst.fromAst(ast); Predicate comprehensionIdentifierPredicate = x -> true; comprehensionIdentifierPredicate = comprehensionIdentifierPredicate .and(node -> node.getKind().equals(Kind.COMPREHENSION)) .and(node -> !node.expr().comprehension().iterVar().startsWith(newIterVarPrefix)) - .and(node -> !node.expr().comprehension().accuVar().startsWith(newResultPrefix)); + .and(node -> !node.expr().comprehension().accuVar().startsWith(newAccuVarPrefix)); LinkedHashMap comprehensionsToMangle = navigableMutableAst @@ -352,18 +359,43 @@ public MangledComprehensionAst mangleComprehensionIdentifierNames( // The map that we'll eventually return to the caller. HashMap mangledIdentNamesToType = new HashMap<>(); + // Intermediary table used for the purposes of generating a unique mangled variable name. + Table comprehensionLevelToType = + HashBasedTable.create(); CelMutableExpr mutatedComprehensionExpr = navigableMutableAst.getAst().expr(); CelMutableSource newSource = navigableMutableAst.getAst().source(); int iterCount = 0; for (Entry comprehensionEntry : comprehensionsToMangle.entrySet()) { - String mangledIterVarName = newIterVarPrefix + ":" + iterCount; - String mangledResultName = newResultPrefix + ":" + iterCount; - MangledComprehensionName mangledComprehensionName = - MangledComprehensionName.of(mangledIterVarName, mangledResultName); - mangledIdentNamesToType.put(mangledComprehensionName, comprehensionEntry.getValue()); + CelNavigableMutableExpr comprehensionNode = comprehensionEntry.getKey(); + MangledComprehensionType comprehensionEntryType = comprehensionEntry.getValue(); + + CelMutableExpr comprehensionExpr = comprehensionNode.expr(); + MangledComprehensionName mangledComprehensionName; + if (incrementSerially) { + // In case of applying CSE via cascaded cel.binds, not only is mangling based on level/types + // meaningless (because all comprehensions are nested anyways, thus all indices would be + // uinque), + // it can lead to an erroneous result due to extracting a common subexpr with accu_var at + // the wrong scope. + // Example: "[1].exists(k, k > 1) && [2].exists(l, l > 1). The loop step for both branches + // are identical, but shouldn't be extracted. + String mangledIterVarName = newIterVarPrefix + ":" + iterCount; + String mangledResultName = newAccuVarPrefix + ":" + iterCount; + mangledComprehensionName = + MangledComprehensionName.of(mangledIterVarName, mangledResultName); + mangledIdentNamesToType.put(mangledComprehensionName, comprehensionEntry.getValue()); + } else { + mangledComprehensionName = + getMangledComprehensionName( + newIterVarPrefix, + newAccuVarPrefix, + comprehensionNode, + comprehensionLevelToType, + comprehensionEntryType); + } + mangledIdentNamesToType.put(mangledComprehensionName, comprehensionEntryType); - CelMutableExpr comprehensionExpr = comprehensionEntry.getKey().expr(); String iterVar = comprehensionExpr.comprehension().iterVar(); String accuVar = comprehensionExpr.comprehension().accuVar(); mutatedComprehensionExpr = @@ -396,6 +428,45 @@ public MangledComprehensionAst mangleComprehensionIdentifierNames( ImmutableMap.copyOf(mangledIdentNamesToType)); } + private static MangledComprehensionName getMangledComprehensionName( + String newIterVarPrefix, + String newResultPrefix, + CelNavigableMutableExpr comprehensionNode, + Table comprehensionLevelToType, + MangledComprehensionType comprehensionEntryType) { + MangledComprehensionName mangledComprehensionName; + int comprehensionNestingLevel = countComprehensionNestingLevel(comprehensionNode); + if (comprehensionLevelToType.contains(comprehensionNestingLevel, comprehensionEntryType)) { + mangledComprehensionName = + comprehensionLevelToType.get(comprehensionNestingLevel, comprehensionEntryType); + } else { + // First time encountering the pair of . Generate a unique + // mangled variable name for this. + int uniqueTypeIdx = comprehensionLevelToType.row(comprehensionNestingLevel).size(); + String mangledIterVarName = + newIterVarPrefix + ":" + comprehensionNestingLevel + ":" + uniqueTypeIdx; + String mangledResultName = + newResultPrefix + ":" + comprehensionNestingLevel + ":" + uniqueTypeIdx; + mangledComprehensionName = MangledComprehensionName.of(mangledIterVarName, mangledResultName); + comprehensionLevelToType.put( + comprehensionNestingLevel, comprehensionEntryType, mangledComprehensionName); + } + return mangledComprehensionName; + } + + private static int countComprehensionNestingLevel(CelNavigableMutableExpr comprehensionExpr) { + int nestedLevel = 0; + Optional maybeParent = comprehensionExpr.parent(); + while (maybeParent.isPresent()) { + if (maybeParent.get().getKind().equals(Kind.COMPREHENSION)) { + nestedLevel++; + } + + maybeParent = maybeParent.get().parent(); + } + return nestedLevel; + } + /** * Replaces a subtree in the given expression node. This operation is intended for AST * optimization purposes. diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java index ecb5b22e4..e6c327915 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java @@ -92,8 +92,8 @@ public class SubexpressionOptimizer implements CelAstOptimizer { private static final SubexpressionOptimizer INSTANCE = new SubexpressionOptimizer(SubexpressionOptimizerOptions.newBuilder().build()); private static final String BIND_IDENTIFIER_PREFIX = "@r"; - private static final String MANGLED_COMPREHENSION_IDENTIFIER_PREFIX = "@c"; - private static final String MANGLED_COMPREHENSION_RESULT_PREFIX = "@x"; + private static final String MANGLED_COMPREHENSION_ITER_VAR_PREFIX = "@it"; + private static final String MANGLED_COMPREHENSION_ACCU_VAR_PREFIX = "@ac"; private static final String CEL_BLOCK_FUNCTION = "cel.@block"; private static final String BLOCK_INDEX_PREFIX = "@index"; private static final Extension CEL_BLOCK_AST_EXTENSION_TAG = @@ -138,8 +138,9 @@ private OptimizationResult optimizeUsingCelBlock(CelAbstractSyntaxTree ast, Cel MangledComprehensionAst mangledComprehensionAst = astMutator.mangleComprehensionIdentifierNames( astToModify, - MANGLED_COMPREHENSION_IDENTIFIER_PREFIX, - MANGLED_COMPREHENSION_RESULT_PREFIX); + MANGLED_COMPREHENSION_ITER_VAR_PREFIX, + MANGLED_COMPREHENSION_ACCU_VAR_PREFIX, + /* incrementSerially= */ false); astToModify = mangledComprehensionAst.mutableAst(); CelMutableSource sourceToModify = astToModify.source(); @@ -339,8 +340,9 @@ private OptimizationResult optimizeUsingCelBind(CelAbstractSyntaxTree ast) { astMutator .mangleComprehensionIdentifierNames( astToModify, - MANGLED_COMPREHENSION_IDENTIFIER_PREFIX, - MANGLED_COMPREHENSION_RESULT_PREFIX) + MANGLED_COMPREHENSION_ITER_VAR_PREFIX, + MANGLED_COMPREHENSION_ACCU_VAR_PREFIX, + /* incrementSerially= */ true) .mutableAst(); CelMutableSource sourceToModify = astToModify.source(); diff --git a/optimizer/src/test/java/dev/cel/optimizer/AstMutatorTest.java b/optimizer/src/test/java/dev/cel/optimizer/AstMutatorTest.java index cdfa1cb00..31cabdb9d 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/AstMutatorTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/AstMutatorTest.java @@ -876,14 +876,14 @@ public void mangleComprehensionVariable_singleMacro() throws Exception { CelAbstractSyntaxTree mangledAst = AST_MUTATOR - .mangleComprehensionIdentifierNames(CelMutableAst.fromCelAst(ast), "@c", "@x") + .mangleComprehensionIdentifierNames(CelMutableAst.fromCelAst(ast), "@it", "@ac", true) .mutableAst() .toParsedAst(); assertThat(mangledAst.getExpr().toString()) .isEqualTo( "COMPREHENSION [13] {\n" - + " iter_var: @c:0\n" + + " iter_var: @it:0\n" + " iter_range: {\n" + " LIST [1] {\n" + " elements: {\n" @@ -891,7 +891,7 @@ public void mangleComprehensionVariable_singleMacro() throws Exception { + " }\n" + " }\n" + " }\n" - + " accu_var: @x:0\n" + + " accu_var: @ac:0\n" + " accu_init: {\n" + " CONSTANT [6] { value: false }\n" + " }\n" @@ -903,7 +903,7 @@ public void mangleComprehensionVariable_singleMacro() throws Exception { + " function: !_\n" + " args: {\n" + " IDENT [7] {\n" - + " name: @x:0\n" + + " name: @ac:0\n" + " }\n" + " }\n" + " }\n" @@ -915,26 +915,69 @@ public void mangleComprehensionVariable_singleMacro() throws Exception { + " function: _||_\n" + " args: {\n" + " IDENT [10] {\n" - + " name: @x:0\n" + + " name: @ac:0\n" + " }\n" + " IDENT [5] {\n" - + " name: @c:0\n" + + " name: @it:0\n" + " }\n" + " }\n" + " }\n" + " }\n" + " result: {\n" + " IDENT [12] {\n" - + " name: @x:0\n" + + " name: @ac:0\n" + " }\n" + " }\n" + "}"); - - assertThat(CEL_UNPARSER.unparse(mangledAst)).isEqualTo("[false].exists(@c:0, @c:0)"); + assertThat(CEL_UNPARSER.unparse(mangledAst)).isEqualTo("[false].exists(@it:0, @it:0)"); assertThat(CEL.createProgram(CEL.check(mangledAst).getAst()).eval()).isEqualTo(false); assertConsistentMacroCalls(ast); } + @Test + public void mangleComprehensionVariable_adjacentMacros_sameIterVarTypes() throws Exception { + CelAbstractSyntaxTree ast = + CEL.compile( + "[1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [1,2,3].map(j, [1, 2, 3].map(j, j +" + + " 1))") + .getAst(); + + CelAbstractSyntaxTree mangledAst = + AST_MUTATOR + .mangleComprehensionIdentifierNames(CelMutableAst.fromCelAst(ast), "@it", "@ac", false) + .mutableAst() + .toParsedAst(); + + assertThat(CEL_UNPARSER.unparse(mangledAst)) + .isEqualTo( + "[1, 2, 3].map(@it:0:0, [1, 2, 3].map(@it:1:0, @it:1:0 + 1)) == " + + "[1, 2, 3].map(@it:0:0, [1, 2, 3].map(@it:1:0, @it:1:0 + 1))"); + assertThat(CEL.createProgram(CEL.check(mangledAst).getAst()).eval()).isEqualTo(true); + assertConsistentMacroCalls(ast); + } + + @Test + public void mangleComprehensionVariable_adjacentMacros_differentIterVarTypes() throws Exception { + CelAbstractSyntaxTree ast = + CEL.compile( + "[1,2,3].map(i, [1, 2, 3].map(i, i)) == dyn([1u,2u,3u].map(j, [1u, 2u, 3u].map(j," + + " j)))") + .getAst(); + + CelAbstractSyntaxTree mangledAst = + AST_MUTATOR + .mangleComprehensionIdentifierNames(CelMutableAst.fromCelAst(ast), "@it", "@ac", false) + .mutableAst() + .toParsedAst(); + + assertThat(CEL_UNPARSER.unparse(mangledAst)) + .isEqualTo( + "[1, 2, 3].map(@it:0:0, [1, 2, 3].map(@it:1:0, @it:1:0)) == " + + "dyn([1u, 2u, 3u].map(@it:0:1, [1u, 2u, 3u].map(@it:1:1, @it:1:1)))"); + assertThat(CEL.createProgram(CEL.check(mangledAst).getAst()).eval()).isEqualTo(true); + assertConsistentMacroCalls(ast); + } + @Test public void mangleComprehensionVariable_macroSourceDisabled_macroCallMapIsEmpty() throws Exception { @@ -947,7 +990,7 @@ public void mangleComprehensionVariable_macroSourceDisabled_macroCallMapIsEmpty( CelAbstractSyntaxTree mangledAst = AST_MUTATOR - .mangleComprehensionIdentifierNames(CelMutableAst.fromCelAst(ast), "@c", "@x") + .mangleComprehensionIdentifierNames(CelMutableAst.fromCelAst(ast), "@it", "@ac", true) .mutableAst() .toParsedAst(); @@ -960,14 +1003,14 @@ public void mangleComprehensionVariable_nestedMacroWithShadowedVariables() throw CelAbstractSyntaxTree mangledAst = AST_MUTATOR - .mangleComprehensionIdentifierNames(CelMutableAst.fromCelAst(ast), "@c", "@x") + .mangleComprehensionIdentifierNames(CelMutableAst.fromCelAst(ast), "@it", "@ac", true) .mutableAst() .toParsedAst(); assertThat(mangledAst.getExpr().toString()) .isEqualTo( "COMPREHENSION [27] {\n" - + " iter_var: @c:1\n" + + " iter_var: @it:1\n" + " iter_range: {\n" + " LIST [1] {\n" + " elements: {\n" @@ -977,7 +1020,7 @@ public void mangleComprehensionVariable_nestedMacroWithShadowedVariables() throw + " }\n" + " }\n" + " }\n" - + " accu_var: @x:1\n" + + " accu_var: @ac:1\n" + " accu_init: {\n" + " CONSTANT [20] { value: false }\n" + " }\n" @@ -989,7 +1032,7 @@ public void mangleComprehensionVariable_nestedMacroWithShadowedVariables() throw + " function: !_\n" + " args: {\n" + " IDENT [21] {\n" - + " name: @x:1\n" + + " name: @ac:1\n" + " }\n" + " }\n" + " }\n" @@ -1001,20 +1044,20 @@ public void mangleComprehensionVariable_nestedMacroWithShadowedVariables() throw + " function: _||_\n" + " args: {\n" + " IDENT [24] {\n" - + " name: @x:1\n" + + " name: @ac:1\n" + " }\n" + " COMPREHENSION [19] {\n" - + " iter_var: @c:0\n" + + " iter_var: @it:0\n" + " iter_range: {\n" + " LIST [5] {\n" + " elements: {\n" + " IDENT [6] {\n" - + " name: @c:1\n" + + " name: @it:1\n" + " }\n" + " }\n" + " }\n" + " }\n" - + " accu_var: @x:0\n" + + " accu_var: @ac:0\n" + " accu_init: {\n" + " CONSTANT [12] { value: false }\n" + " }\n" @@ -1026,7 +1069,7 @@ public void mangleComprehensionVariable_nestedMacroWithShadowedVariables() throw + " function: !_\n" + " args: {\n" + " IDENT [13] {\n" - + " name: @x:0\n" + + " name: @ac:0\n" + " }\n" + " }\n" + " }\n" @@ -1038,13 +1081,13 @@ public void mangleComprehensionVariable_nestedMacroWithShadowedVariables() throw + " function: _||_\n" + " args: {\n" + " IDENT [16] {\n" - + " name: @x:0\n" + + " name: @ac:0\n" + " }\n" + " CALL [10] {\n" + " function: _==_\n" + " args: {\n" + " IDENT [9] {\n" - + " name: @c:0\n" + + " name: @it:0\n" + " }\n" + " CONSTANT [11] { value: 1 }\n" + " }\n" @@ -1054,7 +1097,7 @@ public void mangleComprehensionVariable_nestedMacroWithShadowedVariables() throw + " }\n" + " result: {\n" + " IDENT [18] {\n" - + " name: @x:0\n" + + " name: @ac:0\n" + " }\n" + " }\n" + " }\n" @@ -1063,13 +1106,13 @@ public void mangleComprehensionVariable_nestedMacroWithShadowedVariables() throw + " }\n" + " result: {\n" + " IDENT [26] {\n" - + " name: @x:1\n" + + " name: @ac:1\n" + " }\n" + " }\n" + "}"); assertThat(CEL_UNPARSER.unparse(mangledAst)) - .isEqualTo("[x].exists(@c:1, [@c:1].exists(@c:0, @c:0 == 1))"); + .isEqualTo("[x].exists(@it:1, [@it:1].exists(@it:0, @it:0 == 1))"); assertThat(CEL.createProgram(CEL.check(mangledAst).getAst()).eval(ImmutableMap.of("x", 1))) .isEqualTo(true); assertConsistentMacroCalls(ast); @@ -1081,7 +1124,7 @@ public void mangleComprehensionVariable_hasMacro_noOp() throws Exception { CelAbstractSyntaxTree mangledAst = AST_MUTATOR - .mangleComprehensionIdentifierNames(CelMutableAst.fromCelAst(ast), "@c", "@x") + .mangleComprehensionIdentifierNames(CelMutableAst.fromCelAst(ast), "@it", "@ac", true) .mutableAst() .toParsedAst(); diff --git a/optimizer/src/test/resources/constfold_before_subexpression_unparsed.baseline b/optimizer/src/test/resources/constfold_before_subexpression_unparsed.baseline index 897b4d775..7324d1716 100644 --- a/optimizer/src/test/resources/constfold_before_subexpression_unparsed.baseline +++ b/optimizer/src/test/resources/constfold_before_subexpression_unparsed.baseline @@ -418,17 +418,17 @@ Test case: MACRO_SHADOWED_VARIABLE Source: [x - 1 > 3 ? x - 1 : 5].exists(x, x - 1 > 3) || x - 1 > 3 =====> Result: true -[CASCADED_BINDS]: cel.bind(@r0, x - 1, cel.bind(@r1, @r0 > 3, [@r1 ? @r0 : 5].exists(@c:0, @c:0 - 1 > 3) || @r1)) -[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([x - 1, @index0 > 3], [@index1 ? @index0 : 5].exists(@c:0, @c:0 - 1 > 3) || @index1) -[BLOCK_RECURSION_DEPTH_1]: cel.@block([x - 1, @index0 > 3, @index1 ? @index0 : 5, [@index2], @c:0 - 1, @index4 > 3, @x:0 || @index5], @index3.exists(@c:0, @index5) || @index1) -[BLOCK_RECURSION_DEPTH_2]: cel.@block([x - 1 > 3, @index0 ? (x - 1) : 5, @c:0 - 1 > 3, [@index1], @x:0 || @index2], @index3.exists(@c:0, @index2) || @index0) -[BLOCK_RECURSION_DEPTH_3]: cel.@block([x - 1 > 3, [@index0 ? (x - 1) : 5], @x:0 || @c:0 - 1 > 3, @index1.exists(@c:0, @c:0 - 1 > 3)], @index3 || @index0) -[BLOCK_RECURSION_DEPTH_4]: cel.@block([x - 1 > 3, [@index0 ? (x - 1) : 5].exists(@c:0, @c:0 - 1 > 3)], @index1 || @index0) -[BLOCK_RECURSION_DEPTH_5]: cel.@block([x - 1 > 3], [@index0 ? (x - 1) : 5].exists(@c:0, @c:0 - 1 > 3) || @index0) -[BLOCK_RECURSION_DEPTH_6]: cel.@block([x - 1 > 3], [@index0 ? (x - 1) : 5].exists(@c:0, @c:0 - 1 > 3) || @index0) -[BLOCK_RECURSION_DEPTH_7]: cel.@block([x - 1 > 3], [@index0 ? (x - 1) : 5].exists(@c:0, @c:0 - 1 > 3) || @index0) -[BLOCK_RECURSION_DEPTH_8]: cel.@block([x - 1 > 3], [@index0 ? (x - 1) : 5].exists(@c:0, @c:0 - 1 > 3) || @index0) -[BLOCK_RECURSION_DEPTH_9]: cel.@block([x - 1 > 3], [@index0 ? (x - 1) : 5].exists(@c:0, @c:0 - 1 > 3) || @index0) +[CASCADED_BINDS]: cel.bind(@r0, x - 1, cel.bind(@r1, @r0 > 3, [@r1 ? @r0 : 5].exists(@it:0, @it:0 - 1 > 3) || @r1)) +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([x - 1, @index0 > 3], [@index1 ? @index0 : 5].exists(@it:0:0, @it:0:0 - 1 > 3) || @index1) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([x - 1, @index0 > 3, @index1 ? @index0 : 5, [@index2], @it:0:0 - 1, @index4 > 3, @ac:0:0 || @index5], @index3.exists(@it:0:0, @index5) || @index1) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([x - 1 > 3, @index0 ? (x - 1) : 5, @it:0:0 - 1 > 3, [@index1], @ac:0:0 || @index2], @index3.exists(@it:0:0, @index2) || @index0) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([x - 1 > 3, [@index0 ? (x - 1) : 5], @ac:0:0 || @it:0:0 - 1 > 3, @index1.exists(@it:0:0, @it:0:0 - 1 > 3)], @index3 || @index0) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([x - 1 > 3, [@index0 ? (x - 1) : 5].exists(@it:0:0, @it:0:0 - 1 > 3)], @index1 || @index0) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([x - 1 > 3], [@index0 ? (x - 1) : 5].exists(@it:0:0, @it:0:0 - 1 > 3) || @index0) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([x - 1 > 3], [@index0 ? (x - 1) : 5].exists(@it:0:0, @it:0:0 - 1 > 3) || @index0) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([x - 1 > 3], [@index0 ? (x - 1) : 5].exists(@it:0:0, @it:0:0 - 1 > 3) || @index0) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([x - 1 > 3], [@index0 ? (x - 1) : 5].exists(@it:0:0, @it:0:0 - 1 > 3) || @index0) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([x - 1 > 3], [@index0 ? (x - 1) : 5].exists(@it:0:0, @it:0:0 - 1 > 3) || @index0) Test case: MACRO_SHADOWED_VARIABLE_2 Source: ["foo", "bar"].map(x, [x + x, x + x]).map(x, [x + x, x + x]) diff --git a/optimizer/src/test/resources/large_expressions_bind_cascaded.baseline b/optimizer/src/test/resources/large_expressions_bind_cascaded.baseline index a37fd38ce..cec9eec5d 100644 --- a/optimizer/src/test/resources/large_expressions_bind_cascaded.baseline +++ b/optimizer/src/test/resources/large_expressions_bind_cascaded.baseline @@ -14,4 +14,4 @@ Test case: NESTED_MACROS Source: [1,2,3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3])))))))) =====> Result: [[[[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]]], [[[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]]], [[[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]]]] -Unparsed: cel.bind(@r0, [1, 2, 3], @r0.map(@c:7, @r0.map(@c:6, @r0.map(@c:5, @r0.map(@c:4, @r0.map(@c:3, @r0.map(@c:2, @r0.map(@c:1, @r0.map(@c:0, @r0))))))))) \ No newline at end of file +Unparsed: cel.bind(@r0, [1, 2, 3], @r0.map(@it:7, @r0.map(@it:6, @r0.map(@it:5, @r0.map(@it:4, @r0.map(@it:3, @r0.map(@it:2, @r0.map(@it:1, @r0.map(@it:0, @r0))))))))) \ No newline at end of file diff --git a/optimizer/src/test/resources/large_expressions_block_common_subexpr.baseline b/optimizer/src/test/resources/large_expressions_block_common_subexpr.baseline index 35a169875..87623446d 100644 --- a/optimizer/src/test/resources/large_expressions_block_common_subexpr.baseline +++ b/optimizer/src/test/resources/large_expressions_block_common_subexpr.baseline @@ -14,4 +14,4 @@ Test case: NESTED_MACROS Source: [1,2,3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3])))))))) =====> Result: [[[[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]]], [[[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]]], [[[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]]]] -Unparsed: cel.@block([[1, 2, 3]], @index0.map(@c:7, @index0.map(@c:6, @index0.map(@c:5, @index0.map(@c:4, @index0.map(@c:3, @index0.map(@c:2, @index0.map(@c:1, @index0.map(@c:0, @index0))))))))) \ No newline at end of file +Unparsed: cel.@block([[1, 2, 3]], @index0.map(@it:0:0, @index0.map(@it:1:0, @index0.map(@it:2:0, @index0.map(@it:3:0, @index0.map(@it:4:0, @index0.map(@it:5:0, @index0.map(@it:6:0, @index0.map(@it:7:0, @index0))))))))) \ No newline at end of file diff --git a/optimizer/src/test/resources/large_expressions_block_recursion_depth_1.baseline b/optimizer/src/test/resources/large_expressions_block_recursion_depth_1.baseline index 7409190cc..8dd1445eb 100644 --- a/optimizer/src/test/resources/large_expressions_block_recursion_depth_1.baseline +++ b/optimizer/src/test/resources/large_expressions_block_recursion_depth_1.baseline @@ -14,4 +14,4 @@ Test case: NESTED_MACROS Source: [1,2,3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3])))))))) =====> Result: [[[[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]]], [[[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]]], [[[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]]]] -Unparsed: cel.@block([[1, 2, 3], [@index0], @x:0 + @index1], @index0.map(@c:7, @index0.map(@c:6, @index0.map(@c:5, @index0.map(@c:4, @index0.map(@c:3, @index0.map(@c:2, @index0.map(@c:1, @index0.map(@c:0, @index0))))))))) \ No newline at end of file +Unparsed: cel.@block([[1, 2, 3], [@index0], @ac:7:0 + @index1], @index0.map(@it:0:0, @index0.map(@it:1:0, @index0.map(@it:2:0, @index0.map(@it:3:0, @index0.map(@it:4:0, @index0.map(@it:5:0, @index0.map(@it:6:0, @index0.map(@it:7:0, @index0))))))))) \ No newline at end of file diff --git a/optimizer/src/test/resources/large_expressions_block_recursion_depth_2.baseline b/optimizer/src/test/resources/large_expressions_block_recursion_depth_2.baseline index 01fe95991..f139abe3c 100644 --- a/optimizer/src/test/resources/large_expressions_block_recursion_depth_2.baseline +++ b/optimizer/src/test/resources/large_expressions_block_recursion_depth_2.baseline @@ -14,4 +14,4 @@ Test case: NESTED_MACROS Source: [1,2,3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3])))))))) =====> Result: [[[[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]]], [[[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]]], [[[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]]]] -Unparsed: cel.@block([[1, 2, 3], @x:0 + [@index0], @index0.map(@c:0, @index0), @x:1 + [@index2], @index0.map(@c:1, @index2), @x:2 + [@index4], @index0.map(@c:2, @index4), @x:3 + [@index6], @index0.map(@c:3, @index6), @x:4 + [@index8], @index0.map(@c:4, @index8), @x:5 + [@index10], @index0.map(@c:5, @index10), @x:6 + [@index12], @index0.map(@c:6, @index12), @x:7 + [@index14]], @index0.map(@c:7, @index14)) \ No newline at end of file +Unparsed: cel.@block([[1, 2, 3], @ac:7:0 + [@index0], @index0.map(@it:7:0, @index0), @ac:6:0 + [@index2], @index0.map(@it:6:0, @index2), @ac:5:0 + [@index4], @index0.map(@it:5:0, @index4), @ac:4:0 + [@index6], @index0.map(@it:4:0, @index6), @ac:3:0 + [@index8], @index0.map(@it:3:0, @index8), @ac:2:0 + [@index10], @index0.map(@it:2:0, @index10), @ac:1:0 + [@index12], @index0.map(@it:1:0, @index12), @ac:0:0 + [@index14]], @index0.map(@it:0:0, @index14)) \ No newline at end of file diff --git a/optimizer/src/test/resources/large_expressions_block_recursion_depth_3.baseline b/optimizer/src/test/resources/large_expressions_block_recursion_depth_3.baseline index 56d163470..3ce295592 100644 --- a/optimizer/src/test/resources/large_expressions_block_recursion_depth_3.baseline +++ b/optimizer/src/test/resources/large_expressions_block_recursion_depth_3.baseline @@ -14,4 +14,4 @@ Test case: NESTED_MACROS Source: [1,2,3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3].map(i, [1, 2, 3])))))))) =====> Result: [[[[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]]], [[[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]]], [[[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]], [[[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]], [[[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]], [[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]], [[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]]]]]] -Unparsed: cel.@block([[1, 2, 3], @index0.map(@c:0, @index0), @index0.map(@c:1, @index1), @index0.map(@c:2, @index2), @index0.map(@c:3, @index3), @index0.map(@c:4, @index4), @index0.map(@c:5, @index5), @index0.map(@c:6, @index6)], @index0.map(@c:7, @index7)) \ No newline at end of file +Unparsed: cel.@block([[1, 2, 3], @index0.map(@it:7:0, @index0), @index0.map(@it:6:0, @index1), @index0.map(@it:5:0, @index2), @index0.map(@it:4:0, @index3), @index0.map(@it:3:0, @index4), @index0.map(@it:2:0, @index5), @index0.map(@it:1:0, @index6)], @index0.map(@it:0:0, @index7)) \ No newline at end of file diff --git a/optimizer/src/test/resources/subexpression_ast_block_common_subexpr_only.baseline b/optimizer/src/test/resources/subexpression_ast_block_common_subexpr_only.baseline index d2267c0d8..292b584f6 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_common_subexpr_only.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_common_subexpr_only.baseline @@ -1116,504 +1116,95 @@ CALL [1] { args: { LIST [2] { elements: { - LIST [3] { - elements: { - CONSTANT [4] { value: 1 } - } - } - LIST [5] { - elements: { - CONSTANT [6] { value: 2 } - } - } - } - } - CALL [7] { - function: _==_ - args: { - CALL [8] { - function: _+_ + CALL [3] { + function: size args: { - CALL [9] { - function: _+_ - args: { - CALL [10] { - function: _+_ - args: { - CALL [11] { - function: size - args: { - LIST [12] { - elements: { - COMPREHENSION [13] { - iter_var: @c:0 - iter_range: { - IDENT [14] { - name: @index0 - } - } - accu_var: @x:0 - accu_init: { - CONSTANT [15] { value: false } - } - loop_condition: { - CALL [16] { - function: @not_strictly_false - args: { - CALL [17] { - function: !_ - args: { - IDENT [18] { - name: @x:0 - } - } - } - } - } - } - loop_step: { - CALL [19] { - function: _||_ - args: { - IDENT [20] { - name: @x:0 - } - CALL [21] { - function: _>_ - args: { - IDENT [22] { - name: @c:0 - } - CONSTANT [23] { value: 0 } - } - } - } - } - } - result: { - IDENT [24] { - name: @x:0 - } - } - } - } - } - } - } - CALL [25] { - function: size - args: { - LIST [26] { - elements: { - COMPREHENSION [27] { - iter_var: @c:1 - iter_range: { - IDENT [28] { - name: @index0 - } - } - accu_var: @x:1 - accu_init: { - CONSTANT [29] { value: false } - } - loop_condition: { - CALL [30] { - function: @not_strictly_false - args: { - CALL [31] { - function: !_ - args: { - IDENT [32] { - name: @x:1 - } - } - } - } - } - } - loop_step: { - CALL [33] { - function: _||_ - args: { - IDENT [34] { - name: @x:1 - } - CALL [35] { - function: _>_ - args: { - IDENT [36] { - name: @c:1 - } - CONSTANT [37] { value: 0 } - } - } - } - } - } - result: { - IDENT [38] { - name: @x:1 - } - } - } - } - } - } - } - } - } - CALL [39] { - function: size - args: { - LIST [40] { + LIST [4] { + elements: { + COMPREHENSION [5] { + iter_var: @it:0:0 + iter_range: { + LIST [6] { elements: { - COMPREHENSION [41] { - iter_var: @c:2 - iter_range: { - IDENT [42] { - name: @index1 - } - } - accu_var: @x:2 - accu_init: { - CONSTANT [43] { value: false } - } - loop_condition: { - CALL [44] { - function: @not_strictly_false - args: { - CALL [45] { - function: !_ - args: { - IDENT [46] { - name: @x:2 - } - } - } - } - } - } - loop_step: { - CALL [47] { - function: _||_ - args: { - IDENT [48] { - name: @x:2 - } - CALL [49] { - function: _>_ - args: { - IDENT [50] { - name: @c:2 - } - CONSTANT [51] { value: 1 } - } - } - } - } - } - result: { - IDENT [52] { - name: @x:2 - } - } - } + CONSTANT [7] { value: 1 } } } } - } - } - } - CALL [53] { - function: size - args: { - LIST [54] { - elements: { - COMPREHENSION [55] { - iter_var: @c:3 - iter_range: { - IDENT [56] { - name: @index1 - } - } - accu_var: @x:3 - accu_init: { - CONSTANT [57] { value: false } - } - loop_condition: { - CALL [58] { - function: @not_strictly_false - args: { - CALL [59] { - function: !_ - args: { - IDENT [60] { - name: @x:3 - } - } - } - } - } - } - loop_step: { - CALL [61] { - function: _||_ + accu_var: @ac:0:0 + accu_init: { + CONSTANT [8] { value: false } + } + loop_condition: { + CALL [9] { + function: @not_strictly_false + args: { + CALL [10] { + function: !_ args: { - IDENT [62] { - name: @x:3 - } - CALL [63] { - function: _>_ - args: { - IDENT [64] { - name: @c:3 - } - CONSTANT [65] { value: 1 } - } + IDENT [11] { + name: @ac:0:0 } } } } - result: { - IDENT [66] { - name: @x:3 - } - } } } - } - } - } - } - } - CONSTANT [67] { value: 4 } - } - } - } -} -Test case: MULTIPLE_MACROS_2 -Source: [[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == 'a')] + [['a'].exists(l, l == 'a')] == [true, true, true, true] -=====> -CALL [1] { - function: cel.@block - args: { - LIST [2] { - elements: { - LIST [3] { - elements: { - CONSTANT [4] { value: 1 } - } - } - LIST [5] { - elements: { - CONSTANT [6] { value: "a" } - } - } - } - } - CALL [7] { - function: _==_ - args: { - CALL [8] { - function: _+_ - args: { - CALL [9] { - function: _+_ - args: { - CALL [10] { - function: _+_ - args: { - LIST [11] { - elements: { - COMPREHENSION [12] { - iter_var: @c:0 - iter_range: { - IDENT [13] { - name: @index0 - } - } - accu_var: @x:0 - accu_init: { - CONSTANT [14] { value: false } - } - loop_condition: { - CALL [15] { - function: @not_strictly_false - args: { - CALL [16] { - function: !_ - args: { - IDENT [17] { - name: @x:0 - } - } - } - } - } - } - loop_step: { - CALL [18] { - function: _||_ - args: { - IDENT [19] { - name: @x:0 - } - CALL [20] { - function: _>_ - args: { - IDENT [21] { - name: @c:0 - } - CONSTANT [22] { value: 0 } - } - } - } - } - } - result: { - IDENT [23] { - name: @x:0 - } - } + loop_step: { + CALL [12] { + function: _||_ + args: { + IDENT [13] { + name: @ac:0:0 } - } - } - LIST [24] { - elements: { - COMPREHENSION [25] { - iter_var: @c:1 - iter_range: { - IDENT [26] { - name: @index0 - } - } - accu_var: @x:1 - accu_init: { - CONSTANT [27] { value: false } - } - loop_condition: { - CALL [28] { - function: @not_strictly_false - args: { - CALL [29] { - function: !_ - args: { - IDENT [30] { - name: @x:1 - } - } - } - } - } - } - loop_step: { - CALL [31] { - function: _||_ - args: { - IDENT [32] { - name: @x:1 - } - CALL [33] { - function: _>_ - args: { - IDENT [34] { - name: @c:1 - } - CONSTANT [35] { value: 0 } - } - } - } - } - } - result: { - IDENT [36] { - name: @x:1 + CALL [14] { + function: _>_ + args: { + IDENT [15] { + name: @it:0:0 } + CONSTANT [16] { value: 0 } } } } } } - } - LIST [37] { - elements: { - COMPREHENSION [38] { - iter_var: @c:2 - iter_range: { - IDENT [39] { - name: @index1 - } - } - accu_var: @x:2 - accu_init: { - CONSTANT [40] { value: false } - } - loop_condition: { - CALL [41] { - function: @not_strictly_false - args: { - CALL [42] { - function: !_ - args: { - IDENT [43] { - name: @x:2 - } - } - } - } - } - } - loop_step: { - CALL [44] { - function: _||_ - args: { - IDENT [45] { - name: @x:2 - } - CALL [46] { - function: _==_ - args: { - IDENT [47] { - name: @c:2 - } - CONSTANT [48] { value: "a" } - } - } - } - } - } - result: { - IDENT [49] { - name: @x:2 - } - } + result: { + IDENT [17] { + name: @ac:0:0 } } } } } - LIST [50] { + } + } + CALL [18] { + function: size + args: { + LIST [19] { elements: { - COMPREHENSION [51] { - iter_var: @c:3 + COMPREHENSION [20] { + iter_var: @it:0:0 iter_range: { - IDENT [52] { - name: @index1 + LIST [21] { + elements: { + CONSTANT [22] { value: 2 } + } } } - accu_var: @x:3 + accu_var: @ac:0:0 accu_init: { - CONSTANT [53] { value: false } + CONSTANT [23] { value: false } } loop_condition: { - CALL [54] { + CALL [24] { function: @not_strictly_false args: { - CALL [55] { + CALL [25] { function: !_ args: { - IDENT [56] { - name: @x:3 + IDENT [26] { + name: @ac:0:0 } } } @@ -1621,27 +1212,27 @@ CALL [1] { } } loop_step: { - CALL [57] { + CALL [27] { function: _||_ args: { - IDENT [58] { - name: @x:3 + IDENT [28] { + name: @ac:0:0 } - CALL [59] { - function: _==_ + CALL [29] { + function: _>_ args: { - IDENT [60] { - name: @c:3 + IDENT [30] { + name: @it:0:0 } - CONSTANT [61] { value: "a" } + CONSTANT [31] { value: 1 } } } } } } result: { - IDENT [62] { - name: @x:3 + IDENT [32] { + name: @ac:0:0 } } } @@ -1649,20 +1240,45 @@ CALL [1] { } } } - LIST [63] { - elements: { - CONSTANT [64] { value: true } - CONSTANT [65] { value: true } - CONSTANT [66] { value: true } - CONSTANT [67] { value: true } + } + } + CALL [33] { + function: _==_ + args: { + CALL [34] { + function: _+_ + args: { + CALL [35] { + function: _+_ + args: { + CALL [36] { + function: _+_ + args: { + IDENT [37] { + name: @index0 + } + IDENT [38] { + name: @index0 + } + } + } + IDENT [39] { + name: @index1 + } + } + } + IDENT [40] { + name: @index1 + } } } + CONSTANT [41] { value: 4 } } } } } -Test case: MULTIPLE_MACROS_3 -Source: [1].exists(i, i > 0) && [1].exists(j, j > 0) && [1].exists(k, k > 1) && [2].exists(l, l > 1) +Test case: MULTIPLE_MACROS_2 +Source: [[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == 'a')] + [['a'].exists(l, l == 'a')] == [true, true, true, true] =====> CALL [1] { function: cel.@block @@ -1671,37 +1287,28 @@ CALL [1] { elements: { LIST [3] { elements: { - CONSTANT [4] { value: 1 } - } - } - } - } - CALL [5] { - function: _&&_ - args: { - CALL [6] { - function: _&&_ - args: { - COMPREHENSION [7] { - iter_var: @c:0 + COMPREHENSION [4] { + iter_var: @it:0:0 iter_range: { - IDENT [8] { - name: @index0 + LIST [5] { + elements: { + CONSTANT [6] { value: 1 } + } } } - accu_var: @x:0 + accu_var: @ac:0:0 accu_init: { - CONSTANT [9] { value: false } + CONSTANT [7] { value: false } } loop_condition: { - CALL [10] { + CALL [8] { function: @not_strictly_false args: { - CALL [11] { + CALL [9] { function: !_ args: { - IDENT [12] { - name: @x:0 + IDENT [10] { + name: @ac:0:0 } } } @@ -1709,38 +1316,44 @@ CALL [1] { } } loop_step: { - CALL [13] { + CALL [11] { function: _||_ args: { - IDENT [14] { - name: @x:0 + IDENT [12] { + name: @ac:0:0 } - CALL [15] { + CALL [13] { function: _>_ args: { - IDENT [16] { - name: @c:0 + IDENT [14] { + name: @it:0:0 } - CONSTANT [17] { value: 0 } + CONSTANT [15] { value: 0 } } } } } } result: { - IDENT [18] { - name: @x:0 + IDENT [16] { + name: @ac:0:0 } } } - COMPREHENSION [19] { - iter_var: @c:1 + } + } + LIST [17] { + elements: { + COMPREHENSION [18] { + iter_var: @it:0:1 iter_range: { - IDENT [20] { - name: @index0 + LIST [19] { + elements: { + CONSTANT [20] { value: "a" } + } } } - accu_var: @x:1 + accu_var: @ac:0:1 accu_init: { CONSTANT [21] { value: false } } @@ -1752,7 +1365,7 @@ CALL [1] { function: !_ args: { IDENT [24] { - name: @x:1 + name: @ac:0:1 } } } @@ -1764,15 +1377,15 @@ CALL [1] { function: _||_ args: { IDENT [26] { - name: @x:1 + name: @ac:0:1 } CALL [27] { - function: _>_ + function: _==_ args: { IDENT [28] { - name: @c:1 + name: @it:0:1 } - CONSTANT [29] { value: 0 } + CONSTANT [29] { value: "a" } } } } @@ -1780,35 +1393,175 @@ CALL [1] { } result: { IDENT [30] { - name: @x:1 + name: @ac:0:1 + } + } + } + } + } + } + } + CALL [31] { + function: _==_ + args: { + CALL [32] { + function: _+_ + args: { + CALL [33] { + function: _+_ + args: { + CALL [34] { + function: _+_ + args: { + IDENT [35] { + name: @index0 + } + IDENT [36] { + name: @index0 + } + } + } + IDENT [37] { + name: @index1 + } + } + } + IDENT [38] { + name: @index1 + } + } + } + LIST [39] { + elements: { + CONSTANT [40] { value: true } + CONSTANT [41] { value: true } + CONSTANT [42] { value: true } + CONSTANT [43] { value: true } + } + } + } + } + } +} +Test case: MULTIPLE_MACROS_3 +Source: [1].exists(i, i > 0) && [1].exists(j, j > 0) && [1].exists(k, k > 1) && [2].exists(l, l > 1) +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + COMPREHENSION [3] { + iter_var: @it:0:0 + iter_range: { + LIST [4] { + elements: { + CONSTANT [5] { value: 1 } + } + } + } + accu_var: @ac:0:0 + accu_init: { + CONSTANT [6] { value: false } + } + loop_condition: { + CALL [7] { + function: @not_strictly_false + args: { + CALL [8] { + function: !_ + args: { + IDENT [9] { + name: @ac:0:0 + } + } + } + } + } + } + loop_step: { + CALL [10] { + function: _||_ + args: { + IDENT [11] { + name: @ac:0:0 + } + CALL [12] { + function: _>_ + args: { + IDENT [13] { + name: @it:0:0 + } + CONSTANT [14] { value: 0 } + } + } + } + } + } + result: { + IDENT [15] { + name: @ac:0:0 + } + } + } + CALL [16] { + function: _||_ + args: { + IDENT [17] { + name: @ac:0:0 + } + CALL [18] { + function: _>_ + args: { + IDENT [19] { + name: @it:0:0 } + CONSTANT [20] { value: 1 } } } } } - CALL [31] { + } + } + CALL [21] { + function: _&&_ + args: { + CALL [22] { + function: _&&_ + args: { + IDENT [23] { + name: @index0 + } + IDENT [24] { + name: @index0 + } + } + } + CALL [25] { function: _&&_ args: { - COMPREHENSION [32] { - iter_var: @c:2 + COMPREHENSION [26] { + iter_var: @it:0:0 iter_range: { - IDENT [33] { - name: @index0 + LIST [27] { + elements: { + CONSTANT [28] { value: 1 } + } } } - accu_var: @x:2 + accu_var: @ac:0:0 accu_init: { - CONSTANT [34] { value: false } + CONSTANT [29] { value: false } } loop_condition: { - CALL [35] { + CALL [30] { function: @not_strictly_false args: { - CALL [36] { + CALL [31] { function: !_ args: { - IDENT [37] { - name: @x:2 + IDENT [32] { + name: @ac:0:0 } } } @@ -1816,52 +1569,38 @@ CALL [1] { } } loop_step: { - CALL [38] { - function: _||_ - args: { - IDENT [39] { - name: @x:2 - } - CALL [40] { - function: _>_ - args: { - IDENT [41] { - name: @c:2 - } - CONSTANT [42] { value: 1 } - } - } - } + IDENT [33] { + name: @index1 } } result: { - IDENT [43] { - name: @x:2 + IDENT [34] { + name: @ac:0:0 } } } - COMPREHENSION [44] { - iter_var: @c:3 + COMPREHENSION [35] { + iter_var: @it:0:0 iter_range: { - LIST [45] { + LIST [36] { elements: { - CONSTANT [46] { value: 2 } + CONSTANT [37] { value: 2 } } } } - accu_var: @x:3 + accu_var: @ac:0:0 accu_init: { - CONSTANT [47] { value: false } + CONSTANT [38] { value: false } } loop_condition: { - CALL [48] { + CALL [39] { function: @not_strictly_false args: { - CALL [49] { + CALL [40] { function: !_ args: { - IDENT [50] { - name: @x:3 + IDENT [41] { + name: @ac:0:0 } } } @@ -1869,27 +1608,13 @@ CALL [1] { } } loop_step: { - CALL [51] { - function: _||_ - args: { - IDENT [52] { - name: @x:3 - } - CALL [53] { - function: _>_ - args: { - IDENT [54] { - name: @c:3 - } - CONSTANT [55] { value: 1 } - } - } - } + IDENT [42] { + name: @index1 } } result: { - IDENT [56] { - name: @x:3 + IDENT [43] { + name: @ac:0:0 } } } @@ -1927,13 +1652,13 @@ CALL [1] { function: _==_ args: { COMPREHENSION [12] { - iter_var: @c:1 + iter_var: @it:0:0 iter_range: { IDENT [13] { name: @index0 } } - accu_var: @x:1 + accu_var: @ac:0:0 accu_init: { LIST [14] { elements: { @@ -1948,18 +1673,18 @@ CALL [1] { function: _+_ args: { IDENT [17] { - name: @x:1 + name: @ac:0:0 } LIST [18] { elements: { COMPREHENSION [19] { - iter_var: @c:0 + iter_var: @it:1:0 iter_range: { IDENT [20] { name: @index0 } } - accu_var: @x:0 + accu_var: @ac:1:0 accu_init: { LIST [21] { elements: { @@ -1974,7 +1699,7 @@ CALL [1] { function: _+_ args: { IDENT [24] { - name: @x:0 + name: @ac:1:0 } LIST [25] { elements: { @@ -1982,7 +1707,7 @@ CALL [1] { function: _+_ args: { IDENT [27] { - name: @c:0 + name: @it:1:0 } CONSTANT [28] { value: 1 } } @@ -1994,7 +1719,7 @@ CALL [1] { } result: { IDENT [29] { - name: @x:0 + name: @ac:1:0 } } } @@ -2005,7 +1730,7 @@ CALL [1] { } result: { IDENT [30] { - name: @x:1 + name: @ac:0:0 } } } @@ -2033,7 +1758,7 @@ CALL [31] { function: _==_ args: { COMPREHENSION [30] { - iter_var: @c:1 + iter_var: @it:0:0 iter_range: { LIST [1] { elements: { @@ -2042,7 +1767,7 @@ CALL [31] { } } } - accu_var: @x:1 + accu_var: @ac:0:0 accu_init: { LIST [24] { elements: { @@ -2057,12 +1782,12 @@ CALL [31] { function: _+_ args: { IDENT [26] { - name: @x:1 + name: @ac:0:0 } LIST [27] { elements: { COMPREHENSION [23] { - iter_var: @c:0 + iter_var: @it:1:0 iter_range: { LIST [6] { elements: { @@ -2072,7 +1797,7 @@ CALL [31] { } } } - accu_var: @x:0 + accu_var: @ac:1:0 accu_init: { LIST [15] { elements: { @@ -2090,10 +1815,10 @@ CALL [31] { function: _==_ args: { IDENT [12] { - name: @c:0 + name: @it:1:0 } IDENT [14] { - name: @c:1 + name: @it:0:0 } } } @@ -2101,26 +1826,26 @@ CALL [31] { function: _+_ args: { IDENT [17] { - name: @x:0 + name: @ac:1:0 } LIST [18] { elements: { IDENT [11] { - name: @c:0 + name: @it:1:0 } } } } } IDENT [20] { - name: @x:0 + name: @ac:1:0 } } } } result: { IDENT [22] { - name: @x:0 + name: @ac:1:0 } } } @@ -2131,7 +1856,7 @@ CALL [31] { } result: { IDENT [29] { - name: @x:1 + name: @ac:0:0 } } } @@ -2166,70 +1891,65 @@ CALL [1] { CONSTANT [6] { value: 3 } } } - } - } - CALL [7] { - function: _==_ - args: { - COMPREHENSION [8] { - iter_var: @c:1 + COMPREHENSION [7] { + iter_var: @it:0:0 iter_range: { - IDENT [9] { + IDENT [8] { name: @index0 } } - accu_var: @x:1 + accu_var: @ac:0:0 accu_init: { - LIST [10] { + LIST [9] { elements: { } } } loop_condition: { - CONSTANT [11] { value: true } + CONSTANT [10] { value: true } } loop_step: { - CALL [12] { + CALL [11] { function: _+_ args: { - IDENT [13] { - name: @x:1 + IDENT [12] { + name: @ac:0:0 } - LIST [14] { + LIST [13] { elements: { - COMPREHENSION [15] { - iter_var: @c:0 + COMPREHENSION [14] { + iter_var: @it:1:0 iter_range: { - IDENT [16] { + IDENT [15] { name: @index0 } } - accu_var: @x:0 + accu_var: @ac:1:0 accu_init: { - LIST [17] { + LIST [16] { elements: { } } } loop_condition: { - CONSTANT [18] { value: true } + CONSTANT [17] { value: true } } loop_step: { - CALL [19] { + CALL [18] { function: _+_ args: { - IDENT [20] { - name: @x:0 + IDENT [19] { + name: @ac:1:0 } - LIST [21] { + LIST [20] { elements: { - CALL [22] { + CALL [21] { function: _+_ args: { - IDENT [23] { - name: @c:0 + IDENT [22] { + name: @it:1:0 } - CONSTANT [24] { value: 1 } + CONSTANT [23] { value: 1 } } } } @@ -2238,8 +1958,8 @@ CALL [1] { } } result: { - IDENT [25] { - name: @x:0 + IDENT [24] { + name: @ac:1:0 } } } @@ -2249,93 +1969,21 @@ CALL [1] { } } result: { - IDENT [26] { - name: @x:1 + IDENT [25] { + name: @ac:0:0 } } } - COMPREHENSION [27] { - iter_var: @c:3 - iter_range: { - IDENT [28] { - name: @index0 - } - } - accu_var: @x:3 - accu_init: { - LIST [29] { - elements: { - } - } - } - loop_condition: { - CONSTANT [30] { value: true } - } - loop_step: { - CALL [31] { - function: _+_ - args: { - IDENT [32] { - name: @x:3 - } - LIST [33] { - elements: { - COMPREHENSION [34] { - iter_var: @c:2 - iter_range: { - IDENT [35] { - name: @index0 - } - } - accu_var: @x:2 - accu_init: { - LIST [36] { - elements: { - } - } - } - loop_condition: { - CONSTANT [37] { value: true } - } - loop_step: { - CALL [38] { - function: _+_ - args: { - IDENT [39] { - name: @x:2 - } - LIST [40] { - elements: { - CALL [41] { - function: _+_ - args: { - IDENT [42] { - name: @c:2 - } - CONSTANT [43] { value: 1 } - } - } - } - } - } - } - } - result: { - IDENT [44] { - name: @x:2 - } - } - } - } - } - } - } - } - result: { - IDENT [45] { - name: @x:3 - } - } + } + } + CALL [26] { + function: _==_ + args: { + IDENT [27] { + name: @index1 + } + IDENT [28] { + name: @index1 } } } @@ -2507,13 +2155,13 @@ CALL [1] { function: _==_ args: { COMPREHENSION [13] { - iter_var: @c:1 + iter_var: @it:0:0 iter_range: { IDENT [14] { name: @index0 } } - accu_var: @x:1 + accu_var: @ac:0:0 accu_init: { LIST [15] { elements: { @@ -2528,18 +2176,18 @@ CALL [1] { function: _+_ args: { IDENT [18] { - name: @x:1 + name: @ac:0:0 } LIST [19] { elements: { COMPREHENSION [20] { - iter_var: @c:0 + iter_var: @it:1:0 iter_range: { IDENT [21] { name: @index0 } } - accu_var: @x:0 + accu_var: @ac:1:0 accu_init: { LIST [22] { elements: { @@ -2554,7 +2202,7 @@ CALL [1] { function: _+_ args: { IDENT [25] { - name: @x:0 + name: @ac:1:0 } LIST [26] { elements: { @@ -2568,7 +2216,7 @@ CALL [1] { } result: { IDENT [28] { - name: @x:0 + name: @ac:1:0 } } } @@ -2579,7 +2227,7 @@ CALL [1] { } result: { IDENT [29] { - name: @x:1 + name: @ac:0:0 } } } @@ -2629,7 +2277,7 @@ CALL [1] { function: _||_ args: { COMPREHENSION [10] { - iter_var: @c:0 + iter_var: @it:0:0 iter_range: { LIST [11] { elements: { @@ -2648,7 +2296,7 @@ CALL [1] { } } } - accu_var: @x:0 + accu_var: @ac:0:0 accu_init: { CONSTANT [16] { value: false } } @@ -2660,7 +2308,7 @@ CALL [1] { function: !_ args: { IDENT [19] { - name: @x:0 + name: @ac:0:0 } } } @@ -2672,7 +2320,7 @@ CALL [1] { function: _||_ args: { IDENT [21] { - name: @x:0 + name: @ac:0:0 } CALL [22] { function: _>_ @@ -2681,7 +2329,7 @@ CALL [1] { function: _-_ args: { IDENT [24] { - name: @c:0 + name: @it:0:0 } CONSTANT [25] { value: 1 } } @@ -2694,7 +2342,7 @@ CALL [1] { } result: { IDENT [27] { - name: @x:0 + name: @ac:0:0 } } } @@ -2717,10 +2365,10 @@ CALL [1] { function: _+_ args: { IDENT [4] { - name: @c:0 + name: @it:1:0 } IDENT [5] { - name: @c:0 + name: @it:1:0 } } } @@ -2728,20 +2376,20 @@ CALL [1] { function: _+_ args: { IDENT [7] { - name: @c:1 + name: @it:0:0 } IDENT [8] { - name: @c:1 + name: @it:0:0 } } } } } COMPREHENSION [9] { - iter_var: @c:1 + iter_var: @it:0:0 iter_range: { COMPREHENSION [10] { - iter_var: @c:0 + iter_var: @it:1:0 iter_range: { LIST [11] { elements: { @@ -2750,7 +2398,7 @@ CALL [1] { } } } - accu_var: @x:0 + accu_var: @ac:1:0 accu_init: { LIST [14] { elements: { @@ -2765,7 +2413,7 @@ CALL [1] { function: _+_ args: { IDENT [17] { - name: @x:0 + name: @ac:1:0 } LIST [18] { elements: { @@ -2786,12 +2434,12 @@ CALL [1] { } result: { IDENT [22] { - name: @x:0 + name: @ac:1:0 } } } } - accu_var: @x:1 + accu_var: @ac:0:0 accu_init: { LIST [23] { elements: { @@ -2806,7 +2454,7 @@ CALL [1] { function: _+_ args: { IDENT [26] { - name: @x:1 + name: @ac:0:0 } LIST [27] { elements: { @@ -2827,7 +2475,7 @@ CALL [1] { } result: { IDENT [31] { - name: @x:1 + name: @ac:0:0 } } } diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_1.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_1.baseline index bcfc70fb1..070df4db9 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_1.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_1.baseline @@ -1436,130 +1436,90 @@ CALL [1] { CONSTANT [4] { value: 1 } } } - LIST [5] { - elements: { - CONSTANT [6] { value: 2 } - } - } - CALL [7] { + CALL [5] { function: _>_ args: { - IDENT [8] { - name: @c:0 + IDENT [6] { + name: @it:0:0 } - CONSTANT [9] { value: 0 } + CONSTANT [7] { value: 0 } } } - CALL [10] { + CALL [8] { function: _||_ args: { - IDENT [11] { - name: @x:0 + IDENT [9] { + name: @ac:0:0 } - IDENT [12] { - name: @index2 + IDENT [10] { + name: @index1 } } } + LIST [11] { + elements: { + CONSTANT [12] { value: 2 } + } + } CALL [13] { function: _>_ args: { IDENT [14] { - name: @c:1 + name: @it:0:0 } - CONSTANT [15] { value: 0 } + CONSTANT [15] { value: 1 } } } CALL [16] { function: _||_ args: { IDENT [17] { - name: @x:1 + name: @ac:0:0 } IDENT [18] { name: @index4 } } } - CALL [19] { - function: _>_ - args: { - IDENT [20] { - name: @c:2 - } - CONSTANT [21] { value: 1 } - } - } - CALL [22] { - function: _||_ - args: { - IDENT [23] { - name: @x:2 - } - IDENT [24] { - name: @index6 - } - } - } - CALL [25] { - function: _>_ - args: { - IDENT [26] { - name: @c:3 - } - CONSTANT [27] { value: 1 } - } - } - CALL [28] { - function: _||_ - args: { - IDENT [29] { - name: @x:3 - } - IDENT [30] { - name: @index8 - } - } - } } } - CALL [31] { + CALL [19] { function: _==_ args: { - CALL [32] { + CALL [20] { function: _+_ args: { - CALL [33] { + CALL [21] { function: _+_ args: { - CALL [34] { + CALL [22] { function: _+_ args: { - CALL [35] { + CALL [23] { function: size args: { - LIST [36] { + LIST [24] { elements: { - COMPREHENSION [37] { - iter_var: @c:0 + COMPREHENSION [25] { + iter_var: @it:0:0 iter_range: { - IDENT [38] { + IDENT [26] { name: @index0 } } - accu_var: @x:0 + accu_var: @ac:0:0 accu_init: { - CONSTANT [39] { value: false } + CONSTANT [27] { value: false } } loop_condition: { - CALL [40] { + CALL [28] { function: @not_strictly_false args: { - CALL [41] { + CALL [29] { function: !_ args: { - IDENT [42] { - name: @x:0 + IDENT [30] { + name: @ac:0:0 } } } @@ -1567,13 +1527,13 @@ CALL [1] { } } loop_step: { - IDENT [43] { - name: @index3 + IDENT [31] { + name: @index2 } } result: { - IDENT [44] { - name: @x:0 + IDENT [32] { + name: @ac:0:0 } } } @@ -1581,31 +1541,31 @@ CALL [1] { } } } - CALL [45] { + CALL [33] { function: size args: { - LIST [46] { + LIST [34] { elements: { - COMPREHENSION [47] { - iter_var: @c:1 + COMPREHENSION [35] { + iter_var: @it:0:0 iter_range: { - IDENT [48] { + IDENT [36] { name: @index0 } } - accu_var: @x:1 + accu_var: @ac:0:0 accu_init: { - CONSTANT [49] { value: false } + CONSTANT [37] { value: false } } loop_condition: { - CALL [50] { + CALL [38] { function: @not_strictly_false args: { - CALL [51] { + CALL [39] { function: !_ args: { - IDENT [52] { - name: @x:1 + IDENT [40] { + name: @ac:0:0 } } } @@ -1613,13 +1573,13 @@ CALL [1] { } } loop_step: { - IDENT [53] { - name: @index5 + IDENT [41] { + name: @index2 } } result: { - IDENT [54] { - name: @x:1 + IDENT [42] { + name: @ac:0:0 } } } @@ -1629,31 +1589,31 @@ CALL [1] { } } } - CALL [55] { + CALL [43] { function: size args: { - LIST [56] { + LIST [44] { elements: { - COMPREHENSION [57] { - iter_var: @c:2 + COMPREHENSION [45] { + iter_var: @it:0:0 iter_range: { - IDENT [58] { - name: @index1 + IDENT [46] { + name: @index3 } } - accu_var: @x:2 + accu_var: @ac:0:0 accu_init: { - CONSTANT [59] { value: false } + CONSTANT [47] { value: false } } loop_condition: { - CALL [60] { + CALL [48] { function: @not_strictly_false args: { - CALL [61] { + CALL [49] { function: !_ args: { - IDENT [62] { - name: @x:2 + IDENT [50] { + name: @ac:0:0 } } } @@ -1661,13 +1621,13 @@ CALL [1] { } } loop_step: { - IDENT [63] { - name: @index7 + IDENT [51] { + name: @index5 } } result: { - IDENT [64] { - name: @x:2 + IDENT [52] { + name: @ac:0:0 } } } @@ -1677,31 +1637,31 @@ CALL [1] { } } } - CALL [65] { + CALL [53] { function: size args: { - LIST [66] { + LIST [54] { elements: { - COMPREHENSION [67] { - iter_var: @c:3 + COMPREHENSION [55] { + iter_var: @it:0:0 iter_range: { - IDENT [68] { - name: @index1 + IDENT [56] { + name: @index3 } } - accu_var: @x:3 + accu_var: @ac:0:0 accu_init: { - CONSTANT [69] { value: false } + CONSTANT [57] { value: false } } loop_condition: { - CALL [70] { + CALL [58] { function: @not_strictly_false args: { - CALL [71] { + CALL [59] { function: !_ args: { - IDENT [72] { - name: @x:3 + IDENT [60] { + name: @ac:0:0 } } } @@ -1709,13 +1669,13 @@ CALL [1] { } } loop_step: { - IDENT [73] { - name: @index9 + IDENT [61] { + name: @index5 } } result: { - IDENT [74] { - name: @x:3 + IDENT [62] { + name: @ac:0:0 } } } @@ -1725,7 +1685,7 @@ CALL [1] { } } } - CONSTANT [75] { value: 4 } + CONSTANT [63] { value: 4 } } } } @@ -1743,135 +1703,95 @@ CALL [1] { CONSTANT [4] { value: 1 } } } - LIST [5] { - elements: { - CONSTANT [6] { value: "a" } - } - } - CALL [7] { + CALL [5] { function: _>_ args: { - IDENT [8] { - name: @c:0 + IDENT [6] { + name: @it:0:0 } - CONSTANT [9] { value: 0 } + CONSTANT [7] { value: 0 } } } - CALL [10] { + CALL [8] { function: _||_ args: { - IDENT [11] { - name: @x:0 + IDENT [9] { + name: @ac:0:0 } - IDENT [12] { - name: @index2 + IDENT [10] { + name: @index1 } } } + LIST [11] { + elements: { + CONSTANT [12] { value: "a" } + } + } CALL [13] { - function: _>_ + function: _==_ args: { IDENT [14] { - name: @c:1 + name: @it:0:1 } - CONSTANT [15] { value: 0 } + CONSTANT [15] { value: "a" } } } CALL [16] { function: _||_ args: { IDENT [17] { - name: @x:1 + name: @ac:0:1 } IDENT [18] { name: @index4 } } } - CALL [19] { - function: _==_ - args: { - IDENT [20] { - name: @c:2 - } - CONSTANT [21] { value: "a" } - } - } - CALL [22] { - function: _||_ - args: { - IDENT [23] { - name: @x:2 - } - IDENT [24] { - name: @index6 - } - } - } - CALL [25] { - function: _==_ - args: { - IDENT [26] { - name: @c:3 - } - CONSTANT [27] { value: "a" } - } - } - CALL [28] { - function: _||_ - args: { - IDENT [29] { - name: @x:3 - } - IDENT [30] { - name: @index8 - } - } - } - LIST [31] { + LIST [19] { elements: { - CONSTANT [32] { value: true } - CONSTANT [33] { value: true } - CONSTANT [34] { value: true } - CONSTANT [35] { value: true } + CONSTANT [20] { value: true } + CONSTANT [21] { value: true } + CONSTANT [22] { value: true } + CONSTANT [23] { value: true } } } } } - CALL [36] { + CALL [24] { function: _==_ args: { - CALL [37] { + CALL [25] { function: _+_ args: { - CALL [38] { + CALL [26] { function: _+_ args: { - CALL [39] { + CALL [27] { function: _+_ args: { - LIST [40] { + LIST [28] { elements: { - COMPREHENSION [41] { - iter_var: @c:0 + COMPREHENSION [29] { + iter_var: @it:0:0 iter_range: { - IDENT [42] { + IDENT [30] { name: @index0 } } - accu_var: @x:0 + accu_var: @ac:0:0 accu_init: { - CONSTANT [43] { value: false } + CONSTANT [31] { value: false } } loop_condition: { - CALL [44] { + CALL [32] { function: @not_strictly_false args: { - CALL [45] { + CALL [33] { function: !_ args: { - IDENT [46] { - name: @x:0 + IDENT [34] { + name: @ac:0:0 } } } @@ -1879,40 +1799,40 @@ CALL [1] { } } loop_step: { - IDENT [47] { - name: @index3 + IDENT [35] { + name: @index2 } } result: { - IDENT [48] { - name: @x:0 + IDENT [36] { + name: @ac:0:0 } } } } } - LIST [49] { + LIST [37] { elements: { - COMPREHENSION [50] { - iter_var: @c:1 + COMPREHENSION [38] { + iter_var: @it:0:0 iter_range: { - IDENT [51] { + IDENT [39] { name: @index0 } } - accu_var: @x:1 + accu_var: @ac:0:0 accu_init: { - CONSTANT [52] { value: false } + CONSTANT [40] { value: false } } loop_condition: { - CALL [53] { + CALL [41] { function: @not_strictly_false args: { - CALL [54] { + CALL [42] { function: !_ args: { - IDENT [55] { - name: @x:1 + IDENT [43] { + name: @ac:0:0 } } } @@ -1920,13 +1840,13 @@ CALL [1] { } } loop_step: { - IDENT [56] { - name: @index5 + IDENT [44] { + name: @index2 } } result: { - IDENT [57] { - name: @x:1 + IDENT [45] { + name: @ac:0:0 } } } @@ -1934,28 +1854,28 @@ CALL [1] { } } } - LIST [58] { + LIST [46] { elements: { - COMPREHENSION [59] { - iter_var: @c:2 + COMPREHENSION [47] { + iter_var: @it:0:1 iter_range: { - IDENT [60] { - name: @index1 + IDENT [48] { + name: @index3 } } - accu_var: @x:2 + accu_var: @ac:0:1 accu_init: { - CONSTANT [61] { value: false } + CONSTANT [49] { value: false } } loop_condition: { - CALL [62] { + CALL [50] { function: @not_strictly_false args: { - CALL [63] { + CALL [51] { function: !_ args: { - IDENT [64] { - name: @x:2 + IDENT [52] { + name: @ac:0:1 } } } @@ -1963,13 +1883,13 @@ CALL [1] { } } loop_step: { - IDENT [65] { - name: @index7 + IDENT [53] { + name: @index5 } } result: { - IDENT [66] { - name: @x:2 + IDENT [54] { + name: @ac:0:1 } } } @@ -1977,28 +1897,28 @@ CALL [1] { } } } - LIST [67] { + LIST [55] { elements: { - COMPREHENSION [68] { - iter_var: @c:3 + COMPREHENSION [56] { + iter_var: @it:0:1 iter_range: { - IDENT [69] { - name: @index1 + IDENT [57] { + name: @index3 } } - accu_var: @x:3 + accu_var: @ac:0:1 accu_init: { - CONSTANT [70] { value: false } + CONSTANT [58] { value: false } } loop_condition: { - CALL [71] { + CALL [59] { function: @not_strictly_false args: { - CALL [72] { + CALL [60] { function: !_ args: { - IDENT [73] { - name: @x:3 + IDENT [61] { + name: @ac:0:1 } } } @@ -2006,13 +1926,13 @@ CALL [1] { } } loop_step: { - IDENT [74] { - name: @index9 + IDENT [62] { + name: @index5 } } result: { - IDENT [75] { - name: @x:3 + IDENT [63] { + name: @ac:0:1 } } } @@ -2020,8 +1940,8 @@ CALL [1] { } } } - IDENT [76] { - name: @index10 + IDENT [64] { + name: @index6 } } } @@ -2044,7 +1964,7 @@ CALL [1] { function: _>_ args: { IDENT [6] { - name: @c:0 + name: @it:0:0 } CONSTANT [7] { value: 0 } } @@ -2053,7 +1973,7 @@ CALL [1] { function: _||_ args: { IDENT [9] { - name: @x:0 + name: @ac:0:0 } IDENT [10] { name: @index1 @@ -2064,95 +1984,55 @@ CALL [1] { function: _>_ args: { IDENT [12] { - name: @c:1 + name: @it:0:0 } - CONSTANT [13] { value: 0 } + CONSTANT [13] { value: 1 } } } CALL [14] { function: _||_ args: { IDENT [15] { - name: @x:1 + name: @ac:0:0 } IDENT [16] { name: @index3 } } } - CALL [17] { - function: _>_ - args: { - IDENT [18] { - name: @c:2 - } - CONSTANT [19] { value: 1 } - } - } - CALL [20] { - function: _||_ - args: { - IDENT [21] { - name: @x:2 - } - IDENT [22] { - name: @index5 - } - } - } - LIST [23] { + LIST [17] { elements: { - CONSTANT [24] { value: 2 } - } - } - CALL [25] { - function: _>_ - args: { - IDENT [26] { - name: @c:3 - } - CONSTANT [27] { value: 1 } - } - } - CALL [28] { - function: _||_ - args: { - IDENT [29] { - name: @x:3 - } - IDENT [30] { - name: @index8 - } + CONSTANT [18] { value: 2 } } } } } - CALL [31] { + CALL [19] { function: _&&_ args: { - CALL [32] { + CALL [20] { function: _&&_ args: { - COMPREHENSION [33] { - iter_var: @c:0 + COMPREHENSION [21] { + iter_var: @it:0:0 iter_range: { - IDENT [34] { + IDENT [22] { name: @index0 } } - accu_var: @x:0 + accu_var: @ac:0:0 accu_init: { - CONSTANT [35] { value: false } + CONSTANT [23] { value: false } } loop_condition: { - CALL [36] { + CALL [24] { function: @not_strictly_false args: { - CALL [37] { + CALL [25] { function: !_ args: { - IDENT [38] { - name: @x:0 + IDENT [26] { + name: @ac:0:0 } } } @@ -2160,36 +2040,36 @@ CALL [1] { } } loop_step: { - IDENT [39] { + IDENT [27] { name: @index2 } } result: { - IDENT [40] { - name: @x:0 + IDENT [28] { + name: @ac:0:0 } } } - COMPREHENSION [41] { - iter_var: @c:1 + COMPREHENSION [29] { + iter_var: @it:0:0 iter_range: { - IDENT [42] { + IDENT [30] { name: @index0 } } - accu_var: @x:1 + accu_var: @ac:0:0 accu_init: { - CONSTANT [43] { value: false } + CONSTANT [31] { value: false } } loop_condition: { - CALL [44] { + CALL [32] { function: @not_strictly_false args: { - CALL [45] { + CALL [33] { function: !_ args: { - IDENT [46] { - name: @x:1 + IDENT [34] { + name: @ac:0:0 } } } @@ -2197,41 +2077,41 @@ CALL [1] { } } loop_step: { - IDENT [47] { - name: @index4 + IDENT [35] { + name: @index2 } } result: { - IDENT [48] { - name: @x:1 + IDENT [36] { + name: @ac:0:0 } } } } } - CALL [49] { + CALL [37] { function: _&&_ args: { - COMPREHENSION [50] { - iter_var: @c:2 + COMPREHENSION [38] { + iter_var: @it:0:0 iter_range: { - IDENT [51] { + IDENT [39] { name: @index0 } } - accu_var: @x:2 + accu_var: @ac:0:0 accu_init: { - CONSTANT [52] { value: false } + CONSTANT [40] { value: false } } loop_condition: { - CALL [53] { + CALL [41] { function: @not_strictly_false args: { - CALL [54] { + CALL [42] { function: !_ args: { - IDENT [55] { - name: @x:2 + IDENT [43] { + name: @ac:0:0 } } } @@ -2239,36 +2119,36 @@ CALL [1] { } } loop_step: { - IDENT [56] { - name: @index6 + IDENT [44] { + name: @index4 } } result: { - IDENT [57] { - name: @x:2 + IDENT [45] { + name: @ac:0:0 } } } - COMPREHENSION [58] { - iter_var: @c:3 + COMPREHENSION [46] { + iter_var: @it:0:0 iter_range: { - IDENT [59] { - name: @index7 + IDENT [47] { + name: @index5 } } - accu_var: @x:3 + accu_var: @ac:0:0 accu_init: { - CONSTANT [60] { value: false } + CONSTANT [48] { value: false } } loop_condition: { - CALL [61] { + CALL [49] { function: @not_strictly_false args: { - CALL [62] { + CALL [50] { function: !_ args: { - IDENT [63] { - name: @x:3 + IDENT [51] { + name: @ac:0:0 } } } @@ -2276,13 +2156,13 @@ CALL [1] { } } loop_step: { - IDENT [64] { - name: @index9 + IDENT [52] { + name: @index4 } } result: { - IDENT [65] { - name: @x:3 + IDENT [53] { + name: @ac:0:0 } } } @@ -2318,7 +2198,7 @@ CALL [1] { function: _+_ args: { IDENT [12] { - name: @c:0 + name: @it:1:0 } CONSTANT [13] { value: 1 } } @@ -2334,7 +2214,7 @@ CALL [1] { function: _+_ args: { IDENT [17] { - name: @x:0 + name: @ac:1:0 } IDENT [18] { name: @index3 @@ -2360,13 +2240,13 @@ CALL [1] { function: _==_ args: { COMPREHENSION [24] { - iter_var: @c:1 + iter_var: @it:0:0 iter_range: { IDENT [25] { name: @index0 } } - accu_var: @x:1 + accu_var: @ac:0:0 accu_init: { LIST [26] { elements: { @@ -2381,18 +2261,18 @@ CALL [1] { function: _+_ args: { IDENT [29] { - name: @x:1 + name: @ac:0:0 } LIST [30] { elements: { COMPREHENSION [31] { - iter_var: @c:0 + iter_var: @it:1:0 iter_range: { IDENT [32] { name: @index0 } } - accu_var: @x:0 + accu_var: @ac:1:0 accu_init: { LIST [33] { elements: { @@ -2409,7 +2289,7 @@ CALL [1] { } result: { IDENT [36] { - name: @x:0 + name: @ac:1:0 } } } @@ -2420,7 +2300,7 @@ CALL [1] { } result: { IDENT [37] { - name: @x:1 + name: @ac:0:0 } } } @@ -2456,17 +2336,17 @@ CALL [1] { function: _==_ args: { IDENT [11] { - name: @c:0 + name: @it:1:0 } IDENT [12] { - name: @c:1 + name: @it:0:0 } } } LIST [13] { elements: { IDENT [14] { - name: @c:0 + name: @it:1:0 } } } @@ -2474,7 +2354,7 @@ CALL [1] { function: _+_ args: { IDENT [16] { - name: @x:0 + name: @ac:1:0 } IDENT [17] { name: @index3 @@ -2491,7 +2371,7 @@ CALL [1] { name: @index4 } IDENT [21] { - name: @x:0 + name: @ac:1:0 } } } @@ -2521,13 +2401,13 @@ CALL [1] { function: _==_ args: { COMPREHENSION [30] { - iter_var: @c:1 + iter_var: @it:0:0 iter_range: { IDENT [31] { name: @index0 } } - accu_var: @x:1 + accu_var: @ac:0:0 accu_init: { LIST [32] { elements: { @@ -2542,18 +2422,18 @@ CALL [1] { function: _+_ args: { IDENT [35] { - name: @x:1 + name: @ac:0:0 } LIST [36] { elements: { COMPREHENSION [37] { - iter_var: @c:0 + iter_var: @it:1:0 iter_range: { IDENT [38] { name: @index1 } } - accu_var: @x:0 + accu_var: @ac:1:0 accu_init: { LIST [39] { elements: { @@ -2570,7 +2450,7 @@ CALL [1] { } result: { IDENT [42] { - name: @x:0 + name: @ac:1:0 } } } @@ -2581,7 +2461,7 @@ CALL [1] { } result: { IDENT [43] { - name: @x:1 + name: @ac:0:0 } } } @@ -2611,7 +2491,7 @@ CALL [1] { function: _+_ args: { IDENT [8] { - name: @c:0 + name: @it:1:0 } CONSTANT [9] { value: 1 } } @@ -2627,96 +2507,69 @@ CALL [1] { function: _+_ args: { IDENT [13] { - name: @x:0 + name: @ac:1:0 } IDENT [14] { name: @index2 } } } - CALL [15] { - function: _+_ - args: { - IDENT [16] { - name: @c:2 - } - CONSTANT [17] { value: 1 } - } - } - LIST [18] { - elements: { - IDENT [19] { - name: @index4 - } - } - } - CALL [20] { - function: _+_ - args: { - IDENT [21] { - name: @x:2 - } - IDENT [22] { - name: @index5 - } - } - } } } - CALL [23] { + CALL [15] { function: _==_ args: { - COMPREHENSION [24] { - iter_var: @c:1 + COMPREHENSION [16] { + iter_var: @it:0:0 iter_range: { - IDENT [25] { + IDENT [17] { name: @index0 } } - accu_var: @x:1 + accu_var: @ac:0:0 accu_init: { - LIST [26] { + LIST [18] { elements: { } } } loop_condition: { - CONSTANT [27] { value: true } + CONSTANT [19] { value: true } } loop_step: { - CALL [28] { + CALL [20] { function: _+_ args: { - IDENT [29] { - name: @x:1 + IDENT [21] { + name: @ac:0:0 } - LIST [30] { + LIST [22] { elements: { - COMPREHENSION [31] { - iter_var: @c:0 + COMPREHENSION [23] { + iter_var: @it:1:0 iter_range: { - IDENT [32] { + IDENT [24] { name: @index0 } } - accu_var: @x:0 + accu_var: @ac:1:0 accu_init: { - LIST [33] { + LIST [25] { elements: { } } } loop_condition: { - CONSTANT [34] { value: true } + CONSTANT [26] { value: true } } loop_step: { - IDENT [35] { + IDENT [27] { name: @index3 } } result: { - IDENT [36] { - name: @x:0 + IDENT [28] { + name: @ac:1:0 } } } @@ -2726,62 +2579,62 @@ CALL [1] { } } result: { - IDENT [37] { - name: @x:1 + IDENT [29] { + name: @ac:0:0 } } } - COMPREHENSION [38] { - iter_var: @c:3 + COMPREHENSION [30] { + iter_var: @it:0:0 iter_range: { - IDENT [39] { + IDENT [31] { name: @index0 } } - accu_var: @x:3 + accu_var: @ac:0:0 accu_init: { - LIST [40] { + LIST [32] { elements: { } } } loop_condition: { - CONSTANT [41] { value: true } + CONSTANT [33] { value: true } } loop_step: { - CALL [42] { + CALL [34] { function: _+_ args: { - IDENT [43] { - name: @x:3 + IDENT [35] { + name: @ac:0:0 } - LIST [44] { + LIST [36] { elements: { - COMPREHENSION [45] { - iter_var: @c:2 + COMPREHENSION [37] { + iter_var: @it:1:0 iter_range: { - IDENT [46] { + IDENT [38] { name: @index0 } } - accu_var: @x:2 + accu_var: @ac:1:0 accu_init: { - LIST [47] { + LIST [39] { elements: { } } } loop_condition: { - CONSTANT [48] { value: true } + CONSTANT [40] { value: true } } loop_step: { - IDENT [49] { - name: @index6 + IDENT [41] { + name: @index3 } } result: { - IDENT [50] { - name: @x:2 + IDENT [42] { + name: @ac:1:0 } } } @@ -2791,8 +2644,8 @@ CALL [1] { } } result: { - IDENT [51] { - name: @x:3 + IDENT [43] { + name: @ac:0:0 } } } @@ -2989,7 +2842,7 @@ CALL [1] { function: _+_ args: { IDENT [15] { - name: @x:0 + name: @ac:1:0 } IDENT [16] { name: @index3 @@ -3012,13 +2865,13 @@ CALL [1] { function: _==_ args: { COMPREHENSION [21] { - iter_var: @c:1 + iter_var: @it:0:0 iter_range: { IDENT [22] { name: @index0 } } - accu_var: @x:1 + accu_var: @ac:0:0 accu_init: { LIST [23] { elements: { @@ -3033,18 +2886,18 @@ CALL [1] { function: _+_ args: { IDENT [26] { - name: @x:1 + name: @ac:0:0 } LIST [27] { elements: { COMPREHENSION [28] { - iter_var: @c:0 + iter_var: @it:1:0 iter_range: { IDENT [29] { name: @index0 } } - accu_var: @x:0 + accu_var: @ac:1:0 accu_init: { LIST [30] { elements: { @@ -3061,7 +2914,7 @@ CALL [1] { } result: { IDENT [33] { - name: @x:0 + name: @ac:1:0 } } } @@ -3072,7 +2925,7 @@ CALL [1] { } result: { IDENT [34] { - name: @x:1 + name: @ac:0:0 } } } @@ -3132,7 +2985,7 @@ CALL [1] { function: _-_ args: { IDENT [16] { - name: @c:0 + name: @it:0:0 } CONSTANT [17] { value: 1 } } @@ -3150,7 +3003,7 @@ CALL [1] { function: _||_ args: { IDENT [22] { - name: @x:0 + name: @ac:0:0 } IDENT [23] { name: @index5 @@ -3163,13 +3016,13 @@ CALL [1] { function: _||_ args: { COMPREHENSION [25] { - iter_var: @c:0 + iter_var: @it:0:0 iter_range: { IDENT [26] { name: @index3 } } - accu_var: @x:0 + accu_var: @ac:0:0 accu_init: { CONSTANT [27] { value: false } } @@ -3181,7 +3034,7 @@ CALL [1] { function: !_ args: { IDENT [30] { - name: @x:0 + name: @ac:0:0 } } } @@ -3195,7 +3048,7 @@ CALL [1] { } result: { IDENT [32] { - name: @x:0 + name: @ac:0:0 } } } @@ -3218,10 +3071,10 @@ CALL [1] { function: _+_ args: { IDENT [4] { - name: @c:0 + name: @it:1:0 } IDENT [5] { - name: @c:0 + name: @it:1:0 } } } @@ -3229,10 +3082,10 @@ CALL [1] { function: _+_ args: { IDENT [7] { - name: @c:1 + name: @it:0:0 } IDENT [8] { - name: @c:1 + name: @it:0:0 } } } @@ -3263,7 +3116,7 @@ CALL [1] { function: _+_ args: { IDENT [18] { - name: @x:0 + name: @ac:1:0 } IDENT [19] { name: @index4 @@ -3291,7 +3144,7 @@ CALL [1] { function: _+_ args: { IDENT [26] { - name: @x:1 + name: @ac:0:0 } IDENT [27] { name: @index7 @@ -3301,16 +3154,16 @@ CALL [1] { } } COMPREHENSION [28] { - iter_var: @c:1 + iter_var: @it:0:0 iter_range: { COMPREHENSION [29] { - iter_var: @c:0 + iter_var: @it:1:0 iter_range: { IDENT [30] { name: @index2 } } - accu_var: @x:0 + accu_var: @ac:1:0 accu_init: { LIST [31] { elements: { @@ -3327,12 +3180,12 @@ CALL [1] { } result: { IDENT [34] { - name: @x:0 + name: @ac:1:0 } } } } - accu_var: @x:1 + accu_var: @ac:0:0 accu_init: { LIST [35] { elements: { @@ -3349,7 +3202,7 @@ CALL [1] { } result: { IDENT [38] { - name: @x:1 + name: @ac:0:0 } } } diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_2.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_2.baseline index 7a46177d8..28336f2e3 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_2.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_2.baseline @@ -1252,123 +1252,89 @@ CALL [1] { args: { LIST [2] { elements: { - LIST [3] { - elements: { - CONSTANT [4] { value: 1 } - } - } - LIST [5] { - elements: { - CONSTANT [6] { value: 2 } - } - } - CALL [7] { + CALL [3] { function: _||_ args: { - IDENT [8] { - name: @x:0 + IDENT [4] { + name: @ac:0:0 } - CALL [9] { + CALL [5] { function: _>_ args: { - IDENT [10] { - name: @c:0 + IDENT [6] { + name: @it:0:0 } - CONSTANT [11] { value: 0 } + CONSTANT [7] { value: 0 } } } } } - CALL [12] { + CALL [8] { function: _||_ args: { - IDENT [13] { - name: @x:1 + IDENT [9] { + name: @ac:0:0 } - CALL [14] { + CALL [10] { function: _>_ args: { - IDENT [15] { - name: @c:1 + IDENT [11] { + name: @it:0:0 } - CONSTANT [16] { value: 0 } + CONSTANT [12] { value: 1 } } } } } - CALL [17] { - function: _||_ - args: { - IDENT [18] { - name: @x:2 - } - CALL [19] { - function: _>_ - args: { - IDENT [20] { - name: @c:2 - } - CONSTANT [21] { value: 1 } - } - } + LIST [13] { + elements: { + CONSTANT [14] { value: 1 } } } - CALL [22] { - function: _||_ - args: { - IDENT [23] { - name: @x:3 - } - CALL [24] { - function: _>_ - args: { - IDENT [25] { - name: @c:3 - } - CONSTANT [26] { value: 1 } - } - } + LIST [15] { + elements: { + CONSTANT [16] { value: 2 } } } } } - CALL [27] { + CALL [17] { function: _==_ args: { - CALL [28] { + CALL [18] { function: _+_ args: { - CALL [29] { + CALL [19] { function: _+_ args: { - CALL [30] { + CALL [20] { function: _+_ args: { - CALL [31] { + CALL [21] { function: size args: { - LIST [32] { + LIST [22] { elements: { - COMPREHENSION [33] { - iter_var: @c:0 + COMPREHENSION [23] { + iter_var: @it:0:0 iter_range: { - IDENT [34] { - name: @index0 + IDENT [24] { + name: @index2 } } - accu_var: @x:0 + accu_var: @ac:0:0 accu_init: { - CONSTANT [35] { value: false } + CONSTANT [25] { value: false } } loop_condition: { - CALL [36] { + CALL [26] { function: @not_strictly_false args: { - CALL [37] { + CALL [27] { function: !_ args: { - IDENT [38] { - name: @x:0 + IDENT [28] { + name: @ac:0:0 } } } @@ -1376,13 +1342,13 @@ CALL [1] { } } loop_step: { - IDENT [39] { - name: @index2 + IDENT [29] { + name: @index0 } } result: { - IDENT [40] { - name: @x:0 + IDENT [30] { + name: @ac:0:0 } } } @@ -1390,31 +1356,31 @@ CALL [1] { } } } - CALL [41] { + CALL [31] { function: size args: { - LIST [42] { + LIST [32] { elements: { - COMPREHENSION [43] { - iter_var: @c:1 + COMPREHENSION [33] { + iter_var: @it:0:0 iter_range: { - IDENT [44] { - name: @index0 + IDENT [34] { + name: @index2 } } - accu_var: @x:1 + accu_var: @ac:0:0 accu_init: { - CONSTANT [45] { value: false } + CONSTANT [35] { value: false } } loop_condition: { - CALL [46] { + CALL [36] { function: @not_strictly_false args: { - CALL [47] { + CALL [37] { function: !_ args: { - IDENT [48] { - name: @x:1 + IDENT [38] { + name: @ac:0:0 } } } @@ -1422,13 +1388,13 @@ CALL [1] { } } loop_step: { - IDENT [49] { - name: @index3 + IDENT [39] { + name: @index0 } } result: { - IDENT [50] { - name: @x:1 + IDENT [40] { + name: @ac:0:0 } } } @@ -1438,31 +1404,31 @@ CALL [1] { } } } - CALL [51] { + CALL [41] { function: size args: { - LIST [52] { + LIST [42] { elements: { - COMPREHENSION [53] { - iter_var: @c:2 + COMPREHENSION [43] { + iter_var: @it:0:0 iter_range: { - IDENT [54] { - name: @index1 + IDENT [44] { + name: @index3 } } - accu_var: @x:2 + accu_var: @ac:0:0 accu_init: { - CONSTANT [55] { value: false } + CONSTANT [45] { value: false } } loop_condition: { - CALL [56] { + CALL [46] { function: @not_strictly_false args: { - CALL [57] { + CALL [47] { function: !_ args: { - IDENT [58] { - name: @x:2 + IDENT [48] { + name: @ac:0:0 } } } @@ -1470,13 +1436,13 @@ CALL [1] { } } loop_step: { - IDENT [59] { - name: @index4 + IDENT [49] { + name: @index1 } } result: { - IDENT [60] { - name: @x:2 + IDENT [50] { + name: @ac:0:0 } } } @@ -1486,31 +1452,31 @@ CALL [1] { } } } - CALL [61] { + CALL [51] { function: size args: { - LIST [62] { + LIST [52] { elements: { - COMPREHENSION [63] { - iter_var: @c:3 + COMPREHENSION [53] { + iter_var: @it:0:0 iter_range: { - IDENT [64] { - name: @index1 + IDENT [54] { + name: @index3 } } - accu_var: @x:3 + accu_var: @ac:0:0 accu_init: { - CONSTANT [65] { value: false } + CONSTANT [55] { value: false } } loop_condition: { - CALL [66] { + CALL [56] { function: @not_strictly_false args: { - CALL [67] { + CALL [57] { function: !_ args: { - IDENT [68] { - name: @x:3 + IDENT [58] { + name: @ac:0:0 } } } @@ -1518,13 +1484,13 @@ CALL [1] { } } loop_step: { - IDENT [69] { - name: @index5 + IDENT [59] { + name: @index1 } } result: { - IDENT [70] { - name: @x:3 + IDENT [60] { + name: @ac:0:0 } } } @@ -1534,7 +1500,7 @@ CALL [1] { } } } - CONSTANT [71] { value: 4 } + CONSTANT [61] { value: 4 } } } } @@ -1547,128 +1513,94 @@ CALL [1] { args: { LIST [2] { elements: { - LIST [3] { - elements: { - CONSTANT [4] { value: 1 } - } - } - LIST [5] { - elements: { - CONSTANT [6] { value: "a" } - } - } - CALL [7] { + CALL [3] { function: _||_ args: { - IDENT [8] { - name: @x:0 + IDENT [4] { + name: @ac:0:0 } - CALL [9] { + CALL [5] { function: _>_ args: { - IDENT [10] { - name: @c:0 + IDENT [6] { + name: @it:0:0 } - CONSTANT [11] { value: 0 } + CONSTANT [7] { value: 0 } } } } } - CALL [12] { + CALL [8] { function: _||_ args: { - IDENT [13] { - name: @x:1 + IDENT [9] { + name: @ac:0:1 } - CALL [14] { - function: _>_ + CALL [10] { + function: _==_ args: { - IDENT [15] { - name: @c:1 + IDENT [11] { + name: @it:0:1 } - CONSTANT [16] { value: 0 } + CONSTANT [12] { value: "a" } } } } } - CALL [17] { - function: _||_ - args: { - IDENT [18] { - name: @x:2 - } - CALL [19] { - function: _==_ - args: { - IDENT [20] { - name: @c:2 - } - CONSTANT [21] { value: "a" } - } - } + LIST [13] { + elements: { + CONSTANT [14] { value: 1 } } } - CALL [22] { - function: _||_ - args: { - IDENT [23] { - name: @x:3 - } - CALL [24] { - function: _==_ - args: { - IDENT [25] { - name: @c:3 - } - CONSTANT [26] { value: "a" } - } - } + LIST [15] { + elements: { + CONSTANT [16] { value: "a" } } } - LIST [27] { + LIST [17] { elements: { - CONSTANT [28] { value: true } - CONSTANT [29] { value: true } - CONSTANT [30] { value: true } - CONSTANT [31] { value: true } + CONSTANT [18] { value: true } + CONSTANT [19] { value: true } + CONSTANT [20] { value: true } + CONSTANT [21] { value: true } } } } } - CALL [32] { + CALL [22] { function: _==_ args: { - CALL [33] { + CALL [23] { function: _+_ args: { - CALL [34] { + CALL [24] { function: _+_ args: { - CALL [35] { + CALL [25] { function: _+_ args: { - LIST [36] { + LIST [26] { elements: { - COMPREHENSION [37] { - iter_var: @c:0 + COMPREHENSION [27] { + iter_var: @it:0:0 iter_range: { - IDENT [38] { - name: @index0 + IDENT [28] { + name: @index2 } } - accu_var: @x:0 + accu_var: @ac:0:0 accu_init: { - CONSTANT [39] { value: false } + CONSTANT [29] { value: false } } loop_condition: { - CALL [40] { + CALL [30] { function: @not_strictly_false args: { - CALL [41] { + CALL [31] { function: !_ args: { - IDENT [42] { - name: @x:0 + IDENT [32] { + name: @ac:0:0 } } } @@ -1676,40 +1608,40 @@ CALL [1] { } } loop_step: { - IDENT [43] { - name: @index2 + IDENT [33] { + name: @index0 } } result: { - IDENT [44] { - name: @x:0 + IDENT [34] { + name: @ac:0:0 } } } } } - LIST [45] { + LIST [35] { elements: { - COMPREHENSION [46] { - iter_var: @c:1 + COMPREHENSION [36] { + iter_var: @it:0:0 iter_range: { - IDENT [47] { - name: @index0 + IDENT [37] { + name: @index2 } } - accu_var: @x:1 + accu_var: @ac:0:0 accu_init: { - CONSTANT [48] { value: false } + CONSTANT [38] { value: false } } loop_condition: { - CALL [49] { + CALL [39] { function: @not_strictly_false args: { - CALL [50] { + CALL [40] { function: !_ args: { - IDENT [51] { - name: @x:1 + IDENT [41] { + name: @ac:0:0 } } } @@ -1717,13 +1649,13 @@ CALL [1] { } } loop_step: { - IDENT [52] { - name: @index3 + IDENT [42] { + name: @index0 } } result: { - IDENT [53] { - name: @x:1 + IDENT [43] { + name: @ac:0:0 } } } @@ -1731,28 +1663,28 @@ CALL [1] { } } } - LIST [54] { + LIST [44] { elements: { - COMPREHENSION [55] { - iter_var: @c:2 + COMPREHENSION [45] { + iter_var: @it:0:1 iter_range: { - IDENT [56] { - name: @index1 + IDENT [46] { + name: @index3 } } - accu_var: @x:2 + accu_var: @ac:0:1 accu_init: { - CONSTANT [57] { value: false } + CONSTANT [47] { value: false } } loop_condition: { - CALL [58] { + CALL [48] { function: @not_strictly_false args: { - CALL [59] { + CALL [49] { function: !_ args: { - IDENT [60] { - name: @x:2 + IDENT [50] { + name: @ac:0:1 } } } @@ -1760,13 +1692,13 @@ CALL [1] { } } loop_step: { - IDENT [61] { - name: @index4 + IDENT [51] { + name: @index1 } } result: { - IDENT [62] { - name: @x:2 + IDENT [52] { + name: @ac:0:1 } } } @@ -1774,28 +1706,28 @@ CALL [1] { } } } - LIST [63] { + LIST [53] { elements: { - COMPREHENSION [64] { - iter_var: @c:3 + COMPREHENSION [54] { + iter_var: @it:0:1 iter_range: { - IDENT [65] { - name: @index1 + IDENT [55] { + name: @index3 } } - accu_var: @x:3 + accu_var: @ac:0:1 accu_init: { - CONSTANT [66] { value: false } + CONSTANT [56] { value: false } } loop_condition: { - CALL [67] { + CALL [57] { function: @not_strictly_false args: { - CALL [68] { + CALL [58] { function: !_ args: { - IDENT [69] { - name: @x:3 + IDENT [59] { + name: @ac:0:1 } } } @@ -1803,13 +1735,13 @@ CALL [1] { } } loop_step: { - IDENT [70] { - name: @index5 + IDENT [60] { + name: @index1 } } result: { - IDENT [71] { - name: @x:3 + IDENT [61] { + name: @ac:0:1 } } } @@ -1817,8 +1749,8 @@ CALL [1] { } } } - IDENT [72] { - name: @index6 + IDENT [62] { + name: @index4 } } } @@ -1832,112 +1764,78 @@ CALL [1] { args: { LIST [2] { elements: { - LIST [3] { - elements: { - CONSTANT [4] { value: 1 } - } - } - CALL [5] { - function: _||_ - args: { - IDENT [6] { - name: @x:0 - } - CALL [7] { - function: _>_ - args: { - IDENT [8] { - name: @c:0 - } - CONSTANT [9] { value: 0 } - } - } - } - } - CALL [10] { + CALL [3] { function: _||_ args: { - IDENT [11] { - name: @x:1 + IDENT [4] { + name: @ac:0:0 } - CALL [12] { + CALL [5] { function: _>_ args: { - IDENT [13] { - name: @c:1 + IDENT [6] { + name: @it:0:0 } - CONSTANT [14] { value: 0 } + CONSTANT [7] { value: 0 } } } } } - CALL [15] { + CALL [8] { function: _||_ args: { - IDENT [16] { - name: @x:2 + IDENT [9] { + name: @ac:0:0 } - CALL [17] { + CALL [10] { function: _>_ args: { - IDENT [18] { - name: @c:2 + IDENT [11] { + name: @it:0:0 } - CONSTANT [19] { value: 1 } + CONSTANT [12] { value: 1 } } } } } - CALL [20] { - function: _||_ - args: { - IDENT [21] { - name: @x:3 - } - CALL [22] { - function: _>_ - args: { - IDENT [23] { - name: @c:3 - } - CONSTANT [24] { value: 1 } - } - } + LIST [13] { + elements: { + CONSTANT [14] { value: 1 } } } - LIST [25] { + LIST [15] { elements: { - CONSTANT [26] { value: 2 } + CONSTANT [16] { value: 2 } } } } } - CALL [27] { + CALL [17] { function: _&&_ args: { - CALL [28] { + CALL [18] { function: _&&_ args: { - COMPREHENSION [29] { - iter_var: @c:0 + COMPREHENSION [19] { + iter_var: @it:0:0 iter_range: { - IDENT [30] { - name: @index0 + IDENT [20] { + name: @index2 } } - accu_var: @x:0 + accu_var: @ac:0:0 accu_init: { - CONSTANT [31] { value: false } + CONSTANT [21] { value: false } } loop_condition: { - CALL [32] { + CALL [22] { function: @not_strictly_false args: { - CALL [33] { + CALL [23] { function: !_ args: { - IDENT [34] { - name: @x:0 + IDENT [24] { + name: @ac:0:0 } } } @@ -1945,36 +1843,36 @@ CALL [1] { } } loop_step: { - IDENT [35] { - name: @index1 + IDENT [25] { + name: @index0 } } result: { - IDENT [36] { - name: @x:0 + IDENT [26] { + name: @ac:0:0 } } } - COMPREHENSION [37] { - iter_var: @c:1 + COMPREHENSION [27] { + iter_var: @it:0:0 iter_range: { - IDENT [38] { - name: @index0 + IDENT [28] { + name: @index2 } } - accu_var: @x:1 + accu_var: @ac:0:0 accu_init: { - CONSTANT [39] { value: false } + CONSTANT [29] { value: false } } loop_condition: { - CALL [40] { + CALL [30] { function: @not_strictly_false args: { - CALL [41] { + CALL [31] { function: !_ args: { - IDENT [42] { - name: @x:1 + IDENT [32] { + name: @ac:0:0 } } } @@ -1982,41 +1880,41 @@ CALL [1] { } } loop_step: { - IDENT [43] { - name: @index2 + IDENT [33] { + name: @index0 } } result: { - IDENT [44] { - name: @x:1 + IDENT [34] { + name: @ac:0:0 } } } } } - CALL [45] { + CALL [35] { function: _&&_ args: { - COMPREHENSION [46] { - iter_var: @c:2 + COMPREHENSION [36] { + iter_var: @it:0:0 iter_range: { - IDENT [47] { - name: @index0 + IDENT [37] { + name: @index2 } } - accu_var: @x:2 + accu_var: @ac:0:0 accu_init: { - CONSTANT [48] { value: false } + CONSTANT [38] { value: false } } loop_condition: { - CALL [49] { + CALL [39] { function: @not_strictly_false args: { - CALL [50] { + CALL [40] { function: !_ args: { - IDENT [51] { - name: @x:2 + IDENT [41] { + name: @ac:0:0 } } } @@ -2024,36 +1922,36 @@ CALL [1] { } } loop_step: { - IDENT [52] { - name: @index3 + IDENT [42] { + name: @index1 } } result: { - IDENT [53] { - name: @x:2 + IDENT [43] { + name: @ac:0:0 } } } - COMPREHENSION [54] { - iter_var: @c:3 + COMPREHENSION [44] { + iter_var: @it:0:0 iter_range: { - IDENT [55] { - name: @index5 + IDENT [45] { + name: @index3 } } - accu_var: @x:3 + accu_var: @ac:0:0 accu_init: { - CONSTANT [56] { value: false } + CONSTANT [46] { value: false } } loop_condition: { - CALL [57] { + CALL [47] { function: @not_strictly_false args: { - CALL [58] { + CALL [48] { function: !_ args: { - IDENT [59] { - name: @x:3 + IDENT [49] { + name: @ac:0:0 } } } @@ -2061,13 +1959,13 @@ CALL [1] { } } loop_step: { - IDENT [60] { - name: @index4 + IDENT [50] { + name: @index1 } } result: { - IDENT [61] { - name: @x:3 + IDENT [51] { + name: @ac:0:0 } } } @@ -2105,7 +2003,7 @@ CALL [1] { function: _+_ args: { IDENT [13] { - name: @c:0 + name: @it:1:0 } CONSTANT [14] { value: 1 } } @@ -2113,13 +2011,13 @@ CALL [1] { } } COMPREHENSION [15] { - iter_var: @c:0 + iter_var: @it:1:0 iter_range: { IDENT [16] { name: @index0 } } - accu_var: @x:0 + accu_var: @ac:1:0 accu_init: { LIST [17] { elements: { @@ -2134,7 +2032,7 @@ CALL [1] { function: _+_ args: { IDENT [20] { - name: @x:0 + name: @ac:1:0 } IDENT [21] { name: @index2 @@ -2144,7 +2042,7 @@ CALL [1] { } result: { IDENT [22] { - name: @x:0 + name: @ac:1:0 } } } @@ -2152,7 +2050,7 @@ CALL [1] { function: _+_ args: { IDENT [24] { - name: @x:1 + name: @ac:0:0 } LIST [25] { elements: { @@ -2164,13 +2062,13 @@ CALL [1] { } } COMPREHENSION [27] { - iter_var: @c:1 + iter_var: @it:0:0 iter_range: { IDENT [28] { name: @index0 } } - accu_var: @x:1 + accu_var: @ac:0:0 accu_init: { LIST [29] { elements: { @@ -2187,7 +2085,7 @@ CALL [1] { } result: { IDENT [32] { - name: @x:1 + name: @ac:0:0 } } } @@ -2228,12 +2126,12 @@ CALL [1] { function: _+_ args: { IDENT [4] { - name: @x:0 + name: @ac:1:0 } LIST [5] { elements: { IDENT [6] { - name: @c:0 + name: @it:1:0 } } } @@ -2246,10 +2144,10 @@ CALL [1] { function: _==_ args: { IDENT [9] { - name: @c:0 + name: @it:1:0 } IDENT [10] { - name: @c:1 + name: @it:0:0 } } } @@ -2257,12 +2155,12 @@ CALL [1] { name: @index0 } IDENT [12] { - name: @x:0 + name: @ac:1:0 } } } COMPREHENSION [13] { - iter_var: @c:0 + iter_var: @it:1:0 iter_range: { LIST [14] { elements: { @@ -2272,7 +2170,7 @@ CALL [1] { } } } - accu_var: @x:0 + accu_var: @ac:1:0 accu_init: { LIST [18] { elements: { @@ -2289,7 +2187,7 @@ CALL [1] { } result: { IDENT [21] { - name: @x:0 + name: @ac:1:0 } } } @@ -2297,7 +2195,7 @@ CALL [1] { function: _+_ args: { IDENT [23] { - name: @x:1 + name: @ac:0:0 } LIST [24] { elements: { @@ -2309,7 +2207,7 @@ CALL [1] { } } COMPREHENSION [26] { - iter_var: @c:1 + iter_var: @it:0:0 iter_range: { LIST [27] { elements: { @@ -2318,7 +2216,7 @@ CALL [1] { } } } - accu_var: @x:1 + accu_var: @ac:0:0 accu_init: { LIST [30] { elements: { @@ -2335,7 +2233,7 @@ CALL [1] { } result: { IDENT [33] { - name: @x:1 + name: @ac:0:0 } } } @@ -2378,205 +2276,114 @@ CALL [1] { elements: { LIST [3] { elements: { - CONSTANT [4] { value: 1 } - CONSTANT [5] { value: 2 } - CONSTANT [6] { value: 3 } - } - } - LIST [7] { - elements: { - CALL [8] { - function: _+_ - args: { - IDENT [9] { - name: @c:0 - } - CONSTANT [10] { value: 1 } - } - } - } - } - COMPREHENSION [11] { - iter_var: @c:0 - iter_range: { - IDENT [12] { - name: @index0 - } - } - accu_var: @x:0 - accu_init: { - LIST [13] { - elements: { - } - } - } - loop_condition: { - CONSTANT [14] { value: true } - } - loop_step: { - CALL [15] { + CALL [4] { function: _+_ args: { - IDENT [16] { - name: @x:0 - } - IDENT [17] { - name: @index1 - } - } - } - } - result: { - IDENT [18] { - name: @x:0 - } - } - } - CALL [19] { - function: _+_ - args: { - IDENT [20] { - name: @x:1 - } - LIST [21] { - elements: { - IDENT [22] { - name: @index2 + IDENT [5] { + name: @it:1:0 } + CONSTANT [6] { value: 1 } } } } } - COMPREHENSION [23] { - iter_var: @c:1 + COMPREHENSION [7] { + iter_var: @it:1:0 iter_range: { - IDENT [24] { - name: @index0 - } - } - accu_var: @x:1 - accu_init: { - LIST [25] { + LIST [8] { elements: { + CONSTANT [9] { value: 1 } + CONSTANT [10] { value: 2 } + CONSTANT [11] { value: 3 } } } } - loop_condition: { - CONSTANT [26] { value: true } - } - loop_step: { - IDENT [27] { - name: @index3 - } - } - result: { - IDENT [28] { - name: @x:1 - } - } - } - LIST [29] { - elements: { - CALL [30] { - function: _+_ - args: { - IDENT [31] { - name: @c:2 - } - CONSTANT [32] { value: 1 } - } - } - } - } - COMPREHENSION [33] { - iter_var: @c:2 - iter_range: { - IDENT [34] { - name: @index0 - } - } - accu_var: @x:2 + accu_var: @ac:1:0 accu_init: { - LIST [35] { + LIST [12] { elements: { } } } loop_condition: { - CONSTANT [36] { value: true } + CONSTANT [13] { value: true } } loop_step: { - CALL [37] { + CALL [14] { function: _+_ args: { - IDENT [38] { - name: @x:2 + IDENT [15] { + name: @ac:1:0 } - IDENT [39] { - name: @index5 + IDENT [16] { + name: @index0 } } } } result: { - IDENT [40] { - name: @x:2 + IDENT [17] { + name: @ac:1:0 } } } - CALL [41] { + CALL [18] { function: _+_ args: { - IDENT [42] { - name: @x:3 + IDENT [19] { + name: @ac:0:0 } - LIST [43] { + LIST [20] { elements: { - IDENT [44] { - name: @index6 + IDENT [21] { + name: @index1 } } } } } - COMPREHENSION [45] { - iter_var: @c:3 + COMPREHENSION [22] { + iter_var: @it:0:0 iter_range: { - IDENT [46] { - name: @index0 + LIST [23] { + elements: { + CONSTANT [24] { value: 1 } + CONSTANT [25] { value: 2 } + CONSTANT [26] { value: 3 } + } } } - accu_var: @x:3 + accu_var: @ac:0:0 accu_init: { - LIST [47] { + LIST [27] { elements: { } } } loop_condition: { - CONSTANT [48] { value: true } + CONSTANT [28] { value: true } } loop_step: { - IDENT [49] { - name: @index7 + IDENT [29] { + name: @index2 } } result: { - IDENT [50] { - name: @x:3 + IDENT [30] { + name: @ac:0:0 } } } } } - CALL [51] { + CALL [31] { function: _==_ args: { - IDENT [52] { - name: @index4 + IDENT [32] { + name: @index3 } - IDENT [53] { - name: @index8 + IDENT [33] { + name: @index3 } } } @@ -2763,13 +2570,13 @@ CALL [1] { } } COMPREHENSION [17] { - iter_var: @c:0 + iter_var: @it:1:0 iter_range: { IDENT [18] { name: @index1 } } - accu_var: @x:0 + accu_var: @ac:1:0 accu_init: { LIST [19] { elements: { @@ -2784,7 +2591,7 @@ CALL [1] { function: _+_ args: { IDENT [22] { - name: @x:0 + name: @ac:1:0 } IDENT [23] { name: @index2 @@ -2794,7 +2601,7 @@ CALL [1] { } result: { IDENT [24] { - name: @x:0 + name: @ac:1:0 } } } @@ -2802,7 +2609,7 @@ CALL [1] { function: _+_ args: { IDENT [26] { - name: @x:1 + name: @ac:0:0 } LIST [27] { elements: { @@ -2814,13 +2621,13 @@ CALL [1] { } } COMPREHENSION [29] { - iter_var: @c:1 + iter_var: @it:0:0 iter_range: { IDENT [30] { name: @index1 } } - accu_var: @x:1 + accu_var: @ac:0:0 accu_init: { LIST [31] { elements: { @@ -2837,7 +2644,7 @@ CALL [1] { } result: { IDENT [34] { - name: @x:1 + name: @ac:0:0 } } } @@ -2911,7 +2718,7 @@ CALL [1] { function: _-_ args: { IDENT [16] { - name: @c:0 + name: @it:0:0 } CONSTANT [17] { value: 1 } } @@ -2930,7 +2737,7 @@ CALL [1] { function: _||_ args: { IDENT [22] { - name: @x:0 + name: @ac:0:0 } IDENT [23] { name: @index2 @@ -2943,13 +2750,13 @@ CALL [1] { function: _||_ args: { COMPREHENSION [25] { - iter_var: @c:0 + iter_var: @it:0:0 iter_range: { IDENT [26] { name: @index3 } } - accu_var: @x:0 + accu_var: @ac:0:0 accu_init: { CONSTANT [27] { value: false } } @@ -2961,7 +2768,7 @@ CALL [1] { function: !_ args: { IDENT [30] { - name: @x:0 + name: @ac:0:0 } } } @@ -2975,7 +2782,7 @@ CALL [1] { } result: { IDENT [32] { - name: @x:0 + name: @ac:0:0 } } } @@ -2998,10 +2805,10 @@ CALL [1] { function: _+_ args: { IDENT [4] { - name: @c:0 + name: @it:1:0 } IDENT [5] { - name: @c:0 + name: @it:1:0 } } } @@ -3009,10 +2816,10 @@ CALL [1] { function: _+_ args: { IDENT [7] { - name: @c:1 + name: @it:0:0 } IDENT [8] { - name: @c:1 + name: @it:0:0 } } } @@ -3031,7 +2838,7 @@ CALL [1] { } } COMPREHENSION [13] { - iter_var: @c:0 + iter_var: @it:1:0 iter_range: { LIST [14] { elements: { @@ -3040,7 +2847,7 @@ CALL [1] { } } } - accu_var: @x:0 + accu_var: @ac:1:0 accu_init: { LIST [17] { elements: { @@ -3055,7 +2862,7 @@ CALL [1] { function: _+_ args: { IDENT [20] { - name: @x:0 + name: @ac:1:0 } IDENT [21] { name: @index2 @@ -3065,7 +2872,7 @@ CALL [1] { } result: { IDENT [22] { - name: @x:0 + name: @ac:1:0 } } } @@ -3086,13 +2893,13 @@ CALL [1] { } } COMPREHENSION [27] { - iter_var: @c:1 + iter_var: @it:0:0 iter_range: { IDENT [28] { name: @index3 } } - accu_var: @x:1 + accu_var: @ac:0:0 accu_init: { LIST [29] { elements: { @@ -3107,7 +2914,7 @@ CALL [1] { function: _+_ args: { IDENT [32] { - name: @x:1 + name: @ac:0:0 } IDENT [33] { name: @index4 @@ -3117,7 +2924,7 @@ CALL [1] { } result: { IDENT [34] { - name: @x:1 + name: @ac:0:0 } } } diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_3.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_3.baseline index 6ecc6d04a..4018942c4 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_3.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_3.baseline @@ -1199,36 +1199,28 @@ CALL [1] { args: { LIST [2] { elements: { - LIST [3] { - elements: { - CONSTANT [4] { value: 1 } - } - } - LIST [5] { - elements: { - CONSTANT [6] { value: 2 } - } - } - COMPREHENSION [7] { - iter_var: @c:0 + COMPREHENSION [3] { + iter_var: @it:0:0 iter_range: { - IDENT [8] { - name: @index0 + LIST [4] { + elements: { + CONSTANT [5] { value: 1 } + } } } - accu_var: @x:0 + accu_var: @ac:0:0 accu_init: { - CONSTANT [9] { value: false } + CONSTANT [6] { value: false } } loop_condition: { - CALL [10] { + CALL [7] { function: @not_strictly_false args: { - CALL [11] { + CALL [8] { function: !_ args: { - IDENT [12] { - name: @x:0 + IDENT [9] { + name: @ac:0:0 } } } @@ -1236,50 +1228,52 @@ CALL [1] { } } loop_step: { - CALL [13] { + CALL [10] { function: _||_ args: { - IDENT [14] { - name: @x:0 + IDENT [11] { + name: @ac:0:0 } - CALL [15] { + CALL [12] { function: _>_ args: { - IDENT [16] { - name: @c:0 + IDENT [13] { + name: @it:0:0 } - CONSTANT [17] { value: 0 } + CONSTANT [14] { value: 0 } } } } } } result: { - IDENT [18] { - name: @x:0 + IDENT [15] { + name: @ac:0:0 } } } - COMPREHENSION [19] { - iter_var: @c:1 + COMPREHENSION [16] { + iter_var: @it:0:0 iter_range: { - IDENT [20] { - name: @index0 + LIST [17] { + elements: { + CONSTANT [18] { value: 2 } + } } } - accu_var: @x:1 + accu_var: @ac:0:0 accu_init: { - CONSTANT [21] { value: false } + CONSTANT [19] { value: false } } loop_condition: { - CALL [22] { + CALL [20] { function: @not_strictly_false args: { - CALL [23] { + CALL [21] { function: !_ args: { - IDENT [24] { - name: @x:1 + IDENT [22] { + name: @ac:0:0 } } } @@ -1287,210 +1281,90 @@ CALL [1] { } } loop_step: { - CALL [25] { + CALL [23] { function: _||_ args: { - IDENT [26] { - name: @x:1 + IDENT [24] { + name: @ac:0:0 } - CALL [27] { + CALL [25] { function: _>_ args: { - IDENT [28] { - name: @c:1 + IDENT [26] { + name: @it:0:0 } - CONSTANT [29] { value: 0 } + CONSTANT [27] { value: 1 } } } } } } result: { - IDENT [30] { - name: @x:1 + IDENT [28] { + name: @ac:0:0 } } } - CALL [31] { - function: _+_ + CALL [29] { + function: size args: { - CALL [32] { - function: size - args: { - LIST [33] { - elements: { - IDENT [34] { - name: @index2 - } - } - } - } - } - CALL [35] { - function: size - args: { - LIST [36] { - elements: { - IDENT [37] { - name: @index3 - } - } + LIST [30] { + elements: { + IDENT [31] { + name: @index0 } } } } } - COMPREHENSION [38] { - iter_var: @c:2 - iter_range: { - IDENT [39] { - name: @index1 - } - } - accu_var: @x:2 - accu_init: { - CONSTANT [40] { value: false } - } - loop_condition: { - CALL [41] { - function: @not_strictly_false - args: { - CALL [42] { - function: !_ - args: { - IDENT [43] { - name: @x:2 - } - } - } - } - } - } - loop_step: { - CALL [44] { - function: _||_ - args: { - IDENT [45] { - name: @x:2 - } - CALL [46] { - function: _>_ - args: { - IDENT [47] { - name: @c:2 - } - CONSTANT [48] { value: 1 } - } + CALL [32] { + function: size + args: { + LIST [33] { + elements: { + IDENT [34] { + name: @index1 } } } } - result: { - IDENT [49] { - name: @x:2 - } - } } - CALL [50] { + CALL [35] { function: _+_ args: { - IDENT [51] { - name: @index4 - } - CALL [52] { - function: size - args: { - LIST [53] { - elements: { - IDENT [54] { - name: @index5 - } - } - } - } - } - } - } - COMPREHENSION [55] { - iter_var: @c:3 - iter_range: { - IDENT [56] { - name: @index1 - } - } - accu_var: @x:3 - accu_init: { - CONSTANT [57] { value: false } - } - loop_condition: { - CALL [58] { - function: @not_strictly_false + CALL [36] { + function: _+_ args: { - CALL [59] { - function: !_ + CALL [37] { + function: _+_ args: { - IDENT [60] { - name: @x:3 + IDENT [38] { + name: @index2 } - } - } - } - } - } - loop_step: { - CALL [61] { - function: _||_ - args: { - IDENT [62] { - name: @x:3 - } - CALL [63] { - function: _>_ - args: { - IDENT [64] { - name: @c:3 + IDENT [39] { + name: @index2 } - CONSTANT [65] { value: 1 } } } - } - } - } - result: { - IDENT [66] { - name: @x:3 - } - } - } - CALL [67] { - function: _+_ - args: { - IDENT [68] { - name: @index6 - } - CALL [69] { - function: size - args: { - LIST [70] { - elements: { - IDENT [71] { - name: @index7 - } - } + IDENT [40] { + name: @index3 } } } + IDENT [41] { + name: @index3 + } } } } } - CALL [72] { + CALL [42] { function: _==_ args: { - IDENT [73] { - name: @index8 + IDENT [43] { + name: @index4 } - CONSTANT [74] { value: 4 } + CONSTANT [44] { value: 4 } } } } @@ -1503,36 +1377,28 @@ CALL [1] { args: { LIST [2] { elements: { - LIST [3] { - elements: { - CONSTANT [4] { value: 1 } - } - } - LIST [5] { - elements: { - CONSTANT [6] { value: "a" } - } - } - COMPREHENSION [7] { - iter_var: @c:0 + COMPREHENSION [3] { + iter_var: @it:0:0 iter_range: { - IDENT [8] { - name: @index0 + LIST [4] { + elements: { + CONSTANT [5] { value: 1 } + } } } - accu_var: @x:0 + accu_var: @ac:0:0 accu_init: { - CONSTANT [9] { value: false } + CONSTANT [6] { value: false } } loop_condition: { - CALL [10] { + CALL [7] { function: @not_strictly_false args: { - CALL [11] { + CALL [8] { function: !_ args: { - IDENT [12] { - name: @x:0 + IDENT [9] { + name: @ac:0:0 } } } @@ -1540,50 +1406,52 @@ CALL [1] { } } loop_step: { - CALL [13] { + CALL [10] { function: _||_ args: { - IDENT [14] { - name: @x:0 + IDENT [11] { + name: @ac:0:0 } - CALL [15] { + CALL [12] { function: _>_ args: { - IDENT [16] { - name: @c:0 + IDENT [13] { + name: @it:0:0 } - CONSTANT [17] { value: 0 } + CONSTANT [14] { value: 0 } } } } } } result: { - IDENT [18] { - name: @x:0 + IDENT [15] { + name: @ac:0:0 } } } - COMPREHENSION [19] { - iter_var: @c:1 + COMPREHENSION [16] { + iter_var: @it:0:1 iter_range: { - IDENT [20] { - name: @index0 + LIST [17] { + elements: { + CONSTANT [18] { value: "a" } + } } } - accu_var: @x:1 + accu_var: @ac:0:1 accu_init: { - CONSTANT [21] { value: false } + CONSTANT [19] { value: false } } loop_condition: { - CALL [22] { + CALL [20] { function: @not_strictly_false args: { - CALL [23] { + CALL [21] { function: !_ args: { - IDENT [24] { - name: @x:1 + IDENT [22] { + name: @ac:0:1 } } } @@ -1591,189 +1459,85 @@ CALL [1] { } } loop_step: { - CALL [25] { + CALL [23] { function: _||_ args: { - IDENT [26] { - name: @x:1 + IDENT [24] { + name: @ac:0:1 } - CALL [27] { - function: _>_ + CALL [25] { + function: _==_ args: { - IDENT [28] { - name: @c:1 + IDENT [26] { + name: @it:0:1 } - CONSTANT [29] { value: 0 } + CONSTANT [27] { value: "a" } } } } } } result: { + IDENT [28] { + name: @ac:0:1 + } + } + } + LIST [29] { + elements: { IDENT [30] { - name: @x:1 + name: @index0 } } } - COMPREHENSION [31] { - iter_var: @c:2 - iter_range: { + LIST [31] { + elements: { IDENT [32] { name: @index1 } } - accu_var: @x:2 - accu_init: { - CONSTANT [33] { value: false } - } - loop_condition: { - CALL [34] { - function: @not_strictly_false - args: { - CALL [35] { - function: !_ - args: { - IDENT [36] { - name: @x:2 - } - } - } - } - } - } - loop_step: { - CALL [37] { - function: _||_ - args: { - IDENT [38] { - name: @x:2 - } - CALL [39] { - function: _==_ - args: { - IDENT [40] { - name: @c:2 - } - CONSTANT [41] { value: "a" } - } - } - } - } - } - result: { - IDENT [42] { - name: @x:2 - } - } } - CALL [43] { + CALL [33] { function: _+_ args: { - CALL [44] { + CALL [34] { function: _+_ args: { - LIST [45] { - elements: { - IDENT [46] { - name: @index2 - } - } - } - LIST [47] { - elements: { - IDENT [48] { - name: @index3 - } - } - } - } - } - LIST [49] { - elements: { - IDENT [50] { - name: @index4 - } - } - } - } - } - COMPREHENSION [51] { - iter_var: @c:3 - iter_range: { - IDENT [52] { - name: @index1 - } - } - accu_var: @x:3 - accu_init: { - CONSTANT [53] { value: false } - } - loop_condition: { - CALL [54] { - function: @not_strictly_false - args: { - CALL [55] { - function: !_ - args: { - IDENT [56] { - name: @x:3 - } - } - } - } - } - } - loop_step: { - CALL [57] { - function: _||_ - args: { - IDENT [58] { - name: @x:3 - } - CALL [59] { - function: _==_ + CALL [35] { + function: _+_ args: { - IDENT [60] { - name: @c:3 + IDENT [36] { + name: @index2 + } + IDENT [37] { + name: @index2 } - CONSTANT [61] { value: "a" } } } + IDENT [38] { + name: @index3 + } } } - } - result: { - IDENT [62] { - name: @x:3 + IDENT [39] { + name: @index3 } } } } } - CALL [63] { + CALL [40] { function: _==_ args: { - CALL [64] { - function: _+_ - args: { - IDENT [65] { - name: @index5 - } - LIST [66] { - elements: { - IDENT [67] { - name: @index6 - } - } - } - } + IDENT [41] { + name: @index4 } - LIST [68] { + LIST [42] { elements: { - CONSTANT [69] { value: true } - CONSTANT [70] { value: true } - CONSTANT [71] { value: true } - CONSTANT [72] { value: true } + CONSTANT [43] { value: true } + CONSTANT [44] { value: true } + CONSTANT [45] { value: true } + CONSTANT [46] { value: true } } } } @@ -1788,31 +1552,28 @@ CALL [1] { args: { LIST [2] { elements: { - LIST [3] { - elements: { - CONSTANT [4] { value: 1 } - } - } - COMPREHENSION [5] { - iter_var: @c:0 + COMPREHENSION [3] { + iter_var: @it:0:0 iter_range: { - IDENT [6] { - name: @index0 + LIST [4] { + elements: { + CONSTANT [5] { value: 1 } + } } } - accu_var: @x:0 + accu_var: @ac:0:0 accu_init: { - CONSTANT [7] { value: false } + CONSTANT [6] { value: false } } loop_condition: { - CALL [8] { + CALL [7] { function: @not_strictly_false args: { - CALL [9] { + CALL [8] { function: !_ args: { - IDENT [10] { - name: @x:0 + IDENT [9] { + name: @ac:0:0 } } } @@ -1820,101 +1581,69 @@ CALL [1] { } } loop_step: { - CALL [11] { + CALL [10] { function: _||_ args: { - IDENT [12] { - name: @x:0 + IDENT [11] { + name: @ac:0:0 } - CALL [13] { + CALL [12] { function: _>_ args: { - IDENT [14] { - name: @c:0 + IDENT [13] { + name: @it:0:0 } - CONSTANT [15] { value: 0 } + CONSTANT [14] { value: 0 } } } } } } result: { - IDENT [16] { - name: @x:0 + IDENT [15] { + name: @ac:0:0 } } } - COMPREHENSION [17] { - iter_var: @c:1 - iter_range: { - IDENT [18] { - name: @index0 - } - } - accu_var: @x:1 - accu_init: { - CONSTANT [19] { value: false } - } - loop_condition: { - CALL [20] { - function: @not_strictly_false - args: { - CALL [21] { - function: !_ - args: { - IDENT [22] { - name: @x:1 - } - } - } - } + CALL [16] { + function: _||_ + args: { + IDENT [17] { + name: @ac:0:0 } - } - loop_step: { - CALL [23] { - function: _||_ + CALL [18] { + function: _>_ args: { - IDENT [24] { - name: @x:1 - } - CALL [25] { - function: _>_ - args: { - IDENT [26] { - name: @c:1 - } - CONSTANT [27] { value: 0 } - } + IDENT [19] { + name: @it:0:0 } + CONSTANT [20] { value: 1 } } } } - result: { - IDENT [28] { - name: @x:1 - } - } } - COMPREHENSION [29] { - iter_var: @c:2 + COMPREHENSION [21] { + iter_var: @it:0:0 iter_range: { - IDENT [30] { - name: @index0 + LIST [22] { + elements: { + CONSTANT [23] { value: 1 } + } } } - accu_var: @x:2 + accu_var: @ac:0:0 accu_init: { - CONSTANT [31] { value: false } + CONSTANT [24] { value: false } } loop_condition: { - CALL [32] { + CALL [25] { function: @not_strictly_false args: { - CALL [33] { + CALL [26] { function: !_ args: { - IDENT [34] { - name: @x:2 + IDENT [27] { + name: @ac:0:0 } } } @@ -1922,52 +1651,38 @@ CALL [1] { } } loop_step: { - CALL [35] { - function: _||_ - args: { - IDENT [36] { - name: @x:2 - } - CALL [37] { - function: _>_ - args: { - IDENT [38] { - name: @c:2 - } - CONSTANT [39] { value: 1 } - } - } - } + IDENT [28] { + name: @index1 } } result: { - IDENT [40] { - name: @x:2 + IDENT [29] { + name: @ac:0:0 } } } - COMPREHENSION [41] { - iter_var: @c:3 + COMPREHENSION [30] { + iter_var: @it:0:0 iter_range: { - LIST [42] { + LIST [31] { elements: { - CONSTANT [43] { value: 2 } + CONSTANT [32] { value: 2 } } } } - accu_var: @x:3 + accu_var: @ac:0:0 accu_init: { - CONSTANT [44] { value: false } + CONSTANT [33] { value: false } } loop_condition: { - CALL [45] { + CALL [34] { function: @not_strictly_false args: { - CALL [46] { + CALL [35] { function: !_ args: { - IDENT [47] { - name: @x:3 + IDENT [36] { + name: @ac:0:0 } } } @@ -1975,54 +1690,40 @@ CALL [1] { } } loop_step: { - CALL [48] { - function: _||_ - args: { - IDENT [49] { - name: @x:3 - } - CALL [50] { - function: _>_ - args: { - IDENT [51] { - name: @c:3 - } - CONSTANT [52] { value: 1 } - } - } - } + IDENT [37] { + name: @index1 } } result: { - IDENT [53] { - name: @x:3 + IDENT [38] { + name: @ac:0:0 } } } } } - CALL [54] { + CALL [39] { function: _&&_ args: { - CALL [55] { + CALL [40] { function: _&&_ args: { - IDENT [56] { - name: @index1 + IDENT [41] { + name: @index0 } - IDENT [57] { - name: @index2 + IDENT [42] { + name: @index0 } } } - CALL [58] { + CALL [43] { function: _&&_ args: { - IDENT [59] { - name: @index3 + IDENT [44] { + name: @index2 } - IDENT [60] { - name: @index4 + IDENT [45] { + name: @index3 } } } @@ -2056,7 +1757,7 @@ CALL [1] { function: _+_ args: { IDENT [12] { - name: @x:0 + name: @ac:1:0 } LIST [13] { elements: { @@ -2064,7 +1765,7 @@ CALL [1] { function: _+_ args: { IDENT [15] { - name: @c:0 + name: @it:1:0 } CONSTANT [16] { value: 1 } } @@ -2076,13 +1777,13 @@ CALL [1] { LIST [17] { elements: { COMPREHENSION [18] { - iter_var: @c:0 + iter_var: @it:1:0 iter_range: { IDENT [19] { name: @index0 } } - accu_var: @x:0 + accu_var: @ac:1:0 accu_init: { LIST [20] { elements: { @@ -2099,7 +1800,7 @@ CALL [1] { } result: { IDENT [23] { - name: @x:0 + name: @ac:1:0 } } } @@ -2111,13 +1812,13 @@ CALL [1] { function: _==_ args: { COMPREHENSION [25] { - iter_var: @c:1 + iter_var: @it:0:0 iter_range: { IDENT [26] { name: @index0 } } - accu_var: @x:1 + accu_var: @ac:0:0 accu_init: { LIST [27] { elements: { @@ -2132,7 +1833,7 @@ CALL [1] { function: _+_ args: { IDENT [30] { - name: @x:1 + name: @ac:0:0 } IDENT [31] { name: @index3 @@ -2142,7 +1843,7 @@ CALL [1] { } result: { IDENT [32] { - name: @x:1 + name: @ac:0:0 } } } @@ -2178,10 +1879,10 @@ CALL [1] { function: _==_ args: { IDENT [5] { - name: @c:0 + name: @it:1:0 } IDENT [6] { - name: @c:1 + name: @it:0:0 } } } @@ -2189,26 +1890,26 @@ CALL [1] { function: _+_ args: { IDENT [8] { - name: @x:0 + name: @ac:1:0 } LIST [9] { elements: { IDENT [10] { - name: @c:0 + name: @it:1:0 } } } } } IDENT [11] { - name: @x:0 + name: @ac:1:0 } } } LIST [12] { elements: { COMPREHENSION [13] { - iter_var: @c:0 + iter_var: @it:1:0 iter_range: { LIST [14] { elements: { @@ -2218,7 +1919,7 @@ CALL [1] { } } } - accu_var: @x:0 + accu_var: @ac:1:0 accu_init: { LIST [18] { elements: { @@ -2235,7 +1936,7 @@ CALL [1] { } result: { IDENT [21] { - name: @x:0 + name: @ac:1:0 } } } @@ -2247,7 +1948,7 @@ CALL [1] { function: _==_ args: { COMPREHENSION [23] { - iter_var: @c:1 + iter_var: @it:0:0 iter_range: { LIST [24] { elements: { @@ -2256,7 +1957,7 @@ CALL [1] { } } } - accu_var: @x:1 + accu_var: @ac:0:0 accu_init: { LIST [27] { elements: { @@ -2271,7 +1972,7 @@ CALL [1] { function: _+_ args: { IDENT [30] { - name: @x:1 + name: @ac:0:0 } IDENT [31] { name: @index1 @@ -2281,7 +1982,7 @@ CALL [1] { } result: { IDENT [32] { - name: @x:1 + name: @ac:0:0 } } } @@ -2311,198 +2012,116 @@ CALL [1] { args: { LIST [2] { elements: { - LIST [3] { - elements: { - CONSTANT [4] { value: 1 } - CONSTANT [5] { value: 2 } - CONSTANT [6] { value: 3 } - } - } - CALL [7] { + CALL [3] { function: _+_ args: { - IDENT [8] { - name: @x:0 + IDENT [4] { + name: @ac:1:0 } - LIST [9] { + LIST [5] { elements: { - CALL [10] { + CALL [6] { function: _+_ args: { - IDENT [11] { - name: @c:0 + IDENT [7] { + name: @it:1:0 } - CONSTANT [12] { value: 1 } + CONSTANT [8] { value: 1 } } } } } } } - LIST [13] { + LIST [9] { elements: { - COMPREHENSION [14] { - iter_var: @c:0 + COMPREHENSION [10] { + iter_var: @it:1:0 iter_range: { - IDENT [15] { - name: @index0 - } - } - accu_var: @x:0 - accu_init: { - LIST [16] { + LIST [11] { elements: { + CONSTANT [12] { value: 1 } + CONSTANT [13] { value: 2 } + CONSTANT [14] { value: 3 } } } } - loop_condition: { - CONSTANT [17] { value: true } - } - loop_step: { - IDENT [18] { - name: @index1 - } - } - result: { - IDENT [19] { - name: @x:0 - } - } - } - } - } - CALL [20] { - function: _+_ - args: { - IDENT [21] { - name: @x:2 - } - LIST [22] { - elements: { - CALL [23] { - function: _+_ - args: { - IDENT [24] { - name: @c:2 - } - CONSTANT [25] { value: 1 } - } - } - } - } - } - } - LIST [26] { - elements: { - COMPREHENSION [27] { - iter_var: @c:2 - iter_range: { - IDENT [28] { - name: @index0 - } - } - accu_var: @x:2 + accu_var: @ac:1:0 accu_init: { - LIST [29] { + LIST [15] { elements: { } } } loop_condition: { - CONSTANT [30] { value: true } + CONSTANT [16] { value: true } } loop_step: { - IDENT [31] { - name: @index3 + IDENT [17] { + name: @index0 } } result: { - IDENT [32] { - name: @x:2 + IDENT [18] { + name: @ac:1:0 } } } } } - } - } - CALL [33] { - function: _==_ - args: { - COMPREHENSION [34] { - iter_var: @c:1 + COMPREHENSION [19] { + iter_var: @it:0:0 iter_range: { - IDENT [35] { - name: @index0 - } - } - accu_var: @x:1 - accu_init: { - LIST [36] { + LIST [20] { elements: { + CONSTANT [21] { value: 1 } + CONSTANT [22] { value: 2 } + CONSTANT [23] { value: 3 } } } } - loop_condition: { - CONSTANT [37] { value: true } - } - loop_step: { - CALL [38] { - function: _+_ - args: { - IDENT [39] { - name: @x:1 - } - IDENT [40] { - name: @index2 - } - } - } - } - result: { - IDENT [41] { - name: @x:1 - } - } - } - COMPREHENSION [42] { - iter_var: @c:3 - iter_range: { - IDENT [43] { - name: @index0 - } - } - accu_var: @x:3 + accu_var: @ac:0:0 accu_init: { - LIST [44] { + LIST [24] { elements: { } } } loop_condition: { - CONSTANT [45] { value: true } + CONSTANT [25] { value: true } } loop_step: { - CALL [46] { + CALL [26] { function: _+_ args: { - IDENT [47] { - name: @x:3 + IDENT [27] { + name: @ac:0:0 } - IDENT [48] { - name: @index4 + IDENT [28] { + name: @index1 } } } } result: { - IDENT [49] { - name: @x:3 + IDENT [29] { + name: @ac:0:0 } } } } } + CALL [30] { + function: _==_ + args: { + IDENT [31] { + name: @index2 + } + IDENT [32] { + name: @index2 + } + } + } } } Test case: INCLUSION_LIST @@ -2676,7 +2295,7 @@ CALL [1] { function: _+_ args: { IDENT [14] { - name: @x:0 + name: @ac:1:0 } LIST [15] { elements: { @@ -2693,13 +2312,13 @@ CALL [1] { LIST [19] { elements: { COMPREHENSION [20] { - iter_var: @c:0 + iter_var: @it:1:0 iter_range: { IDENT [21] { name: @index1 } } - accu_var: @x:0 + accu_var: @ac:1:0 accu_init: { LIST [22] { elements: { @@ -2716,7 +2335,7 @@ CALL [1] { } result: { IDENT [25] { - name: @x:0 + name: @ac:1:0 } } } @@ -2728,13 +2347,13 @@ CALL [1] { function: _==_ args: { COMPREHENSION [27] { - iter_var: @c:1 + iter_var: @it:0:0 iter_range: { IDENT [28] { name: @index1 } } - accu_var: @x:1 + accu_var: @ac:0:0 accu_init: { LIST [29] { elements: { @@ -2749,7 +2368,7 @@ CALL [1] { function: _+_ args: { IDENT [32] { - name: @x:1 + name: @ac:0:0 } IDENT [33] { name: @index3 @@ -2759,7 +2378,7 @@ CALL [1] { } result: { IDENT [34] { - name: @x:1 + name: @ac:0:0 } } } @@ -2826,7 +2445,7 @@ CALL [1] { function: _||_ args: { IDENT [16] { - name: @x:0 + name: @ac:0:0 } CALL [17] { function: _>_ @@ -2835,7 +2454,7 @@ CALL [1] { function: _-_ args: { IDENT [19] { - name: @c:0 + name: @it:0:0 } CONSTANT [20] { value: 1 } } @@ -2846,13 +2465,13 @@ CALL [1] { } } COMPREHENSION [22] { - iter_var: @c:0 + iter_var: @it:0:0 iter_range: { IDENT [23] { name: @index1 } } - accu_var: @x:0 + accu_var: @ac:0:0 accu_init: { CONSTANT [24] { value: false } } @@ -2864,7 +2483,7 @@ CALL [1] { function: !_ args: { IDENT [27] { - name: @x:0 + name: @ac:0:0 } } } @@ -2878,7 +2497,7 @@ CALL [1] { } result: { IDENT [29] { - name: @x:0 + name: @ac:0:0 } } } @@ -2909,10 +2528,10 @@ CALL [1] { function: _+_ args: { IDENT [4] { - name: @c:0 + name: @it:1:0 } IDENT [5] { - name: @c:0 + name: @it:1:0 } } } @@ -2920,10 +2539,10 @@ CALL [1] { function: _+_ args: { IDENT [7] { - name: @c:1 + name: @it:0:0 } IDENT [8] { - name: @c:1 + name: @it:0:0 } } } @@ -2931,7 +2550,7 @@ CALL [1] { function: _+_ args: { IDENT [10] { - name: @x:0 + name: @ac:1:0 } LIST [11] { elements: { @@ -2953,7 +2572,7 @@ CALL [1] { function: _+_ args: { IDENT [16] { - name: @x:1 + name: @ac:0:0 } LIST [17] { elements: { @@ -2974,10 +2593,10 @@ CALL [1] { } } COMPREHENSION [21] { - iter_var: @c:1 + iter_var: @it:0:0 iter_range: { COMPREHENSION [22] { - iter_var: @c:0 + iter_var: @it:1:0 iter_range: { LIST [23] { elements: { @@ -2986,7 +2605,7 @@ CALL [1] { } } } - accu_var: @x:0 + accu_var: @ac:1:0 accu_init: { LIST [26] { elements: { @@ -3003,12 +2622,12 @@ CALL [1] { } result: { IDENT [29] { - name: @x:0 + name: @ac:1:0 } } } } - accu_var: @x:1 + accu_var: @ac:0:0 accu_init: { LIST [30] { elements: { @@ -3025,7 +2644,7 @@ CALL [1] { } result: { IDENT [33] { - name: @x:1 + name: @ac:0:0 } } } diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_4.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_4.baseline index 0bfb05eaf..69d2d6af5 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_4.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_4.baseline @@ -1171,36 +1171,28 @@ CALL [1] { elements: { LIST [3] { elements: { - CONSTANT [4] { value: 1 } - } - } - LIST [5] { - elements: { - CONSTANT [6] { value: 2 } - } - } - LIST [7] { - elements: { - COMPREHENSION [8] { - iter_var: @c:0 + COMPREHENSION [4] { + iter_var: @it:0:0 iter_range: { - IDENT [9] { - name: @index0 + LIST [5] { + elements: { + CONSTANT [6] { value: 1 } + } } } - accu_var: @x:0 + accu_var: @ac:0:0 accu_init: { - CONSTANT [10] { value: false } + CONSTANT [7] { value: false } } loop_condition: { - CALL [11] { + CALL [8] { function: @not_strictly_false args: { - CALL [12] { + CALL [9] { function: !_ args: { - IDENT [13] { - name: @x:0 + IDENT [10] { + name: @ac:0:0 } } } @@ -1208,54 +1200,56 @@ CALL [1] { } } loop_step: { - CALL [14] { + CALL [11] { function: _||_ args: { - IDENT [15] { - name: @x:0 + IDENT [12] { + name: @ac:0:0 } - CALL [16] { + CALL [13] { function: _>_ args: { - IDENT [17] { - name: @c:0 + IDENT [14] { + name: @it:0:0 } - CONSTANT [18] { value: 0 } + CONSTANT [15] { value: 0 } } } } } } result: { - IDENT [19] { - name: @x:0 + IDENT [16] { + name: @ac:0:0 } } } } } - LIST [20] { + LIST [17] { elements: { - COMPREHENSION [21] { - iter_var: @c:1 + COMPREHENSION [18] { + iter_var: @it:0:0 iter_range: { - IDENT [22] { - name: @index0 + LIST [19] { + elements: { + CONSTANT [20] { value: 2 } + } } } - accu_var: @x:1 + accu_var: @ac:0:0 accu_init: { - CONSTANT [23] { value: false } + CONSTANT [21] { value: false } } loop_condition: { - CALL [24] { + CALL [22] { function: @not_strictly_false args: { - CALL [25] { + CALL [23] { function: !_ args: { - IDENT [26] { - name: @x:1 + IDENT [24] { + name: @ac:0:0 } } } @@ -1263,198 +1257,81 @@ CALL [1] { } } loop_step: { - CALL [27] { + CALL [25] { function: _||_ args: { - IDENT [28] { - name: @x:1 + IDENT [26] { + name: @ac:0:0 } - CALL [29] { + CALL [27] { function: _>_ args: { - IDENT [30] { - name: @c:1 + IDENT [28] { + name: @it:0:0 } - CONSTANT [31] { value: 0 } + CONSTANT [29] { value: 1 } } } } } } result: { - IDENT [32] { - name: @x:1 + IDENT [30] { + name: @ac:0:0 } } } } } - LIST [33] { - elements: { - COMPREHENSION [34] { - iter_var: @c:2 - iter_range: { - IDENT [35] { - name: @index1 - } - } - accu_var: @x:2 - accu_init: { - CONSTANT [36] { value: false } - } - loop_condition: { - CALL [37] { - function: @not_strictly_false - args: { - CALL [38] { - function: !_ - args: { - IDENT [39] { - name: @x:2 - } - } - } - } - } - } - loop_step: { - CALL [40] { - function: _||_ - args: { - IDENT [41] { - name: @x:2 - } - CALL [42] { - function: _>_ - args: { - IDENT [43] { - name: @c:2 - } - CONSTANT [44] { value: 1 } - } - } - } - } - } - result: { - IDENT [45] { - name: @x:2 - } - } + CALL [31] { + function: size + args: { + IDENT [32] { + name: @index0 } } } - LIST [46] { - elements: { - COMPREHENSION [47] { - iter_var: @c:3 - iter_range: { - IDENT [48] { - name: @index1 - } - } - accu_var: @x:3 - accu_init: { - CONSTANT [49] { value: false } - } - loop_condition: { - CALL [50] { - function: @not_strictly_false - args: { - CALL [51] { - function: !_ - args: { - IDENT [52] { - name: @x:3 - } - } - } - } - } - } - loop_step: { - CALL [53] { - function: _||_ - args: { - IDENT [54] { - name: @x:3 - } - CALL [55] { - function: _>_ - args: { - IDENT [56] { - name: @c:3 - } - CONSTANT [57] { value: 1 } - } - } - } - } - } - result: { - IDENT [58] { - name: @x:3 - } - } + CALL [33] { + function: size + args: { + IDENT [34] { + name: @index1 } } } - CALL [59] { + } + } + CALL [35] { + function: _==_ + args: { + CALL [36] { function: _+_ args: { - CALL [60] { + CALL [37] { function: _+_ args: { - CALL [61] { + CALL [38] { function: _+_ args: { - CALL [62] { - function: size - args: { - IDENT [63] { - name: @index2 - } - } + IDENT [39] { + name: @index2 } - CALL [64] { - function: size - args: { - IDENT [65] { - name: @index3 - } - } + IDENT [40] { + name: @index2 } } } - CALL [66] { - function: size - args: { - IDENT [67] { - name: @index4 - } - } + IDENT [41] { + name: @index3 } } } - CALL [68] { - function: size - args: { - IDENT [69] { - name: @index5 - } - } + IDENT [42] { + name: @index3 } } } - } - } - CALL [70] { - function: _==_ - args: { - IDENT [71] { - name: @index6 - } - CONSTANT [72] { value: 4 } + CONSTANT [43] { value: 4 } } } } @@ -1469,91 +1346,28 @@ CALL [1] { elements: { LIST [3] { elements: { - CONSTANT [4] { value: 1 } - } - } - LIST [5] { - elements: { - CONSTANT [6] { value: "a" } - } - } - LIST [7] { - elements: { - COMPREHENSION [8] { - iter_var: @c:0 + COMPREHENSION [4] { + iter_var: @it:0:0 iter_range: { - IDENT [9] { - name: @index0 - } - } - accu_var: @x:0 - accu_init: { - CONSTANT [10] { value: false } - } - loop_condition: { - CALL [11] { - function: @not_strictly_false - args: { - CALL [12] { - function: !_ - args: { - IDENT [13] { - name: @x:0 - } - } - } - } - } - } - loop_step: { - CALL [14] { - function: _||_ - args: { - IDENT [15] { - name: @x:0 - } - CALL [16] { - function: _>_ - args: { - IDENT [17] { - name: @c:0 - } - CONSTANT [18] { value: 0 } - } - } + LIST [5] { + elements: { + CONSTANT [6] { value: 1 } } } } - result: { - IDENT [19] { - name: @x:0 - } - } - } - } - } - LIST [20] { - elements: { - COMPREHENSION [21] { - iter_var: @c:1 - iter_range: { - IDENT [22] { - name: @index0 - } - } - accu_var: @x:1 + accu_var: @ac:0:0 accu_init: { - CONSTANT [23] { value: false } + CONSTANT [7] { value: false } } loop_condition: { - CALL [24] { + CALL [8] { function: @not_strictly_false args: { - CALL [25] { + CALL [9] { function: !_ args: { - IDENT [26] { - name: @x:1 + IDENT [10] { + name: @ac:0:0 } } } @@ -1561,109 +1375,56 @@ CALL [1] { } } loop_step: { - CALL [27] { + CALL [11] { function: _||_ args: { - IDENT [28] { - name: @x:1 + IDENT [12] { + name: @ac:0:0 } - CALL [29] { + CALL [13] { function: _>_ args: { - IDENT [30] { - name: @c:1 + IDENT [14] { + name: @it:0:0 } - CONSTANT [31] { value: 0 } + CONSTANT [15] { value: 0 } } } } } } result: { - IDENT [32] { - name: @x:1 + IDENT [16] { + name: @ac:0:0 } } } } } - LIST [33] { + LIST [17] { elements: { - COMPREHENSION [34] { - iter_var: @c:2 + COMPREHENSION [18] { + iter_var: @it:0:1 iter_range: { - IDENT [35] { - name: @index1 - } - } - accu_var: @x:2 - accu_init: { - CONSTANT [36] { value: false } - } - loop_condition: { - CALL [37] { - function: @not_strictly_false - args: { - CALL [38] { - function: !_ - args: { - IDENT [39] { - name: @x:2 - } - } - } - } - } - } - loop_step: { - CALL [40] { - function: _||_ - args: { - IDENT [41] { - name: @x:2 - } - CALL [42] { - function: _==_ - args: { - IDENT [43] { - name: @c:2 - } - CONSTANT [44] { value: "a" } - } - } + LIST [19] { + elements: { + CONSTANT [20] { value: "a" } } } } - result: { - IDENT [45] { - name: @x:2 - } - } - } - } - } - LIST [46] { - elements: { - COMPREHENSION [47] { - iter_var: @c:3 - iter_range: { - IDENT [48] { - name: @index1 - } - } - accu_var: @x:3 + accu_var: @ac:0:1 accu_init: { - CONSTANT [49] { value: false } + CONSTANT [21] { value: false } } loop_condition: { - CALL [50] { + CALL [22] { function: @not_strictly_false args: { - CALL [51] { + CALL [23] { function: !_ args: { - IDENT [52] { - name: @x:3 + IDENT [24] { + name: @ac:0:1 } } } @@ -1671,27 +1432,27 @@ CALL [1] { } } loop_step: { - CALL [53] { + CALL [25] { function: _||_ args: { - IDENT [54] { - name: @x:3 + IDENT [26] { + name: @ac:0:1 } - CALL [55] { + CALL [27] { function: _==_ args: { - IDENT [56] { - name: @c:3 + IDENT [28] { + name: @it:0:1 } - CONSTANT [57] { value: "a" } + CONSTANT [29] { value: "a" } } } } } } result: { - IDENT [58] { - name: @x:3 + IDENT [30] { + name: @ac:0:1 } } } @@ -1699,42 +1460,42 @@ CALL [1] { } } } - CALL [59] { + CALL [31] { function: _==_ args: { - CALL [60] { + CALL [32] { function: _+_ args: { - CALL [61] { + CALL [33] { function: _+_ args: { - CALL [62] { + CALL [34] { function: _+_ args: { - IDENT [63] { - name: @index2 + IDENT [35] { + name: @index0 } - IDENT [64] { - name: @index3 + IDENT [36] { + name: @index0 } } } - IDENT [65] { - name: @index4 + IDENT [37] { + name: @index1 } } } - IDENT [66] { - name: @index5 + IDENT [38] { + name: @index1 } } } - LIST [67] { + LIST [39] { elements: { - CONSTANT [68] { value: true } - CONSTANT [69] { value: true } - CONSTANT [70] { value: true } - CONSTANT [71] { value: true } + CONSTANT [40] { value: true } + CONSTANT [41] { value: true } + CONSTANT [42] { value: true } + CONSTANT [43] { value: true } } } } @@ -1749,141 +1510,101 @@ CALL [1] { args: { LIST [2] { elements: { - LIST [3] { - elements: { - CONSTANT [4] { value: 1 } - } - } - CALL [5] { - function: _&&_ - args: { - COMPREHENSION [6] { - iter_var: @c:0 - iter_range: { - IDENT [7] { - name: @index0 - } - } - accu_var: @x:0 - accu_init: { - CONSTANT [8] { value: false } + COMPREHENSION [3] { + iter_var: @it:0:0 + iter_range: { + LIST [4] { + elements: { + CONSTANT [5] { value: 1 } } - loop_condition: { - CALL [9] { - function: @not_strictly_false + } + } + accu_var: @ac:0:0 + accu_init: { + CONSTANT [6] { value: false } + } + loop_condition: { + CALL [7] { + function: @not_strictly_false + args: { + CALL [8] { + function: !_ args: { - CALL [10] { - function: !_ - args: { - IDENT [11] { - name: @x:0 - } - } + IDENT [9] { + name: @ac:0:0 } } } } - loop_step: { + } + } + loop_step: { + CALL [10] { + function: _||_ + args: { + IDENT [11] { + name: @ac:0:0 + } CALL [12] { - function: _||_ + function: _>_ args: { IDENT [13] { - name: @x:0 - } - CALL [14] { - function: _>_ - args: { - IDENT [15] { - name: @c:0 - } - CONSTANT [16] { value: 0 } - } + name: @it:0:0 } + CONSTANT [14] { value: 0 } } } } - result: { - IDENT [17] { - name: @x:0 - } - } } - COMPREHENSION [18] { - iter_var: @c:1 - iter_range: { + } + result: { + IDENT [15] { + name: @ac:0:0 + } + } + } + CALL [16] { + function: _||_ + args: { + IDENT [17] { + name: @ac:0:0 + } + CALL [18] { + function: _>_ + args: { IDENT [19] { - name: @index0 - } - } - accu_var: @x:1 - accu_init: { - CONSTANT [20] { value: false } - } - loop_condition: { - CALL [21] { - function: @not_strictly_false - args: { - CALL [22] { - function: !_ - args: { - IDENT [23] { - name: @x:1 - } - } - } - } - } - } - loop_step: { - CALL [24] { - function: _||_ - args: { - IDENT [25] { - name: @x:1 - } - CALL [26] { - function: _>_ - args: { - IDENT [27] { - name: @c:1 - } - CONSTANT [28] { value: 0 } - } - } - } - } - } - result: { - IDENT [29] { - name: @x:1 + name: @it:0:0 } + CONSTANT [20] { value: 1 } } } } } - CALL [30] { + CALL [21] { function: _&&_ args: { - COMPREHENSION [31] { - iter_var: @c:2 + COMPREHENSION [22] { + iter_var: @it:0:0 iter_range: { - IDENT [32] { - name: @index0 + LIST [23] { + elements: { + CONSTANT [24] { value: 1 } + } } } - accu_var: @x:2 + accu_var: @ac:0:0 accu_init: { - CONSTANT [33] { value: false } + CONSTANT [25] { value: false } } loop_condition: { - CALL [34] { + CALL [26] { function: @not_strictly_false args: { - CALL [35] { + CALL [27] { function: !_ args: { - IDENT [36] { - name: @x:2 + IDENT [28] { + name: @ac:0:0 } } } @@ -1891,52 +1612,38 @@ CALL [1] { } } loop_step: { - CALL [37] { - function: _||_ - args: { - IDENT [38] { - name: @x:2 - } - CALL [39] { - function: _>_ - args: { - IDENT [40] { - name: @c:2 - } - CONSTANT [41] { value: 1 } - } - } - } + IDENT [29] { + name: @index1 } } result: { - IDENT [42] { - name: @x:2 + IDENT [30] { + name: @ac:0:0 } } } - COMPREHENSION [43] { - iter_var: @c:3 + COMPREHENSION [31] { + iter_var: @it:0:0 iter_range: { - LIST [44] { + LIST [32] { elements: { - CONSTANT [45] { value: 2 } + CONSTANT [33] { value: 2 } } } } - accu_var: @x:3 + accu_var: @ac:0:0 accu_init: { - CONSTANT [46] { value: false } + CONSTANT [34] { value: false } } loop_condition: { - CALL [47] { + CALL [35] { function: @not_strictly_false args: { - CALL [48] { + CALL [36] { function: !_ args: { - IDENT [49] { - name: @x:3 + IDENT [37] { + name: @ac:0:0 } } } @@ -1944,27 +1651,13 @@ CALL [1] { } } loop_step: { - CALL [50] { - function: _||_ - args: { - IDENT [51] { - name: @x:3 - } - CALL [52] { - function: _>_ - args: { - IDENT [53] { - name: @c:3 - } - CONSTANT [54] { value: 1 } - } - } - } + IDENT [38] { + name: @index1 } } result: { - IDENT [55] { - name: @x:3 + IDENT [39] { + name: @ac:0:0 } } } @@ -1972,13 +1665,21 @@ CALL [1] { } } } - CALL [56] { + CALL [40] { function: _&&_ args: { - IDENT [57] { - name: @index1 + CALL [41] { + function: _&&_ + args: { + IDENT [42] { + name: @index0 + } + IDENT [43] { + name: @index0 + } + } } - IDENT [58] { + IDENT [44] { name: @index2 } } @@ -2008,13 +1709,13 @@ CALL [1] { } } COMPREHENSION [11] { - iter_var: @c:0 + iter_var: @it:1:0 iter_range: { IDENT [12] { name: @index0 } } - accu_var: @x:0 + accu_var: @ac:1:0 accu_init: { LIST [13] { elements: { @@ -2029,7 +1730,7 @@ CALL [1] { function: _+_ args: { IDENT [16] { - name: @x:0 + name: @ac:1:0 } LIST [17] { elements: { @@ -2037,7 +1738,7 @@ CALL [1] { function: _+_ args: { IDENT [19] { - name: @c:0 + name: @it:1:0 } CONSTANT [20] { value: 1 } } @@ -2049,7 +1750,7 @@ CALL [1] { } result: { IDENT [21] { - name: @x:0 + name: @ac:1:0 } } } @@ -2059,13 +1760,13 @@ CALL [1] { function: _==_ args: { COMPREHENSION [23] { - iter_var: @c:1 + iter_var: @it:0:0 iter_range: { IDENT [24] { name: @index0 } } - accu_var: @x:1 + accu_var: @ac:0:0 accu_init: { LIST [25] { elements: { @@ -2080,7 +1781,7 @@ CALL [1] { function: _+_ args: { IDENT [28] { - name: @x:1 + name: @ac:0:0 } LIST [29] { elements: { @@ -2094,7 +1795,7 @@ CALL [1] { } result: { IDENT [31] { - name: @x:1 + name: @ac:0:0 } } } @@ -2124,7 +1825,7 @@ CALL [1] { LIST [2] { elements: { COMPREHENSION [3] { - iter_var: @c:0 + iter_var: @it:1:0 iter_range: { LIST [4] { elements: { @@ -2134,7 +1835,7 @@ CALL [1] { } } } - accu_var: @x:0 + accu_var: @ac:1:0 accu_init: { LIST [8] { elements: { @@ -2152,10 +1853,10 @@ CALL [1] { function: _==_ args: { IDENT [12] { - name: @c:0 + name: @it:1:0 } IDENT [13] { - name: @c:1 + name: @it:0:0 } } } @@ -2163,26 +1864,26 @@ CALL [1] { function: _+_ args: { IDENT [15] { - name: @x:0 + name: @ac:1:0 } LIST [16] { elements: { IDENT [17] { - name: @c:0 + name: @it:1:0 } } } } } IDENT [18] { - name: @x:0 + name: @ac:1:0 } } } } result: { IDENT [19] { - name: @x:0 + name: @ac:1:0 } } } @@ -2192,7 +1893,7 @@ CALL [1] { function: _==_ args: { COMPREHENSION [21] { - iter_var: @c:1 + iter_var: @it:0:0 iter_range: { LIST [22] { elements: { @@ -2201,7 +1902,7 @@ CALL [1] { } } } - accu_var: @x:1 + accu_var: @ac:0:0 accu_init: { LIST [25] { elements: { @@ -2216,7 +1917,7 @@ CALL [1] { function: _+_ args: { IDENT [28] { - name: @x:1 + name: @ac:0:0 } LIST [29] { elements: { @@ -2230,7 +1931,7 @@ CALL [1] { } result: { IDENT [31] { - name: @x:1 + name: @ac:0:0 } } } @@ -2260,46 +1961,43 @@ CALL [1] { args: { LIST [2] { elements: { - LIST [3] { - elements: { - CONSTANT [4] { value: 1 } - CONSTANT [5] { value: 2 } - CONSTANT [6] { value: 3 } - } - } - COMPREHENSION [7] { - iter_var: @c:0 + COMPREHENSION [3] { + iter_var: @it:1:0 iter_range: { - IDENT [8] { - name: @index0 + LIST [4] { + elements: { + CONSTANT [5] { value: 1 } + CONSTANT [6] { value: 2 } + CONSTANT [7] { value: 3 } + } } } - accu_var: @x:0 + accu_var: @ac:1:0 accu_init: { - LIST [9] { + LIST [8] { elements: { } } } loop_condition: { - CONSTANT [10] { value: true } + CONSTANT [9] { value: true } } loop_step: { - CALL [11] { + CALL [10] { function: _+_ args: { - IDENT [12] { - name: @x:0 + IDENT [11] { + name: @ac:1:0 } - LIST [13] { + LIST [12] { elements: { - CALL [14] { + CALL [13] { function: _+_ args: { - IDENT [15] { - name: @c:0 + IDENT [14] { + name: @it:1:0 } - CONSTANT [16] { value: 1 } + CONSTANT [15] { value: 1 } } } } @@ -2308,45 +2006,43 @@ CALL [1] { } } result: { - IDENT [17] { - name: @x:0 + IDENT [16] { + name: @ac:1:0 } } } - COMPREHENSION [18] { - iter_var: @c:2 + COMPREHENSION [17] { + iter_var: @it:0:0 iter_range: { - IDENT [19] { - name: @index0 + LIST [18] { + elements: { + CONSTANT [19] { value: 1 } + CONSTANT [20] { value: 2 } + CONSTANT [21] { value: 3 } + } } } - accu_var: @x:2 + accu_var: @ac:0:0 accu_init: { - LIST [20] { + LIST [22] { elements: { } } } loop_condition: { - CONSTANT [21] { value: true } + CONSTANT [23] { value: true } } loop_step: { - CALL [22] { + CALL [24] { function: _+_ args: { - IDENT [23] { - name: @x:2 + IDENT [25] { + name: @ac:0:0 } - LIST [24] { + LIST [26] { elements: { - CALL [25] { - function: _+_ - args: { - IDENT [26] { - name: @c:2 - } - CONSTANT [27] { value: 1 } - } + IDENT [27] { + name: @index0 } } } @@ -2355,7 +2051,7 @@ CALL [1] { } result: { IDENT [28] { - name: @x:2 + name: @ac:0:0 } } } @@ -2364,85 +2060,11 @@ CALL [1] { CALL [29] { function: _==_ args: { - COMPREHENSION [30] { - iter_var: @c:1 - iter_range: { - IDENT [31] { - name: @index0 - } - } - accu_var: @x:1 - accu_init: { - LIST [32] { - elements: { - } - } - } - loop_condition: { - CONSTANT [33] { value: true } - } - loop_step: { - CALL [34] { - function: _+_ - args: { - IDENT [35] { - name: @x:1 - } - LIST [36] { - elements: { - IDENT [37] { - name: @index1 - } - } - } - } - } - } - result: { - IDENT [38] { - name: @x:1 - } - } + IDENT [30] { + name: @index1 } - COMPREHENSION [39] { - iter_var: @c:3 - iter_range: { - IDENT [40] { - name: @index0 - } - } - accu_var: @x:3 - accu_init: { - LIST [41] { - elements: { - } - } - } - loop_condition: { - CONSTANT [42] { value: true } - } - loop_step: { - CALL [43] { - function: _+_ - args: { - IDENT [44] { - name: @x:3 - } - LIST [45] { - elements: { - IDENT [46] { - name: @index2 - } - } - } - } - } - } - result: { - IDENT [47] { - name: @x:3 - } - } + IDENT [31] { + name: @index1 } } } @@ -2613,13 +2235,13 @@ CALL [1] { } } COMPREHENSION [13] { - iter_var: @c:0 + iter_var: @it:1:0 iter_range: { IDENT [14] { name: @index1 } } - accu_var: @x:0 + accu_var: @ac:1:0 accu_init: { LIST [15] { elements: { @@ -2634,7 +2256,7 @@ CALL [1] { function: _+_ args: { IDENT [18] { - name: @x:0 + name: @ac:1:0 } LIST [19] { elements: { @@ -2651,7 +2273,7 @@ CALL [1] { } result: { IDENT [23] { - name: @x:0 + name: @ac:1:0 } } } @@ -2661,13 +2283,13 @@ CALL [1] { function: _==_ args: { COMPREHENSION [25] { - iter_var: @c:1 + iter_var: @it:0:0 iter_range: { IDENT [26] { name: @index1 } } - accu_var: @x:1 + accu_var: @ac:0:0 accu_init: { LIST [27] { elements: { @@ -2682,7 +2304,7 @@ CALL [1] { function: _+_ args: { IDENT [30] { - name: @x:1 + name: @ac:0:0 } LIST [31] { elements: { @@ -2696,7 +2318,7 @@ CALL [1] { } result: { IDENT [33] { - name: @x:1 + name: @ac:0:0 } } } @@ -2738,7 +2360,7 @@ CALL [1] { } } COMPREHENSION [8] { - iter_var: @c:0 + iter_var: @it:0:0 iter_range: { LIST [9] { elements: { @@ -2763,7 +2385,7 @@ CALL [1] { } } } - accu_var: @x:0 + accu_var: @ac:0:0 accu_init: { CONSTANT [16] { value: false } } @@ -2775,7 +2397,7 @@ CALL [1] { function: !_ args: { IDENT [19] { - name: @x:0 + name: @ac:0:0 } } } @@ -2787,7 +2409,7 @@ CALL [1] { function: _||_ args: { IDENT [21] { - name: @x:0 + name: @ac:0:0 } CALL [22] { function: _>_ @@ -2796,7 +2418,7 @@ CALL [1] { function: _-_ args: { IDENT [24] { - name: @c:0 + name: @it:0:0 } CONSTANT [25] { value: 1 } } @@ -2809,7 +2431,7 @@ CALL [1] { } result: { IDENT [27] { - name: @x:0 + name: @ac:0:0 } } } @@ -2840,10 +2462,10 @@ CALL [1] { function: _+_ args: { IDENT [4] { - name: @c:0 + name: @it:1:0 } IDENT [5] { - name: @c:0 + name: @it:1:0 } } } @@ -2851,15 +2473,15 @@ CALL [1] { function: _+_ args: { IDENT [7] { - name: @c:1 + name: @it:0:0 } IDENT [8] { - name: @c:1 + name: @it:0:0 } } } COMPREHENSION [9] { - iter_var: @c:0 + iter_var: @it:1:0 iter_range: { LIST [10] { elements: { @@ -2868,7 +2490,7 @@ CALL [1] { } } } - accu_var: @x:0 + accu_var: @ac:1:0 accu_init: { LIST [13] { elements: { @@ -2883,7 +2505,7 @@ CALL [1] { function: _+_ args: { IDENT [16] { - name: @x:0 + name: @ac:1:0 } LIST [17] { elements: { @@ -2904,20 +2526,20 @@ CALL [1] { } result: { IDENT [21] { - name: @x:0 + name: @ac:1:0 } } } } } COMPREHENSION [22] { - iter_var: @c:1 + iter_var: @it:0:0 iter_range: { IDENT [23] { name: @index2 } } - accu_var: @x:1 + accu_var: @ac:0:0 accu_init: { LIST [24] { elements: { @@ -2932,7 +2554,7 @@ CALL [1] { function: _+_ args: { IDENT [27] { - name: @x:1 + name: @ac:0:0 } LIST [28] { elements: { @@ -2953,7 +2575,7 @@ CALL [1] { } result: { IDENT [32] { - name: @x:1 + name: @ac:0:0 } } } diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_5.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_5.baseline index ed7daab1e..e27f91a0d 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_5.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_5.baseline @@ -1151,101 +1151,33 @@ CALL [1] { args: { LIST [2] { elements: { - LIST [3] { - elements: { - CONSTANT [4] { value: 1 } - } - } - LIST [5] { - elements: { - CONSTANT [6] { value: 2 } - } - } - CALL [7] { + CALL [3] { function: size args: { - LIST [8] { + LIST [4] { elements: { - COMPREHENSION [9] { - iter_var: @c:0 + COMPREHENSION [5] { + iter_var: @it:0:0 iter_range: { - IDENT [10] { - name: @index0 - } - } - accu_var: @x:0 - accu_init: { - CONSTANT [11] { value: false } - } - loop_condition: { - CALL [12] { - function: @not_strictly_false - args: { - CALL [13] { - function: !_ - args: { - IDENT [14] { - name: @x:0 - } - } - } - } - } - } - loop_step: { - CALL [15] { - function: _||_ - args: { - IDENT [16] { - name: @x:0 - } - CALL [17] { - function: _>_ - args: { - IDENT [18] { - name: @c:0 - } - CONSTANT [19] { value: 0 } - } - } + LIST [6] { + elements: { + CONSTANT [7] { value: 1 } } } } - result: { - IDENT [20] { - name: @x:0 - } - } - } - } - } - } - } - CALL [21] { - function: size - args: { - LIST [22] { - elements: { - COMPREHENSION [23] { - iter_var: @c:1 - iter_range: { - IDENT [24] { - name: @index0 - } - } - accu_var: @x:1 + accu_var: @ac:0:0 accu_init: { - CONSTANT [25] { value: false } + CONSTANT [8] { value: false } } loop_condition: { - CALL [26] { + CALL [9] { function: @not_strictly_false args: { - CALL [27] { + CALL [10] { function: !_ args: { - IDENT [28] { - name: @x:1 + IDENT [11] { + name: @ac:0:0 } } } @@ -1253,27 +1185,27 @@ CALL [1] { } } loop_step: { - CALL [29] { + CALL [12] { function: _||_ args: { - IDENT [30] { - name: @x:1 + IDENT [13] { + name: @ac:0:0 } - CALL [31] { + CALL [14] { function: _>_ args: { - IDENT [32] { - name: @c:1 + IDENT [15] { + name: @it:0:0 } - CONSTANT [33] { value: 0 } + CONSTANT [16] { value: 0 } } } } } } result: { - IDENT [34] { - name: @x:1 + IDENT [17] { + name: @ac:0:0 } } } @@ -1281,91 +1213,33 @@ CALL [1] { } } } - CALL [35] { + CALL [18] { function: size args: { - LIST [36] { + LIST [19] { elements: { - COMPREHENSION [37] { - iter_var: @c:2 + COMPREHENSION [20] { + iter_var: @it:0:0 iter_range: { - IDENT [38] { - name: @index1 - } - } - accu_var: @x:2 - accu_init: { - CONSTANT [39] { value: false } - } - loop_condition: { - CALL [40] { - function: @not_strictly_false - args: { - CALL [41] { - function: !_ - args: { - IDENT [42] { - name: @x:2 - } - } - } - } - } - } - loop_step: { - CALL [43] { - function: _||_ - args: { - IDENT [44] { - name: @x:2 - } - CALL [45] { - function: _>_ - args: { - IDENT [46] { - name: @c:2 - } - CONSTANT [47] { value: 1 } - } - } + LIST [21] { + elements: { + CONSTANT [22] { value: 2 } } } } - result: { - IDENT [48] { - name: @x:2 - } - } - } - } - } - } - } - CALL [49] { - function: size - args: { - LIST [50] { - elements: { - COMPREHENSION [51] { - iter_var: @c:3 - iter_range: { - IDENT [52] { - name: @index1 - } - } - accu_var: @x:3 + accu_var: @ac:0:0 accu_init: { - CONSTANT [53] { value: false } + CONSTANT [23] { value: false } } loop_condition: { - CALL [54] { + CALL [24] { function: @not_strictly_false args: { - CALL [55] { + CALL [25] { function: !_ args: { - IDENT [56] { - name: @x:3 + IDENT [26] { + name: @ac:0:0 } } } @@ -1373,27 +1247,27 @@ CALL [1] { } } loop_step: { - CALL [57] { + CALL [27] { function: _||_ args: { - IDENT [58] { - name: @x:3 + IDENT [28] { + name: @ac:0:0 } - CALL [59] { + CALL [29] { function: _>_ args: { - IDENT [60] { - name: @c:3 + IDENT [30] { + name: @it:0:0 } - CONSTANT [61] { value: 1 } + CONSTANT [31] { value: 1 } } } } } } result: { - IDENT [62] { - name: @x:3 + IDENT [32] { + name: @ac:0:0 } } } @@ -1403,322 +1277,43 @@ CALL [1] { } } } - CALL [63] { + CALL [33] { function: _==_ args: { - CALL [64] { + CALL [34] { function: _+_ args: { - CALL [65] { + CALL [35] { function: _+_ args: { - CALL [66] { + CALL [36] { function: _+_ args: { - IDENT [67] { - name: @index2 - } - IDENT [68] { - name: @index3 - } - } - } - IDENT [69] { - name: @index4 - } - } - } - IDENT [70] { - name: @index5 - } - } - } - CONSTANT [71] { value: 4 } - } - } - } -} -Test case: MULTIPLE_MACROS_2 -Source: [[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == 'a')] + [['a'].exists(l, l == 'a')] == [true, true, true, true] -=====> -CALL [1] { - function: cel.@block - args: { - LIST [2] { - elements: { - LIST [3] { - elements: { - CONSTANT [4] { value: 1 } - } - } - LIST [5] { - elements: { - CONSTANT [6] { value: "a" } - } - } - CALL [7] { - function: _+_ - args: { - LIST [8] { - elements: { - COMPREHENSION [9] { - iter_var: @c:0 - iter_range: { - IDENT [10] { + IDENT [37] { name: @index0 } - } - accu_var: @x:0 - accu_init: { - CONSTANT [11] { value: false } - } - loop_condition: { - CALL [12] { - function: @not_strictly_false - args: { - CALL [13] { - function: !_ - args: { - IDENT [14] { - name: @x:0 - } - } - } - } - } - } - loop_step: { - CALL [15] { - function: _||_ - args: { - IDENT [16] { - name: @x:0 - } - CALL [17] { - function: _>_ - args: { - IDENT [18] { - name: @c:0 - } - CONSTANT [19] { value: 0 } - } - } - } - } - } - result: { - IDENT [20] { - name: @x:0 - } - } - } - } - } - LIST [21] { - elements: { - COMPREHENSION [22] { - iter_var: @c:1 - iter_range: { - IDENT [23] { + IDENT [38] { name: @index0 } } - accu_var: @x:1 - accu_init: { - CONSTANT [24] { value: false } - } - loop_condition: { - CALL [25] { - function: @not_strictly_false - args: { - CALL [26] { - function: !_ - args: { - IDENT [27] { - name: @x:1 - } - } - } - } - } - } - loop_step: { - CALL [28] { - function: _||_ - args: { - IDENT [29] { - name: @x:1 - } - CALL [30] { - function: _>_ - args: { - IDENT [31] { - name: @c:1 - } - CONSTANT [32] { value: 0 } - } - } - } - } - } - result: { - IDENT [33] { - name: @x:1 - } - } } - } - } - } - } - CALL [34] { - function: _+_ - args: { - IDENT [35] { - name: @index2 - } - LIST [36] { - elements: { - COMPREHENSION [37] { - iter_var: @c:2 - iter_range: { - IDENT [38] { - name: @index1 - } - } - accu_var: @x:2 - accu_init: { - CONSTANT [39] { value: false } - } - loop_condition: { - CALL [40] { - function: @not_strictly_false - args: { - CALL [41] { - function: !_ - args: { - IDENT [42] { - name: @x:2 - } - } - } - } - } - } - loop_step: { - CALL [43] { - function: _||_ - args: { - IDENT [44] { - name: @x:2 - } - CALL [45] { - function: _==_ - args: { - IDENT [46] { - name: @c:2 - } - CONSTANT [47] { value: "a" } - } - } - } - } - } - result: { - IDENT [48] { - name: @x:2 - } - } + IDENT [39] { + name: @index1 } } } - } - } - CALL [49] { - function: _+_ - args: { - IDENT [50] { - name: @index3 - } - LIST [51] { - elements: { - COMPREHENSION [52] { - iter_var: @c:3 - iter_range: { - IDENT [53] { - name: @index1 - } - } - accu_var: @x:3 - accu_init: { - CONSTANT [54] { value: false } - } - loop_condition: { - CALL [55] { - function: @not_strictly_false - args: { - CALL [56] { - function: !_ - args: { - IDENT [57] { - name: @x:3 - } - } - } - } - } - } - loop_step: { - CALL [58] { - function: _||_ - args: { - IDENT [59] { - name: @x:3 - } - CALL [60] { - function: _==_ - args: { - IDENT [61] { - name: @c:3 - } - CONSTANT [62] { value: "a" } - } - } - } - } - } - result: { - IDENT [63] { - name: @x:3 - } - } - } - } + IDENT [40] { + name: @index1 } } } - } - } - CALL [64] { - function: _==_ - args: { - IDENT [65] { - name: @index4 - } - LIST [66] { - elements: { - CONSTANT [67] { value: true } - CONSTANT [68] { value: true } - CONSTANT [69] { value: true } - CONSTANT [70] { value: true } - } - } + CONSTANT [41] { value: 4 } } } } } -Test case: MULTIPLE_MACROS_3 -Source: [1].exists(i, i > 0) && [1].exists(j, j > 0) && [1].exists(k, k > 1) && [2].exists(l, l > 1) +Test case: MULTIPLE_MACROS_2 +Source: [[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == 'a')] + [['a'].exists(l, l == 'a')] == [true, true, true, true] =====> CALL [1] { function: cel.@block @@ -1727,37 +1322,28 @@ CALL [1] { elements: { LIST [3] { elements: { - CONSTANT [4] { value: 1 } - } - } - } - } - CALL [5] { - function: _&&_ - args: { - CALL [6] { - function: _&&_ - args: { - COMPREHENSION [7] { - iter_var: @c:0 + COMPREHENSION [4] { + iter_var: @it:0:0 iter_range: { - IDENT [8] { - name: @index0 + LIST [5] { + elements: { + CONSTANT [6] { value: 1 } + } } } - accu_var: @x:0 + accu_var: @ac:0:0 accu_init: { - CONSTANT [9] { value: false } + CONSTANT [7] { value: false } } loop_condition: { - CALL [10] { + CALL [8] { function: @not_strictly_false args: { - CALL [11] { + CALL [9] { function: !_ args: { - IDENT [12] { - name: @x:0 + IDENT [10] { + name: @ac:0:0 } } } @@ -1765,38 +1351,44 @@ CALL [1] { } } loop_step: { - CALL [13] { + CALL [11] { function: _||_ args: { - IDENT [14] { - name: @x:0 + IDENT [12] { + name: @ac:0:0 } - CALL [15] { + CALL [13] { function: _>_ args: { - IDENT [16] { - name: @c:0 + IDENT [14] { + name: @it:0:0 } - CONSTANT [17] { value: 0 } + CONSTANT [15] { value: 0 } } } } } } result: { - IDENT [18] { - name: @x:0 + IDENT [16] { + name: @ac:0:0 } } } - COMPREHENSION [19] { - iter_var: @c:1 + } + } + LIST [17] { + elements: { + COMPREHENSION [18] { + iter_var: @it:0:1 iter_range: { - IDENT [20] { - name: @index0 + LIST [19] { + elements: { + CONSTANT [20] { value: "a" } + } } } - accu_var: @x:1 + accu_var: @ac:0:1 accu_init: { CONSTANT [21] { value: false } } @@ -1808,7 +1400,7 @@ CALL [1] { function: !_ args: { IDENT [24] { - name: @x:1 + name: @ac:0:1 } } } @@ -1820,15 +1412,15 @@ CALL [1] { function: _||_ args: { IDENT [26] { - name: @x:1 + name: @ac:0:1 } CALL [27] { - function: _>_ + function: _==_ args: { IDENT [28] { - name: @c:1 + name: @it:0:1 } - CONSTANT [29] { value: 0 } + CONSTANT [29] { value: "a" } } } } @@ -1836,35 +1428,175 @@ CALL [1] { } result: { IDENT [30] { - name: @x:1 + name: @ac:0:1 + } + } + } + } + } + } + } + CALL [31] { + function: _==_ + args: { + CALL [32] { + function: _+_ + args: { + CALL [33] { + function: _+_ + args: { + CALL [34] { + function: _+_ + args: { + IDENT [35] { + name: @index0 + } + IDENT [36] { + name: @index0 + } + } + } + IDENT [37] { + name: @index1 + } + } + } + IDENT [38] { + name: @index1 + } + } + } + LIST [39] { + elements: { + CONSTANT [40] { value: true } + CONSTANT [41] { value: true } + CONSTANT [42] { value: true } + CONSTANT [43] { value: true } + } + } + } + } + } +} +Test case: MULTIPLE_MACROS_3 +Source: [1].exists(i, i > 0) && [1].exists(j, j > 0) && [1].exists(k, k > 1) && [2].exists(l, l > 1) +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + COMPREHENSION [3] { + iter_var: @it:0:0 + iter_range: { + LIST [4] { + elements: { + CONSTANT [5] { value: 1 } + } + } + } + accu_var: @ac:0:0 + accu_init: { + CONSTANT [6] { value: false } + } + loop_condition: { + CALL [7] { + function: @not_strictly_false + args: { + CALL [8] { + function: !_ + args: { + IDENT [9] { + name: @ac:0:0 + } + } + } + } + } + } + loop_step: { + CALL [10] { + function: _||_ + args: { + IDENT [11] { + name: @ac:0:0 + } + CALL [12] { + function: _>_ + args: { + IDENT [13] { + name: @it:0:0 + } + CONSTANT [14] { value: 0 } + } + } + } + } + } + result: { + IDENT [15] { + name: @ac:0:0 + } + } + } + CALL [16] { + function: _||_ + args: { + IDENT [17] { + name: @ac:0:0 + } + CALL [18] { + function: _>_ + args: { + IDENT [19] { + name: @it:0:0 } + CONSTANT [20] { value: 1 } } } } } - CALL [31] { + } + } + CALL [21] { + function: _&&_ + args: { + CALL [22] { + function: _&&_ + args: { + IDENT [23] { + name: @index0 + } + IDENT [24] { + name: @index0 + } + } + } + CALL [25] { function: _&&_ args: { - COMPREHENSION [32] { - iter_var: @c:2 + COMPREHENSION [26] { + iter_var: @it:0:0 iter_range: { - IDENT [33] { - name: @index0 + LIST [27] { + elements: { + CONSTANT [28] { value: 1 } + } } } - accu_var: @x:2 + accu_var: @ac:0:0 accu_init: { - CONSTANT [34] { value: false } + CONSTANT [29] { value: false } } loop_condition: { - CALL [35] { + CALL [30] { function: @not_strictly_false args: { - CALL [36] { + CALL [31] { function: !_ args: { - IDENT [37] { - name: @x:2 + IDENT [32] { + name: @ac:0:0 } } } @@ -1872,52 +1604,38 @@ CALL [1] { } } loop_step: { - CALL [38] { - function: _||_ - args: { - IDENT [39] { - name: @x:2 - } - CALL [40] { - function: _>_ - args: { - IDENT [41] { - name: @c:2 - } - CONSTANT [42] { value: 1 } - } - } - } + IDENT [33] { + name: @index1 } } result: { - IDENT [43] { - name: @x:2 + IDENT [34] { + name: @ac:0:0 } } } - COMPREHENSION [44] { - iter_var: @c:3 + COMPREHENSION [35] { + iter_var: @it:0:0 iter_range: { - LIST [45] { + LIST [36] { elements: { - CONSTANT [46] { value: 2 } + CONSTANT [37] { value: 2 } } } } - accu_var: @x:3 + accu_var: @ac:0:0 accu_init: { - CONSTANT [47] { value: false } + CONSTANT [38] { value: false } } loop_condition: { - CALL [48] { + CALL [39] { function: @not_strictly_false args: { - CALL [49] { + CALL [40] { function: !_ args: { - IDENT [50] { - name: @x:3 + IDENT [41] { + name: @ac:0:0 } } } @@ -1925,27 +1643,13 @@ CALL [1] { } } loop_step: { - CALL [51] { - function: _||_ - args: { - IDENT [52] { - name: @x:3 - } - CALL [53] { - function: _>_ - args: { - IDENT [54] { - name: @c:3 - } - CONSTANT [55] { value: 1 } - } - } - } + IDENT [42] { + name: @index1 } } result: { - IDENT [56] { - name: @x:3 + IDENT [43] { + name: @ac:0:0 } } } @@ -1980,13 +1684,13 @@ CALL [1] { LIST [11] { elements: { COMPREHENSION [12] { - iter_var: @c:0 + iter_var: @it:1:0 iter_range: { IDENT [13] { name: @index0 } } - accu_var: @x:0 + accu_var: @ac:1:0 accu_init: { LIST [14] { elements: { @@ -2001,7 +1705,7 @@ CALL [1] { function: _+_ args: { IDENT [17] { - name: @x:0 + name: @ac:1:0 } LIST [18] { elements: { @@ -2009,7 +1713,7 @@ CALL [1] { function: _+_ args: { IDENT [20] { - name: @c:0 + name: @it:1:0 } CONSTANT [21] { value: 1 } } @@ -2021,7 +1725,7 @@ CALL [1] { } result: { IDENT [22] { - name: @x:0 + name: @ac:1:0 } } } @@ -2033,13 +1737,13 @@ CALL [1] { function: _==_ args: { COMPREHENSION [24] { - iter_var: @c:1 + iter_var: @it:0:0 iter_range: { IDENT [25] { name: @index0 } } - accu_var: @x:1 + accu_var: @ac:0:0 accu_init: { LIST [26] { elements: { @@ -2054,7 +1758,7 @@ CALL [1] { function: _+_ args: { IDENT [29] { - name: @x:1 + name: @ac:0:0 } IDENT [30] { name: @index2 @@ -2064,7 +1768,7 @@ CALL [1] { } result: { IDENT [31] { - name: @x:1 + name: @ac:0:0 } } } @@ -2096,7 +1800,7 @@ CALL [1] { LIST [3] { elements: { COMPREHENSION [4] { - iter_var: @c:0 + iter_var: @it:1:0 iter_range: { LIST [5] { elements: { @@ -2106,7 +1810,7 @@ CALL [1] { } } } - accu_var: @x:0 + accu_var: @ac:1:0 accu_init: { LIST [9] { elements: { @@ -2124,10 +1828,10 @@ CALL [1] { function: _==_ args: { IDENT [13] { - name: @c:0 + name: @it:1:0 } IDENT [14] { - name: @c:1 + name: @it:0:0 } } } @@ -2135,26 +1839,26 @@ CALL [1] { function: _+_ args: { IDENT [16] { - name: @x:0 + name: @ac:1:0 } LIST [17] { elements: { IDENT [18] { - name: @c:0 + name: @it:1:0 } } } } } IDENT [19] { - name: @x:0 + name: @ac:1:0 } } } } result: { IDENT [20] { - name: @x:0 + name: @ac:1:0 } } } @@ -2166,7 +1870,7 @@ CALL [1] { function: _==_ args: { COMPREHENSION [22] { - iter_var: @c:1 + iter_var: @it:0:0 iter_range: { LIST [23] { elements: { @@ -2175,7 +1879,7 @@ CALL [1] { } } } - accu_var: @x:1 + accu_var: @ac:0:0 accu_init: { LIST [26] { elements: { @@ -2190,7 +1894,7 @@ CALL [1] { function: _+_ args: { IDENT [29] { - name: @x:1 + name: @ac:0:0 } IDENT [30] { name: @index0 @@ -2200,7 +1904,7 @@ CALL [1] { } result: { IDENT [31] { - name: @x:1 + name: @ac:0:0 } } } @@ -2232,96 +1936,43 @@ CALL [1] { elements: { LIST [3] { elements: { - CONSTANT [4] { value: 1 } - CONSTANT [5] { value: 2 } - CONSTANT [6] { value: 3 } - } - } - LIST [7] { - elements: { - COMPREHENSION [8] { - iter_var: @c:0 + COMPREHENSION [4] { + iter_var: @it:1:0 iter_range: { - IDENT [9] { - name: @index0 - } - } - accu_var: @x:0 - accu_init: { - LIST [10] { + LIST [5] { elements: { + CONSTANT [6] { value: 1 } + CONSTANT [7] { value: 2 } + CONSTANT [8] { value: 3 } } } } - loop_condition: { - CONSTANT [11] { value: true } - } - loop_step: { - CALL [12] { - function: _+_ - args: { - IDENT [13] { - name: @x:0 - } - LIST [14] { - elements: { - CALL [15] { - function: _+_ - args: { - IDENT [16] { - name: @c:0 - } - CONSTANT [17] { value: 1 } - } - } - } - } - } - } - } - result: { - IDENT [18] { - name: @x:0 - } - } - } - } - } - LIST [19] { - elements: { - COMPREHENSION [20] { - iter_var: @c:2 - iter_range: { - IDENT [21] { - name: @index0 - } - } - accu_var: @x:2 + accu_var: @ac:1:0 accu_init: { - LIST [22] { + LIST [9] { elements: { } } } loop_condition: { - CONSTANT [23] { value: true } + CONSTANT [10] { value: true } } loop_step: { - CALL [24] { + CALL [11] { function: _+_ args: { - IDENT [25] { - name: @x:2 + IDENT [12] { + name: @ac:1:0 } - LIST [26] { + LIST [13] { elements: { - CALL [27] { + CALL [14] { function: _+_ args: { - IDENT [28] { - name: @c:2 + IDENT [15] { + name: @it:1:0 } - CONSTANT [29] { value: 1 } + CONSTANT [16] { value: 1 } } } } @@ -2330,92 +1981,66 @@ CALL [1] { } } result: { - IDENT [30] { - name: @x:2 + IDENT [17] { + name: @ac:1:0 } } } } } - } - } - CALL [31] { - function: _==_ - args: { - COMPREHENSION [32] { - iter_var: @c:1 + COMPREHENSION [18] { + iter_var: @it:0:0 iter_range: { - IDENT [33] { - name: @index0 - } - } - accu_var: @x:1 - accu_init: { - LIST [34] { + LIST [19] { elements: { + CONSTANT [20] { value: 1 } + CONSTANT [21] { value: 2 } + CONSTANT [22] { value: 3 } } } } - loop_condition: { - CONSTANT [35] { value: true } - } - loop_step: { - CALL [36] { - function: _+_ - args: { - IDENT [37] { - name: @x:1 - } - IDENT [38] { - name: @index1 - } - } - } - } - result: { - IDENT [39] { - name: @x:1 - } - } - } - COMPREHENSION [40] { - iter_var: @c:3 - iter_range: { - IDENT [41] { - name: @index0 - } - } - accu_var: @x:3 + accu_var: @ac:0:0 accu_init: { - LIST [42] { + LIST [23] { elements: { } } } loop_condition: { - CONSTANT [43] { value: true } + CONSTANT [24] { value: true } } loop_step: { - CALL [44] { + CALL [25] { function: _+_ args: { - IDENT [45] { - name: @x:3 + IDENT [26] { + name: @ac:0:0 } - IDENT [46] { - name: @index2 + IDENT [27] { + name: @index0 } } } } result: { - IDENT [47] { - name: @x:3 + IDENT [28] { + name: @ac:0:0 } } } } } + CALL [29] { + function: _==_ + args: { + IDENT [30] { + name: @index1 + } + IDENT [31] { + name: @index1 + } + } + } } } Test case: INCLUSION_LIST @@ -2585,13 +2210,13 @@ CALL [1] { LIST [13] { elements: { COMPREHENSION [14] { - iter_var: @c:0 + iter_var: @it:1:0 iter_range: { IDENT [15] { name: @index1 } } - accu_var: @x:0 + accu_var: @ac:1:0 accu_init: { LIST [16] { elements: { @@ -2606,7 +2231,7 @@ CALL [1] { function: _+_ args: { IDENT [19] { - name: @x:0 + name: @ac:1:0 } LIST [20] { elements: { @@ -2623,7 +2248,7 @@ CALL [1] { } result: { IDENT [24] { - name: @x:0 + name: @ac:1:0 } } } @@ -2635,13 +2260,13 @@ CALL [1] { function: _==_ args: { COMPREHENSION [26] { - iter_var: @c:1 + iter_var: @it:0:0 iter_range: { IDENT [27] { name: @index1 } } - accu_var: @x:1 + accu_var: @ac:0:0 accu_init: { LIST [28] { elements: { @@ -2656,7 +2281,7 @@ CALL [1] { function: _+_ args: { IDENT [31] { - name: @x:1 + name: @ac:0:0 } IDENT [32] { name: @index2 @@ -2666,7 +2291,7 @@ CALL [1] { } result: { IDENT [33] { - name: @x:1 + name: @ac:0:0 } } } @@ -2713,7 +2338,7 @@ CALL [1] { function: _||_ args: { COMPREHENSION [9] { - iter_var: @c:0 + iter_var: @it:0:0 iter_range: { LIST [10] { elements: { @@ -2738,7 +2363,7 @@ CALL [1] { } } } - accu_var: @x:0 + accu_var: @ac:0:0 accu_init: { CONSTANT [17] { value: false } } @@ -2750,7 +2375,7 @@ CALL [1] { function: !_ args: { IDENT [20] { - name: @x:0 + name: @ac:0:0 } } } @@ -2762,7 +2387,7 @@ CALL [1] { function: _||_ args: { IDENT [22] { - name: @x:0 + name: @ac:0:0 } CALL [23] { function: _>_ @@ -2771,7 +2396,7 @@ CALL [1] { function: _-_ args: { IDENT [25] { - name: @c:0 + name: @it:0:0 } CONSTANT [26] { value: 1 } } @@ -2784,7 +2409,7 @@ CALL [1] { } result: { IDENT [28] { - name: @x:0 + name: @ac:0:0 } } } @@ -2807,10 +2432,10 @@ CALL [1] { function: _+_ args: { IDENT [4] { - name: @c:0 + name: @it:1:0 } IDENT [5] { - name: @c:0 + name: @it:1:0 } } } @@ -2818,20 +2443,20 @@ CALL [1] { function: _+_ args: { IDENT [7] { - name: @c:1 + name: @it:0:0 } IDENT [8] { - name: @c:1 + name: @it:0:0 } } } } } COMPREHENSION [9] { - iter_var: @c:1 + iter_var: @it:0:0 iter_range: { COMPREHENSION [10] { - iter_var: @c:0 + iter_var: @it:1:0 iter_range: { LIST [11] { elements: { @@ -2840,7 +2465,7 @@ CALL [1] { } } } - accu_var: @x:0 + accu_var: @ac:1:0 accu_init: { LIST [14] { elements: { @@ -2855,7 +2480,7 @@ CALL [1] { function: _+_ args: { IDENT [17] { - name: @x:0 + name: @ac:1:0 } LIST [18] { elements: { @@ -2876,12 +2501,12 @@ CALL [1] { } result: { IDENT [22] { - name: @x:0 + name: @ac:1:0 } } } } - accu_var: @x:1 + accu_var: @ac:0:0 accu_init: { LIST [23] { elements: { @@ -2896,7 +2521,7 @@ CALL [1] { function: _+_ args: { IDENT [26] { - name: @x:1 + name: @ac:0:0 } LIST [27] { elements: { @@ -2917,7 +2542,7 @@ CALL [1] { } result: { IDENT [31] { - name: @x:1 + name: @ac:0:0 } } } diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_6.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_6.baseline index 0172a0726..89e38dc92 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_6.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_6.baseline @@ -1145,270 +1145,61 @@ CALL [1] { args: { LIST [2] { elements: { - LIST [3] { - elements: { - CONSTANT [4] { value: 1 } - } - } - LIST [5] { - elements: { - CONSTANT [6] { value: 2 } - } - } - CALL [7] { - function: _+_ + CALL [3] { + function: size args: { - CALL [8] { - function: size - args: { - LIST [9] { - elements: { - COMPREHENSION [10] { - iter_var: @c:0 - iter_range: { - IDENT [11] { - name: @index0 - } - } - accu_var: @x:0 - accu_init: { - CONSTANT [12] { value: false } - } - loop_condition: { - CALL [13] { - function: @not_strictly_false - args: { - CALL [14] { - function: !_ - args: { - IDENT [15] { - name: @x:0 - } - } - } - } - } - } - loop_step: { - CALL [16] { - function: _||_ - args: { - IDENT [17] { - name: @x:0 - } - CALL [18] { - function: _>_ - args: { - IDENT [19] { - name: @c:0 - } - CONSTANT [20] { value: 0 } - } - } - } - } - } - result: { - IDENT [21] { - name: @x:0 - } + LIST [4] { + elements: { + COMPREHENSION [5] { + iter_var: @it:0:0 + iter_range: { + LIST [6] { + elements: { + CONSTANT [7] { value: 1 } } } } - } - } - } - CALL [22] { - function: size - args: { - LIST [23] { - elements: { - COMPREHENSION [24] { - iter_var: @c:1 - iter_range: { - IDENT [25] { - name: @index0 - } - } - accu_var: @x:1 - accu_init: { - CONSTANT [26] { value: false } - } - loop_condition: { - CALL [27] { - function: @not_strictly_false - args: { - CALL [28] { - function: !_ - args: { - IDENT [29] { - name: @x:1 - } - } - } - } - } - } - loop_step: { - CALL [30] { - function: _||_ + accu_var: @ac:0:0 + accu_init: { + CONSTANT [8] { value: false } + } + loop_condition: { + CALL [9] { + function: @not_strictly_false + args: { + CALL [10] { + function: !_ args: { - IDENT [31] { - name: @x:1 - } - CALL [32] { - function: _>_ - args: { - IDENT [33] { - name: @c:1 - } - CONSTANT [34] { value: 0 } - } + IDENT [11] { + name: @ac:0:0 } } } } - result: { - IDENT [35] { - name: @x:1 - } - } } } - } - } - } - } - } - CALL [36] { - function: _+_ - args: { - IDENT [37] { - name: @index2 - } - CALL [38] { - function: size - args: { - LIST [39] { - elements: { - COMPREHENSION [40] { - iter_var: @c:2 - iter_range: { - IDENT [41] { - name: @index1 - } - } - accu_var: @x:2 - accu_init: { - CONSTANT [42] { value: false } - } - loop_condition: { - CALL [43] { - function: @not_strictly_false - args: { - CALL [44] { - function: !_ - args: { - IDENT [45] { - name: @x:2 - } - } - } - } + loop_step: { + CALL [12] { + function: _||_ + args: { + IDENT [13] { + name: @ac:0:0 } - } - loop_step: { - CALL [46] { - function: _||_ + CALL [14] { + function: _>_ args: { - IDENT [47] { - name: @x:2 - } - CALL [48] { - function: _>_ - args: { - IDENT [49] { - name: @c:2 - } - CONSTANT [50] { value: 1 } - } + IDENT [15] { + name: @it:0:0 } + CONSTANT [16] { value: 0 } } } } - result: { - IDENT [51] { - name: @x:2 - } - } } } - } - } - } - } - } - CALL [52] { - function: _+_ - args: { - IDENT [53] { - name: @index3 - } - CALL [54] { - function: size - args: { - LIST [55] { - elements: { - COMPREHENSION [56] { - iter_var: @c:3 - iter_range: { - IDENT [57] { - name: @index1 - } - } - accu_var: @x:3 - accu_init: { - CONSTANT [58] { value: false } - } - loop_condition: { - CALL [59] { - function: @not_strictly_false - args: { - CALL [60] { - function: !_ - args: { - IDENT [61] { - name: @x:3 - } - } - } - } - } - } - loop_step: { - CALL [62] { - function: _||_ - args: { - IDENT [63] { - name: @x:3 - } - CALL [64] { - function: _>_ - args: { - IDENT [65] { - name: @c:3 - } - CONSTANT [66] { value: 1 } - } - } - } - } - } - result: { - IDENT [67] { - name: @x:3 - } - } + result: { + IDENT [17] { + name: @ac:0:0 } } } @@ -1416,177 +1207,33 @@ CALL [1] { } } } - } - } - CALL [68] { - function: _==_ - args: { - IDENT [69] { - name: @index4 - } - CONSTANT [70] { value: 4 } - } - } - } -} -Test case: MULTIPLE_MACROS_2 -Source: [[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == 'a')] + [['a'].exists(l, l == 'a')] == [true, true, true, true] -=====> -CALL [1] { - function: cel.@block - args: { - LIST [2] { - elements: { - LIST [3] { - elements: { - CONSTANT [4] { value: 1 } - } - } - LIST [5] { - elements: { - CONSTANT [6] { value: "a" } - } - } - CALL [7] { - function: _+_ + CALL [18] { + function: size args: { - CALL [8] { - function: _+_ - args: { - LIST [9] { - elements: { - COMPREHENSION [10] { - iter_var: @c:0 - iter_range: { - IDENT [11] { - name: @index0 - } - } - accu_var: @x:0 - accu_init: { - CONSTANT [12] { value: false } - } - loop_condition: { - CALL [13] { - function: @not_strictly_false - args: { - CALL [14] { - function: !_ - args: { - IDENT [15] { - name: @x:0 - } - } - } - } - } - } - loop_step: { - CALL [16] { - function: _||_ - args: { - IDENT [17] { - name: @x:0 - } - CALL [18] { - function: _>_ - args: { - IDENT [19] { - name: @c:0 - } - CONSTANT [20] { value: 0 } - } - } - } - } - } - result: { - IDENT [21] { - name: @x:0 - } - } - } - } - } - LIST [22] { - elements: { - COMPREHENSION [23] { - iter_var: @c:1 - iter_range: { - IDENT [24] { - name: @index0 - } - } - accu_var: @x:1 - accu_init: { - CONSTANT [25] { value: false } - } - loop_condition: { - CALL [26] { - function: @not_strictly_false - args: { - CALL [27] { - function: !_ - args: { - IDENT [28] { - name: @x:1 - } - } - } - } - } - } - loop_step: { - CALL [29] { - function: _||_ - args: { - IDENT [30] { - name: @x:1 - } - CALL [31] { - function: _>_ - args: { - IDENT [32] { - name: @c:1 - } - CONSTANT [33] { value: 0 } - } - } - } - } - } - result: { - IDENT [34] { - name: @x:1 - } - } - } - } - } - } - } - LIST [35] { + LIST [19] { elements: { - COMPREHENSION [36] { - iter_var: @c:2 + COMPREHENSION [20] { + iter_var: @it:0:0 iter_range: { - IDENT [37] { - name: @index1 + LIST [21] { + elements: { + CONSTANT [22] { value: 2 } + } } } - accu_var: @x:2 + accu_var: @ac:0:0 accu_init: { - CONSTANT [38] { value: false } + CONSTANT [23] { value: false } } loop_condition: { - CALL [39] { + CALL [24] { function: @not_strictly_false args: { - CALL [40] { + CALL [25] { function: !_ args: { - IDENT [41] { - name: @x:2 + IDENT [26] { + name: @ac:0:0 } } } @@ -1594,27 +1241,27 @@ CALL [1] { } } loop_step: { - CALL [42] { + CALL [27] { function: _||_ args: { - IDENT [43] { - name: @x:2 + IDENT [28] { + name: @ac:0:0 } - CALL [44] { - function: _==_ + CALL [29] { + function: _>_ args: { - IDENT [45] { - name: @c:2 + IDENT [30] { + name: @it:0:0 } - CONSTANT [46] { value: "a" } + CONSTANT [31] { value: 1 } } } } } } result: { - IDENT [47] { - name: @x:2 + IDENT [32] { + name: @ac:0:0 } } } @@ -1624,86 +1271,43 @@ CALL [1] { } } } - CALL [48] { + CALL [33] { function: _==_ args: { - CALL [49] { + CALL [34] { function: _+_ args: { - IDENT [50] { - name: @index2 - } - LIST [51] { - elements: { - COMPREHENSION [52] { - iter_var: @c:3 - iter_range: { - IDENT [53] { - name: @index1 - } - } - accu_var: @x:3 - accu_init: { - CONSTANT [54] { value: false } - } - loop_condition: { - CALL [55] { - function: @not_strictly_false - args: { - CALL [56] { - function: !_ - args: { - IDENT [57] { - name: @x:3 - } - } - } - } - } - } - loop_step: { - CALL [58] { - function: _||_ - args: { - IDENT [59] { - name: @x:3 - } - CALL [60] { - function: _==_ - args: { - IDENT [61] { - name: @c:3 - } - CONSTANT [62] { value: "a" } - } - } - } + CALL [35] { + function: _+_ + args: { + CALL [36] { + function: _+_ + args: { + IDENT [37] { + name: @index0 } - } - result: { - IDENT [63] { - name: @x:3 + IDENT [38] { + name: @index0 } } } + IDENT [39] { + name: @index1 + } } } + IDENT [40] { + name: @index1 + } } } - LIST [64] { - elements: { - CONSTANT [65] { value: true } - CONSTANT [66] { value: true } - CONSTANT [67] { value: true } - CONSTANT [68] { value: true } - } - } + CONSTANT [41] { value: 4 } } } } } -Test case: MULTIPLE_MACROS_3 -Source: [1].exists(i, i > 0) && [1].exists(j, j > 0) && [1].exists(k, k > 1) && [2].exists(l, l > 1) +Test case: MULTIPLE_MACROS_2 +Source: [[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == 'a')] + [['a'].exists(l, l == 'a')] == [true, true, true, true] =====> CALL [1] { function: cel.@block @@ -1712,37 +1316,28 @@ CALL [1] { elements: { LIST [3] { elements: { - CONSTANT [4] { value: 1 } - } - } - } - } - CALL [5] { - function: _&&_ - args: { - CALL [6] { - function: _&&_ - args: { - COMPREHENSION [7] { - iter_var: @c:0 + COMPREHENSION [4] { + iter_var: @it:0:0 iter_range: { - IDENT [8] { - name: @index0 + LIST [5] { + elements: { + CONSTANT [6] { value: 1 } + } } } - accu_var: @x:0 + accu_var: @ac:0:0 accu_init: { - CONSTANT [9] { value: false } + CONSTANT [7] { value: false } } loop_condition: { - CALL [10] { + CALL [8] { function: @not_strictly_false args: { - CALL [11] { + CALL [9] { function: !_ args: { - IDENT [12] { - name: @x:0 + IDENT [10] { + name: @ac:0:0 } } } @@ -1750,38 +1345,44 @@ CALL [1] { } } loop_step: { - CALL [13] { + CALL [11] { function: _||_ args: { - IDENT [14] { - name: @x:0 + IDENT [12] { + name: @ac:0:0 } - CALL [15] { + CALL [13] { function: _>_ args: { - IDENT [16] { - name: @c:0 + IDENT [14] { + name: @it:0:0 } - CONSTANT [17] { value: 0 } + CONSTANT [15] { value: 0 } } } } } } result: { - IDENT [18] { - name: @x:0 + IDENT [16] { + name: @ac:0:0 } } } - COMPREHENSION [19] { - iter_var: @c:1 + } + } + LIST [17] { + elements: { + COMPREHENSION [18] { + iter_var: @it:0:1 iter_range: { - IDENT [20] { - name: @index0 + LIST [19] { + elements: { + CONSTANT [20] { value: "a" } + } } } - accu_var: @x:1 + accu_var: @ac:0:1 accu_init: { CONSTANT [21] { value: false } } @@ -1793,7 +1394,7 @@ CALL [1] { function: !_ args: { IDENT [24] { - name: @x:1 + name: @ac:0:1 } } } @@ -1805,15 +1406,15 @@ CALL [1] { function: _||_ args: { IDENT [26] { - name: @x:1 + name: @ac:0:1 } CALL [27] { - function: _>_ + function: _==_ args: { IDENT [28] { - name: @c:1 + name: @it:0:1 } - CONSTANT [29] { value: 0 } + CONSTANT [29] { value: "a" } } } } @@ -1821,35 +1422,175 @@ CALL [1] { } result: { IDENT [30] { - name: @x:1 + name: @ac:0:1 + } + } + } + } + } + } + } + CALL [31] { + function: _==_ + args: { + CALL [32] { + function: _+_ + args: { + CALL [33] { + function: _+_ + args: { + CALL [34] { + function: _+_ + args: { + IDENT [35] { + name: @index0 + } + IDENT [36] { + name: @index0 + } + } + } + IDENT [37] { + name: @index1 + } + } + } + IDENT [38] { + name: @index1 + } + } + } + LIST [39] { + elements: { + CONSTANT [40] { value: true } + CONSTANT [41] { value: true } + CONSTANT [42] { value: true } + CONSTANT [43] { value: true } + } + } + } + } + } +} +Test case: MULTIPLE_MACROS_3 +Source: [1].exists(i, i > 0) && [1].exists(j, j > 0) && [1].exists(k, k > 1) && [2].exists(l, l > 1) +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + COMPREHENSION [3] { + iter_var: @it:0:0 + iter_range: { + LIST [4] { + elements: { + CONSTANT [5] { value: 1 } + } + } + } + accu_var: @ac:0:0 + accu_init: { + CONSTANT [6] { value: false } + } + loop_condition: { + CALL [7] { + function: @not_strictly_false + args: { + CALL [8] { + function: !_ + args: { + IDENT [9] { + name: @ac:0:0 + } + } + } + } + } + } + loop_step: { + CALL [10] { + function: _||_ + args: { + IDENT [11] { + name: @ac:0:0 + } + CALL [12] { + function: _>_ + args: { + IDENT [13] { + name: @it:0:0 + } + CONSTANT [14] { value: 0 } + } + } + } + } + } + result: { + IDENT [15] { + name: @ac:0:0 + } + } + } + CALL [16] { + function: _||_ + args: { + IDENT [17] { + name: @ac:0:0 + } + CALL [18] { + function: _>_ + args: { + IDENT [19] { + name: @it:0:0 } + CONSTANT [20] { value: 1 } } } } } - CALL [31] { + } + } + CALL [21] { + function: _&&_ + args: { + CALL [22] { + function: _&&_ + args: { + IDENT [23] { + name: @index0 + } + IDENT [24] { + name: @index0 + } + } + } + CALL [25] { function: _&&_ args: { - COMPREHENSION [32] { - iter_var: @c:2 + COMPREHENSION [26] { + iter_var: @it:0:0 iter_range: { - IDENT [33] { - name: @index0 + LIST [27] { + elements: { + CONSTANT [28] { value: 1 } + } } } - accu_var: @x:2 + accu_var: @ac:0:0 accu_init: { - CONSTANT [34] { value: false } + CONSTANT [29] { value: false } } loop_condition: { - CALL [35] { + CALL [30] { function: @not_strictly_false args: { - CALL [36] { + CALL [31] { function: !_ args: { - IDENT [37] { - name: @x:2 + IDENT [32] { + name: @ac:0:0 } } } @@ -1857,52 +1598,38 @@ CALL [1] { } } loop_step: { - CALL [38] { - function: _||_ - args: { - IDENT [39] { - name: @x:2 - } - CALL [40] { - function: _>_ - args: { - IDENT [41] { - name: @c:2 - } - CONSTANT [42] { value: 1 } - } - } - } + IDENT [33] { + name: @index1 } } result: { - IDENT [43] { - name: @x:2 + IDENT [34] { + name: @ac:0:0 } } } - COMPREHENSION [44] { - iter_var: @c:3 + COMPREHENSION [35] { + iter_var: @it:0:0 iter_range: { - LIST [45] { + LIST [36] { elements: { - CONSTANT [46] { value: 2 } + CONSTANT [37] { value: 2 } } } } - accu_var: @x:3 + accu_var: @ac:0:0 accu_init: { - CONSTANT [47] { value: false } + CONSTANT [38] { value: false } } loop_condition: { - CALL [48] { + CALL [39] { function: @not_strictly_false args: { - CALL [49] { + CALL [40] { function: !_ args: { - IDENT [50] { - name: @x:3 + IDENT [41] { + name: @ac:0:0 } } } @@ -1910,27 +1637,13 @@ CALL [1] { } } loop_step: { - CALL [51] { - function: _||_ - args: { - IDENT [52] { - name: @x:3 - } - CALL [53] { - function: _>_ - args: { - IDENT [54] { - name: @c:3 - } - CONSTANT [55] { value: 1 } - } - } - } + IDENT [42] { + name: @index1 } } result: { - IDENT [56] { - name: @x:3 + IDENT [43] { + name: @ac:0:0 } } } @@ -1966,18 +1679,18 @@ CALL [1] { function: _+_ args: { IDENT [12] { - name: @x:1 + name: @ac:0:0 } LIST [13] { elements: { COMPREHENSION [14] { - iter_var: @c:0 + iter_var: @it:1:0 iter_range: { IDENT [15] { name: @index0 } } - accu_var: @x:0 + accu_var: @ac:1:0 accu_init: { LIST [16] { elements: { @@ -1992,7 +1705,7 @@ CALL [1] { function: _+_ args: { IDENT [19] { - name: @x:0 + name: @ac:1:0 } LIST [20] { elements: { @@ -2000,7 +1713,7 @@ CALL [1] { function: _+_ args: { IDENT [22] { - name: @c:0 + name: @it:1:0 } CONSTANT [23] { value: 1 } } @@ -2012,7 +1725,7 @@ CALL [1] { } result: { IDENT [24] { - name: @x:0 + name: @ac:1:0 } } } @@ -2026,13 +1739,13 @@ CALL [1] { function: _==_ args: { COMPREHENSION [26] { - iter_var: @c:1 + iter_var: @it:0:0 iter_range: { IDENT [27] { name: @index0 } } - accu_var: @x:1 + accu_var: @ac:0:0 accu_init: { LIST [28] { elements: { @@ -2049,7 +1762,7 @@ CALL [1] { } result: { IDENT [31] { - name: @x:1 + name: @ac:0:0 } } } @@ -2082,12 +1795,12 @@ CALL [1] { function: _+_ args: { IDENT [4] { - name: @x:1 + name: @ac:0:0 } LIST [5] { elements: { COMPREHENSION [6] { - iter_var: @c:0 + iter_var: @it:1:0 iter_range: { LIST [7] { elements: { @@ -2097,7 +1810,7 @@ CALL [1] { } } } - accu_var: @x:0 + accu_var: @ac:1:0 accu_init: { LIST [11] { elements: { @@ -2115,10 +1828,10 @@ CALL [1] { function: _==_ args: { IDENT [15] { - name: @c:0 + name: @it:1:0 } IDENT [16] { - name: @c:1 + name: @it:0:0 } } } @@ -2126,26 +1839,26 @@ CALL [1] { function: _+_ args: { IDENT [18] { - name: @x:0 + name: @ac:1:0 } LIST [19] { elements: { IDENT [20] { - name: @c:0 + name: @it:1:0 } } } } } IDENT [21] { - name: @x:0 + name: @ac:1:0 } } } } result: { IDENT [22] { - name: @x:0 + name: @ac:1:0 } } } @@ -2159,7 +1872,7 @@ CALL [1] { function: _==_ args: { COMPREHENSION [24] { - iter_var: @c:1 + iter_var: @it:0:0 iter_range: { LIST [25] { elements: { @@ -2168,7 +1881,7 @@ CALL [1] { } } } - accu_var: @x:1 + accu_var: @ac:0:0 accu_init: { LIST [28] { elements: { @@ -2185,7 +1898,7 @@ CALL [1] { } result: { IDENT [31] { - name: @x:1 + name: @ac:0:0 } } } @@ -2215,112 +1928,51 @@ CALL [1] { args: { LIST [2] { elements: { - LIST [3] { - elements: { - CONSTANT [4] { value: 1 } - CONSTANT [5] { value: 2 } - CONSTANT [6] { value: 3 } - } - } - CALL [7] { + CALL [3] { function: _+_ args: { - IDENT [8] { - name: @x:1 + IDENT [4] { + name: @ac:0:0 } - LIST [9] { + LIST [5] { elements: { - COMPREHENSION [10] { - iter_var: @c:0 + COMPREHENSION [6] { + iter_var: @it:1:0 iter_range: { - IDENT [11] { - name: @index0 - } - } - accu_var: @x:0 - accu_init: { - LIST [12] { + LIST [7] { elements: { + CONSTANT [8] { value: 1 } + CONSTANT [9] { value: 2 } + CONSTANT [10] { value: 3 } } } } - loop_condition: { - CONSTANT [13] { value: true } - } - loop_step: { - CALL [14] { - function: _+_ - args: { - IDENT [15] { - name: @x:0 - } - LIST [16] { - elements: { - CALL [17] { - function: _+_ - args: { - IDENT [18] { - name: @c:0 - } - CONSTANT [19] { value: 1 } - } - } - } - } - } - } - } - result: { - IDENT [20] { - name: @x:0 - } - } - } - } - } - } - } - CALL [21] { - function: _+_ - args: { - IDENT [22] { - name: @x:3 - } - LIST [23] { - elements: { - COMPREHENSION [24] { - iter_var: @c:2 - iter_range: { - IDENT [25] { - name: @index0 - } - } - accu_var: @x:2 + accu_var: @ac:1:0 accu_init: { - LIST [26] { + LIST [11] { elements: { } } } loop_condition: { - CONSTANT [27] { value: true } + CONSTANT [12] { value: true } } loop_step: { - CALL [28] { + CALL [13] { function: _+_ args: { - IDENT [29] { - name: @x:2 + IDENT [14] { + name: @ac:1:0 } - LIST [30] { + LIST [15] { elements: { - CALL [31] { + CALL [16] { function: _+_ args: { - IDENT [32] { - name: @c:2 + IDENT [17] { + name: @it:1:0 } - CONSTANT [33] { value: 1 } + CONSTANT [18] { value: 1 } } } } @@ -2329,8 +1981,8 @@ CALL [1] { } } result: { - IDENT [34] { - name: @x:2 + IDENT [19] { + name: @ac:1:0 } } } @@ -2338,69 +1990,51 @@ CALL [1] { } } } - } - } - CALL [35] { - function: _==_ - args: { - COMPREHENSION [36] { - iter_var: @c:1 + COMPREHENSION [20] { + iter_var: @it:0:0 iter_range: { - IDENT [37] { - name: @index0 - } - } - accu_var: @x:1 - accu_init: { - LIST [38] { + LIST [21] { elements: { + CONSTANT [22] { value: 1 } + CONSTANT [23] { value: 2 } + CONSTANT [24] { value: 3 } } } } - loop_condition: { - CONSTANT [39] { value: true } - } - loop_step: { - IDENT [40] { - name: @index1 - } - } - result: { - IDENT [41] { - name: @x:1 - } - } - } - COMPREHENSION [42] { - iter_var: @c:3 - iter_range: { - IDENT [43] { - name: @index0 - } - } - accu_var: @x:3 + accu_var: @ac:0:0 accu_init: { - LIST [44] { + LIST [25] { elements: { } } } loop_condition: { - CONSTANT [45] { value: true } + CONSTANT [26] { value: true } } loop_step: { - IDENT [46] { - name: @index2 + IDENT [27] { + name: @index0 } } result: { - IDENT [47] { - name: @x:3 + IDENT [28] { + name: @ac:0:0 } } } } } + CALL [29] { + function: _==_ + args: { + IDENT [30] { + name: @index1 + } + IDENT [31] { + name: @index1 + } + } + } } } Test case: INCLUSION_LIST @@ -2571,18 +2205,18 @@ CALL [1] { function: _+_ args: { IDENT [14] { - name: @x:1 + name: @ac:0:0 } LIST [15] { elements: { COMPREHENSION [16] { - iter_var: @c:0 + iter_var: @it:1:0 iter_range: { IDENT [17] { name: @index1 } } - accu_var: @x:0 + accu_var: @ac:1:0 accu_init: { LIST [18] { elements: { @@ -2597,7 +2231,7 @@ CALL [1] { function: _+_ args: { IDENT [21] { - name: @x:0 + name: @ac:1:0 } LIST [22] { elements: { @@ -2614,7 +2248,7 @@ CALL [1] { } result: { IDENT [26] { - name: @x:0 + name: @ac:1:0 } } } @@ -2628,13 +2262,13 @@ CALL [1] { function: _==_ args: { COMPREHENSION [28] { - iter_var: @c:1 + iter_var: @it:0:0 iter_range: { IDENT [29] { name: @index1 } } - accu_var: @x:1 + accu_var: @ac:0:0 accu_init: { LIST [30] { elements: { @@ -2651,7 +2285,7 @@ CALL [1] { } result: { IDENT [33] { - name: @x:1 + name: @ac:0:0 } } } @@ -2698,7 +2332,7 @@ CALL [1] { function: _||_ args: { COMPREHENSION [9] { - iter_var: @c:0 + iter_var: @it:0:0 iter_range: { LIST [10] { elements: { @@ -2723,7 +2357,7 @@ CALL [1] { } } } - accu_var: @x:0 + accu_var: @ac:0:0 accu_init: { CONSTANT [17] { value: false } } @@ -2735,7 +2369,7 @@ CALL [1] { function: !_ args: { IDENT [20] { - name: @x:0 + name: @ac:0:0 } } } @@ -2747,7 +2381,7 @@ CALL [1] { function: _||_ args: { IDENT [22] { - name: @x:0 + name: @ac:0:0 } CALL [23] { function: _>_ @@ -2756,7 +2390,7 @@ CALL [1] { function: _-_ args: { IDENT [25] { - name: @c:0 + name: @it:0:0 } CONSTANT [26] { value: 1 } } @@ -2769,7 +2403,7 @@ CALL [1] { } result: { IDENT [28] { - name: @x:0 + name: @ac:0:0 } } } @@ -2792,10 +2426,10 @@ CALL [1] { function: _+_ args: { IDENT [4] { - name: @c:0 + name: @it:1:0 } IDENT [5] { - name: @c:0 + name: @it:1:0 } } } @@ -2803,20 +2437,20 @@ CALL [1] { function: _+_ args: { IDENT [7] { - name: @c:1 + name: @it:0:0 } IDENT [8] { - name: @c:1 + name: @it:0:0 } } } } } COMPREHENSION [9] { - iter_var: @c:1 + iter_var: @it:0:0 iter_range: { COMPREHENSION [10] { - iter_var: @c:0 + iter_var: @it:1:0 iter_range: { LIST [11] { elements: { @@ -2825,7 +2459,7 @@ CALL [1] { } } } - accu_var: @x:0 + accu_var: @ac:1:0 accu_init: { LIST [14] { elements: { @@ -2840,7 +2474,7 @@ CALL [1] { function: _+_ args: { IDENT [17] { - name: @x:0 + name: @ac:1:0 } LIST [18] { elements: { @@ -2861,12 +2495,12 @@ CALL [1] { } result: { IDENT [22] { - name: @x:0 + name: @ac:1:0 } } } } - accu_var: @x:1 + accu_var: @ac:0:0 accu_init: { LIST [23] { elements: { @@ -2881,7 +2515,7 @@ CALL [1] { function: _+_ args: { IDENT [26] { - name: @x:1 + name: @ac:0:0 } LIST [27] { elements: { @@ -2902,7 +2536,7 @@ CALL [1] { } result: { IDENT [31] { - name: @x:1 + name: @ac:0:0 } } } diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_7.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_7.baseline index 5fa185080..e40934fc9 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_7.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_7.baseline @@ -1142,272 +1142,61 @@ CALL [1] { args: { LIST [2] { elements: { - LIST [3] { - elements: { - CONSTANT [4] { value: 1 } - } - } - LIST [5] { - elements: { - CONSTANT [6] { value: 2 } - } - } - CALL [7] { - function: _+_ + CALL [3] { + function: size args: { - CALL [8] { - function: _+_ - args: { - CALL [9] { - function: size - args: { - LIST [10] { + LIST [4] { + elements: { + COMPREHENSION [5] { + iter_var: @it:0:0 + iter_range: { + LIST [6] { elements: { - COMPREHENSION [11] { - iter_var: @c:0 - iter_range: { - IDENT [12] { - name: @index0 - } - } - accu_var: @x:0 - accu_init: { - CONSTANT [13] { value: false } - } - loop_condition: { - CALL [14] { - function: @not_strictly_false - args: { - CALL [15] { - function: !_ - args: { - IDENT [16] { - name: @x:0 - } - } - } - } - } - } - loop_step: { - CALL [17] { - function: _||_ - args: { - IDENT [18] { - name: @x:0 - } - CALL [19] { - function: _>_ - args: { - IDENT [20] { - name: @c:0 - } - CONSTANT [21] { value: 0 } - } - } - } - } - } - result: { - IDENT [22] { - name: @x:0 - } - } - } + CONSTANT [7] { value: 1 } } } } - } - CALL [23] { - function: size - args: { - LIST [24] { - elements: { - COMPREHENSION [25] { - iter_var: @c:1 - iter_range: { - IDENT [26] { - name: @index0 - } - } - accu_var: @x:1 - accu_init: { - CONSTANT [27] { value: false } - } - loop_condition: { - CALL [28] { - function: @not_strictly_false - args: { - CALL [29] { - function: !_ - args: { - IDENT [30] { - name: @x:1 - } - } - } - } - } - } - loop_step: { - CALL [31] { - function: _||_ - args: { - IDENT [32] { - name: @x:1 - } - CALL [33] { - function: _>_ - args: { - IDENT [34] { - name: @c:1 - } - CONSTANT [35] { value: 0 } - } - } - } - } - } - result: { - IDENT [36] { - name: @x:1 - } - } - } - } - } + accu_var: @ac:0:0 + accu_init: { + CONSTANT [8] { value: false } } - } - } - } - CALL [37] { - function: size - args: { - LIST [38] { - elements: { - COMPREHENSION [39] { - iter_var: @c:2 - iter_range: { - IDENT [40] { - name: @index1 - } - } - accu_var: @x:2 - accu_init: { - CONSTANT [41] { value: false } - } - loop_condition: { - CALL [42] { - function: @not_strictly_false - args: { - CALL [43] { - function: !_ - args: { - IDENT [44] { - name: @x:2 - } - } - } - } - } - } - loop_step: { - CALL [45] { - function: _||_ + loop_condition: { + CALL [9] { + function: @not_strictly_false + args: { + CALL [10] { + function: !_ args: { - IDENT [46] { - name: @x:2 - } - CALL [47] { - function: _>_ - args: { - IDENT [48] { - name: @c:2 - } - CONSTANT [49] { value: 1 } - } + IDENT [11] { + name: @ac:0:0 } } } } - result: { - IDENT [50] { - name: @x:2 - } - } } } - } - } - } - } - } - } - } - CALL [51] { - function: _==_ - args: { - CALL [52] { - function: _+_ - args: { - IDENT [53] { - name: @index2 - } - CALL [54] { - function: size - args: { - LIST [55] { - elements: { - COMPREHENSION [56] { - iter_var: @c:3 - iter_range: { - IDENT [57] { - name: @index1 - } - } - accu_var: @x:3 - accu_init: { - CONSTANT [58] { value: false } - } - loop_condition: { - CALL [59] { - function: @not_strictly_false - args: { - CALL [60] { - function: !_ - args: { - IDENT [61] { - name: @x:3 - } - } - } - } + loop_step: { + CALL [12] { + function: _||_ + args: { + IDENT [13] { + name: @ac:0:0 } - } - loop_step: { - CALL [62] { - function: _||_ + CALL [14] { + function: _>_ args: { - IDENT [63] { - name: @x:3 - } - CALL [64] { - function: _>_ - args: { - IDENT [65] { - name: @c:3 - } - CONSTANT [66] { value: 1 } - } + IDENT [15] { + name: @it:0:0 } + CONSTANT [16] { value: 0 } } } } - result: { - IDENT [67] { - name: @x:3 - } - } + } + } + result: { + IDENT [17] { + name: @ac:0:0 } } } @@ -1415,229 +1204,33 @@ CALL [1] { } } } - CONSTANT [68] { value: 4 } - } - } - } -} -Test case: MULTIPLE_MACROS_2 -Source: [[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == 'a')] + [['a'].exists(l, l == 'a')] == [true, true, true, true] -=====> -CALL [1] { - function: cel.@block - args: { - LIST [2] { - elements: { - LIST [3] { - elements: { - CONSTANT [4] { value: 1 } - } - } - LIST [5] { - elements: { - CONSTANT [6] { value: "a" } - } - } - CALL [7] { - function: _+_ + CALL [18] { + function: size args: { - CALL [8] { - function: _+_ - args: { - CALL [9] { - function: _+_ - args: { - LIST [10] { - elements: { - COMPREHENSION [11] { - iter_var: @c:0 - iter_range: { - IDENT [12] { - name: @index0 - } - } - accu_var: @x:0 - accu_init: { - CONSTANT [13] { value: false } - } - loop_condition: { - CALL [14] { - function: @not_strictly_false - args: { - CALL [15] { - function: !_ - args: { - IDENT [16] { - name: @x:0 - } - } - } - } - } - } - loop_step: { - CALL [17] { - function: _||_ - args: { - IDENT [18] { - name: @x:0 - } - CALL [19] { - function: _>_ - args: { - IDENT [20] { - name: @c:0 - } - CONSTANT [21] { value: 0 } - } - } - } - } - } - result: { - IDENT [22] { - name: @x:0 - } - } - } - } - } - LIST [23] { - elements: { - COMPREHENSION [24] { - iter_var: @c:1 - iter_range: { - IDENT [25] { - name: @index0 - } - } - accu_var: @x:1 - accu_init: { - CONSTANT [26] { value: false } - } - loop_condition: { - CALL [27] { - function: @not_strictly_false - args: { - CALL [28] { - function: !_ - args: { - IDENT [29] { - name: @x:1 - } - } - } - } - } - } - loop_step: { - CALL [30] { - function: _||_ - args: { - IDENT [31] { - name: @x:1 - } - CALL [32] { - function: _>_ - args: { - IDENT [33] { - name: @c:1 - } - CONSTANT [34] { value: 0 } - } - } - } - } - } - result: { - IDENT [35] { - name: @x:1 - } - } - } - } - } - } - } - LIST [36] { - elements: { - COMPREHENSION [37] { - iter_var: @c:2 - iter_range: { - IDENT [38] { - name: @index1 - } - } - accu_var: @x:2 - accu_init: { - CONSTANT [39] { value: false } - } - loop_condition: { - CALL [40] { - function: @not_strictly_false - args: { - CALL [41] { - function: !_ - args: { - IDENT [42] { - name: @x:2 - } - } - } - } - } - } - loop_step: { - CALL [43] { - function: _||_ - args: { - IDENT [44] { - name: @x:2 - } - CALL [45] { - function: _==_ - args: { - IDENT [46] { - name: @c:2 - } - CONSTANT [47] { value: "a" } - } - } - } - } - } - result: { - IDENT [48] { - name: @x:2 - } - } - } - } - } - } - } - LIST [49] { + LIST [19] { elements: { - COMPREHENSION [50] { - iter_var: @c:3 + COMPREHENSION [20] { + iter_var: @it:0:0 iter_range: { - IDENT [51] { - name: @index1 + LIST [21] { + elements: { + CONSTANT [22] { value: 2 } + } } } - accu_var: @x:3 + accu_var: @ac:0:0 accu_init: { - CONSTANT [52] { value: false } + CONSTANT [23] { value: false } } loop_condition: { - CALL [53] { + CALL [24] { function: @not_strictly_false args: { - CALL [54] { + CALL [25] { function: !_ args: { - IDENT [55] { - name: @x:3 + IDENT [26] { + name: @ac:0:0 } } } @@ -1645,27 +1238,27 @@ CALL [1] { } } loop_step: { - CALL [56] { + CALL [27] { function: _||_ args: { - IDENT [57] { - name: @x:3 + IDENT [28] { + name: @ac:0:0 } - CALL [58] { - function: _==_ + CALL [29] { + function: _>_ args: { - IDENT [59] { - name: @c:3 + IDENT [30] { + name: @it:0:0 } - CONSTANT [60] { value: "a" } + CONSTANT [31] { value: 1 } } } } } } result: { - IDENT [61] { - name: @x:3 + IDENT [32] { + name: @ac:0:0 } } } @@ -1675,65 +1268,73 @@ CALL [1] { } } } - CALL [62] { + CALL [33] { function: _==_ args: { - IDENT [63] { - name: @index2 - } - LIST [64] { - elements: { - CONSTANT [65] { value: true } - CONSTANT [66] { value: true } - CONSTANT [67] { value: true } - CONSTANT [68] { value: true } + CALL [34] { + function: _+_ + args: { + CALL [35] { + function: _+_ + args: { + CALL [36] { + function: _+_ + args: { + IDENT [37] { + name: @index0 + } + IDENT [38] { + name: @index0 + } + } + } + IDENT [39] { + name: @index1 + } + } + } + IDENT [40] { + name: @index1 + } } } + CONSTANT [41] { value: 4 } } } } } -Test case: MULTIPLE_MACROS_3 -Source: [1].exists(i, i > 0) && [1].exists(j, j > 0) && [1].exists(k, k > 1) && [2].exists(l, l > 1) +Test case: MULTIPLE_MACROS_2 +Source: [[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == 'a')] + [['a'].exists(l, l == 'a')] == [true, true, true, true] =====> CALL [1] { - function: cel.@block - args: { - LIST [2] { - elements: { - LIST [3] { - elements: { - CONSTANT [4] { value: 1 } - } - } - } - } - CALL [5] { - function: _&&_ - args: { - CALL [6] { - function: _&&_ - args: { - COMPREHENSION [7] { - iter_var: @c:0 + function: cel.@block + args: { + LIST [2] { + elements: { + LIST [3] { + elements: { + COMPREHENSION [4] { + iter_var: @it:0:0 iter_range: { - IDENT [8] { - name: @index0 + LIST [5] { + elements: { + CONSTANT [6] { value: 1 } + } } } - accu_var: @x:0 + accu_var: @ac:0:0 accu_init: { - CONSTANT [9] { value: false } + CONSTANT [7] { value: false } } loop_condition: { - CALL [10] { + CALL [8] { function: @not_strictly_false args: { - CALL [11] { + CALL [9] { function: !_ args: { - IDENT [12] { - name: @x:0 + IDENT [10] { + name: @ac:0:0 } } } @@ -1741,38 +1342,44 @@ CALL [1] { } } loop_step: { - CALL [13] { + CALL [11] { function: _||_ args: { - IDENT [14] { - name: @x:0 + IDENT [12] { + name: @ac:0:0 } - CALL [15] { + CALL [13] { function: _>_ args: { - IDENT [16] { - name: @c:0 + IDENT [14] { + name: @it:0:0 } - CONSTANT [17] { value: 0 } + CONSTANT [15] { value: 0 } } } } } } result: { - IDENT [18] { - name: @x:0 + IDENT [16] { + name: @ac:0:0 } } } - COMPREHENSION [19] { - iter_var: @c:1 + } + } + LIST [17] { + elements: { + COMPREHENSION [18] { + iter_var: @it:0:1 iter_range: { - IDENT [20] { - name: @index0 + LIST [19] { + elements: { + CONSTANT [20] { value: "a" } + } } } - accu_var: @x:1 + accu_var: @ac:0:1 accu_init: { CONSTANT [21] { value: false } } @@ -1784,7 +1391,7 @@ CALL [1] { function: !_ args: { IDENT [24] { - name: @x:1 + name: @ac:0:1 } } } @@ -1796,15 +1403,15 @@ CALL [1] { function: _||_ args: { IDENT [26] { - name: @x:1 + name: @ac:0:1 } CALL [27] { - function: _>_ + function: _==_ args: { IDENT [28] { - name: @c:1 + name: @it:0:1 } - CONSTANT [29] { value: 0 } + CONSTANT [29] { value: "a" } } } } @@ -1812,35 +1419,175 @@ CALL [1] { } result: { IDENT [30] { - name: @x:1 + name: @ac:0:1 + } + } + } + } + } + } + } + CALL [31] { + function: _==_ + args: { + CALL [32] { + function: _+_ + args: { + CALL [33] { + function: _+_ + args: { + CALL [34] { + function: _+_ + args: { + IDENT [35] { + name: @index0 + } + IDENT [36] { + name: @index0 + } + } + } + IDENT [37] { + name: @index1 + } + } + } + IDENT [38] { + name: @index1 + } + } + } + LIST [39] { + elements: { + CONSTANT [40] { value: true } + CONSTANT [41] { value: true } + CONSTANT [42] { value: true } + CONSTANT [43] { value: true } + } + } + } + } + } +} +Test case: MULTIPLE_MACROS_3 +Source: [1].exists(i, i > 0) && [1].exists(j, j > 0) && [1].exists(k, k > 1) && [2].exists(l, l > 1) +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + COMPREHENSION [3] { + iter_var: @it:0:0 + iter_range: { + LIST [4] { + elements: { + CONSTANT [5] { value: 1 } + } + } + } + accu_var: @ac:0:0 + accu_init: { + CONSTANT [6] { value: false } + } + loop_condition: { + CALL [7] { + function: @not_strictly_false + args: { + CALL [8] { + function: !_ + args: { + IDENT [9] { + name: @ac:0:0 + } + } + } + } + } + } + loop_step: { + CALL [10] { + function: _||_ + args: { + IDENT [11] { + name: @ac:0:0 + } + CALL [12] { + function: _>_ + args: { + IDENT [13] { + name: @it:0:0 + } + CONSTANT [14] { value: 0 } + } + } + } + } + } + result: { + IDENT [15] { + name: @ac:0:0 + } + } + } + CALL [16] { + function: _||_ + args: { + IDENT [17] { + name: @ac:0:0 + } + CALL [18] { + function: _>_ + args: { + IDENT [19] { + name: @it:0:0 } + CONSTANT [20] { value: 1 } } } } } - CALL [31] { + } + } + CALL [21] { + function: _&&_ + args: { + CALL [22] { + function: _&&_ + args: { + IDENT [23] { + name: @index0 + } + IDENT [24] { + name: @index0 + } + } + } + CALL [25] { function: _&&_ args: { - COMPREHENSION [32] { - iter_var: @c:2 + COMPREHENSION [26] { + iter_var: @it:0:0 iter_range: { - IDENT [33] { - name: @index0 + LIST [27] { + elements: { + CONSTANT [28] { value: 1 } + } } } - accu_var: @x:2 + accu_var: @ac:0:0 accu_init: { - CONSTANT [34] { value: false } + CONSTANT [29] { value: false } } loop_condition: { - CALL [35] { + CALL [30] { function: @not_strictly_false args: { - CALL [36] { + CALL [31] { function: !_ args: { - IDENT [37] { - name: @x:2 + IDENT [32] { + name: @ac:0:0 } } } @@ -1848,52 +1595,38 @@ CALL [1] { } } loop_step: { - CALL [38] { - function: _||_ - args: { - IDENT [39] { - name: @x:2 - } - CALL [40] { - function: _>_ - args: { - IDENT [41] { - name: @c:2 - } - CONSTANT [42] { value: 1 } - } - } - } + IDENT [33] { + name: @index1 } } result: { - IDENT [43] { - name: @x:2 + IDENT [34] { + name: @ac:0:0 } } } - COMPREHENSION [44] { - iter_var: @c:3 + COMPREHENSION [35] { + iter_var: @it:0:0 iter_range: { - LIST [45] { + LIST [36] { elements: { - CONSTANT [46] { value: 2 } + CONSTANT [37] { value: 2 } } } } - accu_var: @x:3 + accu_var: @ac:0:0 accu_init: { - CONSTANT [47] { value: false } + CONSTANT [38] { value: false } } loop_condition: { - CALL [48] { + CALL [39] { function: @not_strictly_false args: { - CALL [49] { + CALL [40] { function: !_ args: { - IDENT [50] { - name: @x:3 + IDENT [41] { + name: @ac:0:0 } } } @@ -1901,27 +1634,13 @@ CALL [1] { } } loop_step: { - CALL [51] { - function: _||_ - args: { - IDENT [52] { - name: @x:3 - } - CALL [53] { - function: _>_ - args: { - IDENT [54] { - name: @c:3 - } - CONSTANT [55] { value: 1 } - } - } - } + IDENT [42] { + name: @index1 } } result: { - IDENT [56] { - name: @x:3 + IDENT [43] { + name: @ac:0:0 } } } @@ -1954,13 +1673,13 @@ CALL [1] { } } COMPREHENSION [11] { - iter_var: @c:1 + iter_var: @it:0:0 iter_range: { IDENT [12] { name: @index0 } } - accu_var: @x:1 + accu_var: @ac:0:0 accu_init: { LIST [13] { elements: { @@ -1975,18 +1694,18 @@ CALL [1] { function: _+_ args: { IDENT [16] { - name: @x:1 + name: @ac:0:0 } LIST [17] { elements: { COMPREHENSION [18] { - iter_var: @c:0 + iter_var: @it:1:0 iter_range: { IDENT [19] { name: @index0 } } - accu_var: @x:0 + accu_var: @ac:1:0 accu_init: { LIST [20] { elements: { @@ -2001,7 +1720,7 @@ CALL [1] { function: _+_ args: { IDENT [23] { - name: @x:0 + name: @ac:1:0 } LIST [24] { elements: { @@ -2009,7 +1728,7 @@ CALL [1] { function: _+_ args: { IDENT [26] { - name: @c:0 + name: @it:1:0 } CONSTANT [27] { value: 1 } } @@ -2021,7 +1740,7 @@ CALL [1] { } result: { IDENT [28] { - name: @x:0 + name: @ac:1:0 } } } @@ -2032,7 +1751,7 @@ CALL [1] { } result: { IDENT [29] { - name: @x:1 + name: @ac:0:0 } } } @@ -2070,7 +1789,7 @@ CALL [1] { LIST [2] { elements: { COMPREHENSION [3] { - iter_var: @c:1 + iter_var: @it:0:0 iter_range: { LIST [4] { elements: { @@ -2079,7 +1798,7 @@ CALL [1] { } } } - accu_var: @x:1 + accu_var: @ac:0:0 accu_init: { LIST [7] { elements: { @@ -2094,12 +1813,12 @@ CALL [1] { function: _+_ args: { IDENT [10] { - name: @x:1 + name: @ac:0:0 } LIST [11] { elements: { COMPREHENSION [12] { - iter_var: @c:0 + iter_var: @it:1:0 iter_range: { LIST [13] { elements: { @@ -2109,7 +1828,7 @@ CALL [1] { } } } - accu_var: @x:0 + accu_var: @ac:1:0 accu_init: { LIST [17] { elements: { @@ -2127,10 +1846,10 @@ CALL [1] { function: _==_ args: { IDENT [21] { - name: @c:0 + name: @it:1:0 } IDENT [22] { - name: @c:1 + name: @it:0:0 } } } @@ -2138,26 +1857,26 @@ CALL [1] { function: _+_ args: { IDENT [24] { - name: @x:0 + name: @ac:1:0 } LIST [25] { elements: { IDENT [26] { - name: @c:0 + name: @it:1:0 } } } } } IDENT [27] { - name: @x:0 + name: @ac:1:0 } } } } result: { IDENT [28] { - name: @x:0 + name: @ac:1:0 } } } @@ -2168,7 +1887,7 @@ CALL [1] { } result: { IDENT [29] { - name: @x:1 + name: @ac:0:0 } } } @@ -2206,155 +1925,73 @@ CALL [1] { args: { LIST [2] { elements: { - LIST [3] { - elements: { - CONSTANT [4] { value: 1 } - CONSTANT [5] { value: 2 } - CONSTANT [6] { value: 3 } - } - } - COMPREHENSION [7] { - iter_var: @c:1 + COMPREHENSION [3] { + iter_var: @it:0:0 iter_range: { - IDENT [8] { - name: @index0 - } - } - accu_var: @x:1 - accu_init: { - LIST [9] { + LIST [4] { elements: { + CONSTANT [5] { value: 1 } + CONSTANT [6] { value: 2 } + CONSTANT [7] { value: 3 } } } } - loop_condition: { - CONSTANT [10] { value: true } - } - loop_step: { - CALL [11] { - function: _+_ - args: { - IDENT [12] { - name: @x:1 - } - LIST [13] { - elements: { - COMPREHENSION [14] { - iter_var: @c:0 - iter_range: { - IDENT [15] { - name: @index0 - } - } - accu_var: @x:0 - accu_init: { - LIST [16] { - elements: { - } - } - } - loop_condition: { - CONSTANT [17] { value: true } - } - loop_step: { - CALL [18] { - function: _+_ - args: { - IDENT [19] { - name: @x:0 - } - LIST [20] { - elements: { - CALL [21] { - function: _+_ - args: { - IDENT [22] { - name: @c:0 - } - CONSTANT [23] { value: 1 } - } - } - } - } - } - } - } - result: { - IDENT [24] { - name: @x:0 - } - } - } - } - } - } - } - } - result: { - IDENT [25] { - name: @x:1 - } - } - } - COMPREHENSION [26] { - iter_var: @c:3 - iter_range: { - IDENT [27] { - name: @index0 - } - } - accu_var: @x:3 + accu_var: @ac:0:0 accu_init: { - LIST [28] { + LIST [8] { elements: { } } } loop_condition: { - CONSTANT [29] { value: true } + CONSTANT [9] { value: true } } loop_step: { - CALL [30] { + CALL [10] { function: _+_ args: { - IDENT [31] { - name: @x:3 + IDENT [11] { + name: @ac:0:0 } - LIST [32] { + LIST [12] { elements: { - COMPREHENSION [33] { - iter_var: @c:2 + COMPREHENSION [13] { + iter_var: @it:1:0 iter_range: { - IDENT [34] { - name: @index0 + LIST [14] { + elements: { + CONSTANT [15] { value: 1 } + CONSTANT [16] { value: 2 } + CONSTANT [17] { value: 3 } + } } } - accu_var: @x:2 + accu_var: @ac:1:0 accu_init: { - LIST [35] { + LIST [18] { elements: { } } } loop_condition: { - CONSTANT [36] { value: true } + CONSTANT [19] { value: true } } loop_step: { - CALL [37] { + CALL [20] { function: _+_ args: { - IDENT [38] { - name: @x:2 + IDENT [21] { + name: @ac:1:0 } - LIST [39] { + LIST [22] { elements: { - CALL [40] { + CALL [23] { function: _+_ args: { - IDENT [41] { - name: @c:2 + IDENT [24] { + name: @it:1:0 } - CONSTANT [42] { value: 1 } + CONSTANT [25] { value: 1 } } } } @@ -2363,8 +2000,8 @@ CALL [1] { } } result: { - IDENT [43] { - name: @x:2 + IDENT [26] { + name: @ac:1:0 } } } @@ -2374,21 +2011,21 @@ CALL [1] { } } result: { - IDENT [44] { - name: @x:3 + IDENT [27] { + name: @ac:0:0 } } } } } - CALL [45] { + CALL [28] { function: _==_ args: { - IDENT [46] { - name: @index1 + IDENT [29] { + name: @index0 } - IDENT [47] { - name: @index2 + IDENT [30] { + name: @index0 } } } @@ -2559,13 +2196,13 @@ CALL [1] { } } COMPREHENSION [13] { - iter_var: @c:1 + iter_var: @it:0:0 iter_range: { IDENT [14] { name: @index1 } } - accu_var: @x:1 + accu_var: @ac:0:0 accu_init: { LIST [15] { elements: { @@ -2580,18 +2217,18 @@ CALL [1] { function: _+_ args: { IDENT [18] { - name: @x:1 + name: @ac:0:0 } LIST [19] { elements: { COMPREHENSION [20] { - iter_var: @c:0 + iter_var: @it:1:0 iter_range: { IDENT [21] { name: @index1 } } - accu_var: @x:0 + accu_var: @ac:1:0 accu_init: { LIST [22] { elements: { @@ -2606,7 +2243,7 @@ CALL [1] { function: _+_ args: { IDENT [25] { - name: @x:0 + name: @ac:1:0 } LIST [26] { elements: { @@ -2623,7 +2260,7 @@ CALL [1] { } result: { IDENT [30] { - name: @x:0 + name: @ac:1:0 } } } @@ -2634,7 +2271,7 @@ CALL [1] { } result: { IDENT [31] { - name: @x:1 + name: @ac:0:0 } } } @@ -2689,7 +2326,7 @@ CALL [1] { function: _||_ args: { COMPREHENSION [9] { - iter_var: @c:0 + iter_var: @it:0:0 iter_range: { LIST [10] { elements: { @@ -2714,7 +2351,7 @@ CALL [1] { } } } - accu_var: @x:0 + accu_var: @ac:0:0 accu_init: { CONSTANT [17] { value: false } } @@ -2726,7 +2363,7 @@ CALL [1] { function: !_ args: { IDENT [20] { - name: @x:0 + name: @ac:0:0 } } } @@ -2738,7 +2375,7 @@ CALL [1] { function: _||_ args: { IDENT [22] { - name: @x:0 + name: @ac:0:0 } CALL [23] { function: _>_ @@ -2747,7 +2384,7 @@ CALL [1] { function: _-_ args: { IDENT [25] { - name: @c:0 + name: @it:0:0 } CONSTANT [26] { value: 1 } } @@ -2760,7 +2397,7 @@ CALL [1] { } result: { IDENT [28] { - name: @x:0 + name: @ac:0:0 } } } @@ -2783,10 +2420,10 @@ CALL [1] { function: _+_ args: { IDENT [4] { - name: @c:0 + name: @it:1:0 } IDENT [5] { - name: @c:0 + name: @it:1:0 } } } @@ -2794,20 +2431,20 @@ CALL [1] { function: _+_ args: { IDENT [7] { - name: @c:1 + name: @it:0:0 } IDENT [8] { - name: @c:1 + name: @it:0:0 } } } } } COMPREHENSION [9] { - iter_var: @c:1 + iter_var: @it:0:0 iter_range: { COMPREHENSION [10] { - iter_var: @c:0 + iter_var: @it:1:0 iter_range: { LIST [11] { elements: { @@ -2816,7 +2453,7 @@ CALL [1] { } } } - accu_var: @x:0 + accu_var: @ac:1:0 accu_init: { LIST [14] { elements: { @@ -2831,7 +2468,7 @@ CALL [1] { function: _+_ args: { IDENT [17] { - name: @x:0 + name: @ac:1:0 } LIST [18] { elements: { @@ -2852,12 +2489,12 @@ CALL [1] { } result: { IDENT [22] { - name: @x:0 + name: @ac:1:0 } } } } - accu_var: @x:1 + accu_var: @ac:0:0 accu_init: { LIST [23] { elements: { @@ -2872,7 +2509,7 @@ CALL [1] { function: _+_ args: { IDENT [26] { - name: @x:1 + name: @ac:0:0 } LIST [27] { elements: { @@ -2893,7 +2530,7 @@ CALL [1] { } result: { IDENT [31] { - name: @x:1 + name: @ac:0:0 } } } diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_8.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_8.baseline index 9da40d283..fd78a51a9 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_8.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_8.baseline @@ -1142,507 +1142,95 @@ CALL [1] { args: { LIST [2] { elements: { - LIST [3] { - elements: { - CONSTANT [4] { value: 1 } - } - } - LIST [5] { - elements: { - CONSTANT [6] { value: 2 } - } - } - CALL [7] { - function: _+_ + CALL [3] { + function: size args: { - CALL [8] { - function: _+_ - args: { - CALL [9] { - function: _+_ - args: { - CALL [10] { - function: size - args: { - LIST [11] { - elements: { - COMPREHENSION [12] { - iter_var: @c:0 - iter_range: { - IDENT [13] { - name: @index0 - } - } - accu_var: @x:0 - accu_init: { - CONSTANT [14] { value: false } - } - loop_condition: { - CALL [15] { - function: @not_strictly_false - args: { - CALL [16] { - function: !_ - args: { - IDENT [17] { - name: @x:0 - } - } - } - } - } - } - loop_step: { - CALL [18] { - function: _||_ - args: { - IDENT [19] { - name: @x:0 - } - CALL [20] { - function: _>_ - args: { - IDENT [21] { - name: @c:0 - } - CONSTANT [22] { value: 0 } - } - } - } - } - } - result: { - IDENT [23] { - name: @x:0 - } - } - } - } - } - } - } - CALL [24] { - function: size - args: { - LIST [25] { - elements: { - COMPREHENSION [26] { - iter_var: @c:1 - iter_range: { - IDENT [27] { - name: @index0 - } - } - accu_var: @x:1 - accu_init: { - CONSTANT [28] { value: false } - } - loop_condition: { - CALL [29] { - function: @not_strictly_false - args: { - CALL [30] { - function: !_ - args: { - IDENT [31] { - name: @x:1 - } - } - } - } - } - } - loop_step: { - CALL [32] { - function: _||_ - args: { - IDENT [33] { - name: @x:1 - } - CALL [34] { - function: _>_ - args: { - IDENT [35] { - name: @c:1 - } - CONSTANT [36] { value: 0 } - } - } - } - } - } - result: { - IDENT [37] { - name: @x:1 - } - } - } - } - } - } - } - } - } - CALL [38] { - function: size - args: { - LIST [39] { + LIST [4] { + elements: { + COMPREHENSION [5] { + iter_var: @it:0:0 + iter_range: { + LIST [6] { elements: { - COMPREHENSION [40] { - iter_var: @c:2 - iter_range: { - IDENT [41] { - name: @index1 - } - } - accu_var: @x:2 - accu_init: { - CONSTANT [42] { value: false } - } - loop_condition: { - CALL [43] { - function: @not_strictly_false - args: { - CALL [44] { - function: !_ - args: { - IDENT [45] { - name: @x:2 - } - } - } - } - } - } - loop_step: { - CALL [46] { - function: _||_ - args: { - IDENT [47] { - name: @x:2 - } - CALL [48] { - function: _>_ - args: { - IDENT [49] { - name: @c:2 - } - CONSTANT [50] { value: 1 } - } - } - } - } - } - result: { - IDENT [51] { - name: @x:2 - } - } - } + CONSTANT [7] { value: 1 } } } } - } - } - } - CALL [52] { - function: size - args: { - LIST [53] { - elements: { - COMPREHENSION [54] { - iter_var: @c:3 - iter_range: { - IDENT [55] { - name: @index1 - } - } - accu_var: @x:3 - accu_init: { - CONSTANT [56] { value: false } - } - loop_condition: { - CALL [57] { - function: @not_strictly_false - args: { - CALL [58] { - function: !_ - args: { - IDENT [59] { - name: @x:3 - } - } - } - } - } - } - loop_step: { - CALL [60] { - function: _||_ + accu_var: @ac:0:0 + accu_init: { + CONSTANT [8] { value: false } + } + loop_condition: { + CALL [9] { + function: @not_strictly_false + args: { + CALL [10] { + function: !_ args: { - IDENT [61] { - name: @x:3 - } - CALL [62] { - function: _>_ - args: { - IDENT [63] { - name: @c:3 - } - CONSTANT [64] { value: 1 } - } + IDENT [11] { + name: @ac:0:0 } } } } - result: { - IDENT [65] { - name: @x:3 - } - } } } - } - } - } - } - } - } - } - CALL [66] { - function: _==_ - args: { - IDENT [67] { - name: @index2 - } - CONSTANT [68] { value: 4 } - } - } - } -} -Test case: MULTIPLE_MACROS_2 -Source: [[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == 'a')] + [['a'].exists(l, l == 'a')] == [true, true, true, true] -=====> -CALL [1] { - function: cel.@block - args: { - LIST [2] { - elements: { - LIST [3] { - elements: { - CONSTANT [4] { value: 1 } - } - } - LIST [5] { - elements: { - CONSTANT [6] { value: "a" } - } - } - } - } - CALL [7] { - function: _==_ - args: { - CALL [8] { - function: _+_ - args: { - CALL [9] { - function: _+_ - args: { - CALL [10] { - function: _+_ - args: { - LIST [11] { - elements: { - COMPREHENSION [12] { - iter_var: @c:0 - iter_range: { - IDENT [13] { - name: @index0 - } - } - accu_var: @x:0 - accu_init: { - CONSTANT [14] { value: false } - } - loop_condition: { - CALL [15] { - function: @not_strictly_false - args: { - CALL [16] { - function: !_ - args: { - IDENT [17] { - name: @x:0 - } - } - } - } - } - } - loop_step: { - CALL [18] { - function: _||_ - args: { - IDENT [19] { - name: @x:0 - } - CALL [20] { - function: _>_ - args: { - IDENT [21] { - name: @c:0 - } - CONSTANT [22] { value: 0 } - } - } - } - } - } - result: { - IDENT [23] { - name: @x:0 - } - } + loop_step: { + CALL [12] { + function: _||_ + args: { + IDENT [13] { + name: @ac:0:0 } - } - } - LIST [24] { - elements: { - COMPREHENSION [25] { - iter_var: @c:1 - iter_range: { - IDENT [26] { - name: @index0 - } - } - accu_var: @x:1 - accu_init: { - CONSTANT [27] { value: false } - } - loop_condition: { - CALL [28] { - function: @not_strictly_false - args: { - CALL [29] { - function: !_ - args: { - IDENT [30] { - name: @x:1 - } - } - } - } - } - } - loop_step: { - CALL [31] { - function: _||_ - args: { - IDENT [32] { - name: @x:1 - } - CALL [33] { - function: _>_ - args: { - IDENT [34] { - name: @c:1 - } - CONSTANT [35] { value: 0 } - } - } - } - } - } - result: { - IDENT [36] { - name: @x:1 + CALL [14] { + function: _>_ + args: { + IDENT [15] { + name: @it:0:0 } + CONSTANT [16] { value: 0 } } } } } } - } - LIST [37] { - elements: { - COMPREHENSION [38] { - iter_var: @c:2 - iter_range: { - IDENT [39] { - name: @index1 - } - } - accu_var: @x:2 - accu_init: { - CONSTANT [40] { value: false } - } - loop_condition: { - CALL [41] { - function: @not_strictly_false - args: { - CALL [42] { - function: !_ - args: { - IDENT [43] { - name: @x:2 - } - } - } - } - } - } - loop_step: { - CALL [44] { - function: _||_ - args: { - IDENT [45] { - name: @x:2 - } - CALL [46] { - function: _==_ - args: { - IDENT [47] { - name: @c:2 - } - CONSTANT [48] { value: "a" } - } - } - } - } - } - result: { - IDENT [49] { - name: @x:2 - } - } + result: { + IDENT [17] { + name: @ac:0:0 } } } } } - LIST [50] { + } + } + CALL [18] { + function: size + args: { + LIST [19] { elements: { - COMPREHENSION [51] { - iter_var: @c:3 + COMPREHENSION [20] { + iter_var: @it:0:0 iter_range: { - IDENT [52] { - name: @index1 + LIST [21] { + elements: { + CONSTANT [22] { value: 2 } + } } } - accu_var: @x:3 + accu_var: @ac:0:0 accu_init: { - CONSTANT [53] { value: false } + CONSTANT [23] { value: false } } loop_condition: { - CALL [54] { + CALL [24] { function: @not_strictly_false args: { - CALL [55] { + CALL [25] { function: !_ args: { - IDENT [56] { - name: @x:3 + IDENT [26] { + name: @ac:0:0 } } } @@ -1650,27 +1238,27 @@ CALL [1] { } } loop_step: { - CALL [57] { + CALL [27] { function: _||_ args: { - IDENT [58] { - name: @x:3 + IDENT [28] { + name: @ac:0:0 } - CALL [59] { - function: _==_ + CALL [29] { + function: _>_ args: { - IDENT [60] { - name: @c:3 + IDENT [30] { + name: @it:0:0 } - CONSTANT [61] { value: "a" } + CONSTANT [31] { value: 1 } } } } } } result: { - IDENT [62] { - name: @x:3 + IDENT [32] { + name: @ac:0:0 } } } @@ -1678,20 +1266,45 @@ CALL [1] { } } } - LIST [63] { - elements: { - CONSTANT [64] { value: true } - CONSTANT [65] { value: true } - CONSTANT [66] { value: true } - CONSTANT [67] { value: true } + } + } + CALL [33] { + function: _==_ + args: { + CALL [34] { + function: _+_ + args: { + CALL [35] { + function: _+_ + args: { + CALL [36] { + function: _+_ + args: { + IDENT [37] { + name: @index0 + } + IDENT [38] { + name: @index0 + } + } + } + IDENT [39] { + name: @index1 + } + } + } + IDENT [40] { + name: @index1 + } } } + CONSTANT [41] { value: 4 } } } } } -Test case: MULTIPLE_MACROS_3 -Source: [1].exists(i, i > 0) && [1].exists(j, j > 0) && [1].exists(k, k > 1) && [2].exists(l, l > 1) +Test case: MULTIPLE_MACROS_2 +Source: [[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == 'a')] + [['a'].exists(l, l == 'a')] == [true, true, true, true] =====> CALL [1] { function: cel.@block @@ -1700,37 +1313,28 @@ CALL [1] { elements: { LIST [3] { elements: { - CONSTANT [4] { value: 1 } - } - } - } - } - CALL [5] { - function: _&&_ - args: { - CALL [6] { - function: _&&_ - args: { - COMPREHENSION [7] { - iter_var: @c:0 - iter_range: { - IDENT [8] { - name: @index0 + COMPREHENSION [4] { + iter_var: @it:0:0 + iter_range: { + LIST [5] { + elements: { + CONSTANT [6] { value: 1 } + } } } - accu_var: @x:0 + accu_var: @ac:0:0 accu_init: { - CONSTANT [9] { value: false } + CONSTANT [7] { value: false } } loop_condition: { - CALL [10] { + CALL [8] { function: @not_strictly_false args: { - CALL [11] { + CALL [9] { function: !_ args: { - IDENT [12] { - name: @x:0 + IDENT [10] { + name: @ac:0:0 } } } @@ -1738,38 +1342,44 @@ CALL [1] { } } loop_step: { - CALL [13] { + CALL [11] { function: _||_ args: { - IDENT [14] { - name: @x:0 + IDENT [12] { + name: @ac:0:0 } - CALL [15] { + CALL [13] { function: _>_ args: { - IDENT [16] { - name: @c:0 + IDENT [14] { + name: @it:0:0 } - CONSTANT [17] { value: 0 } + CONSTANT [15] { value: 0 } } } } } } result: { - IDENT [18] { - name: @x:0 + IDENT [16] { + name: @ac:0:0 } } } - COMPREHENSION [19] { - iter_var: @c:1 + } + } + LIST [17] { + elements: { + COMPREHENSION [18] { + iter_var: @it:0:1 iter_range: { - IDENT [20] { - name: @index0 + LIST [19] { + elements: { + CONSTANT [20] { value: "a" } + } } } - accu_var: @x:1 + accu_var: @ac:0:1 accu_init: { CONSTANT [21] { value: false } } @@ -1781,7 +1391,7 @@ CALL [1] { function: !_ args: { IDENT [24] { - name: @x:1 + name: @ac:0:1 } } } @@ -1793,15 +1403,15 @@ CALL [1] { function: _||_ args: { IDENT [26] { - name: @x:1 + name: @ac:0:1 } CALL [27] { - function: _>_ + function: _==_ args: { IDENT [28] { - name: @c:1 + name: @it:0:1 } - CONSTANT [29] { value: 0 } + CONSTANT [29] { value: "a" } } } } @@ -1809,35 +1419,175 @@ CALL [1] { } result: { IDENT [30] { - name: @x:1 + name: @ac:0:1 + } + } + } + } + } + } + } + CALL [31] { + function: _==_ + args: { + CALL [32] { + function: _+_ + args: { + CALL [33] { + function: _+_ + args: { + CALL [34] { + function: _+_ + args: { + IDENT [35] { + name: @index0 + } + IDENT [36] { + name: @index0 + } + } + } + IDENT [37] { + name: @index1 + } + } + } + IDENT [38] { + name: @index1 + } + } + } + LIST [39] { + elements: { + CONSTANT [40] { value: true } + CONSTANT [41] { value: true } + CONSTANT [42] { value: true } + CONSTANT [43] { value: true } + } + } + } + } + } +} +Test case: MULTIPLE_MACROS_3 +Source: [1].exists(i, i > 0) && [1].exists(j, j > 0) && [1].exists(k, k > 1) && [2].exists(l, l > 1) +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + COMPREHENSION [3] { + iter_var: @it:0:0 + iter_range: { + LIST [4] { + elements: { + CONSTANT [5] { value: 1 } + } + } + } + accu_var: @ac:0:0 + accu_init: { + CONSTANT [6] { value: false } + } + loop_condition: { + CALL [7] { + function: @not_strictly_false + args: { + CALL [8] { + function: !_ + args: { + IDENT [9] { + name: @ac:0:0 + } + } + } + } + } + } + loop_step: { + CALL [10] { + function: _||_ + args: { + IDENT [11] { + name: @ac:0:0 + } + CALL [12] { + function: _>_ + args: { + IDENT [13] { + name: @it:0:0 + } + CONSTANT [14] { value: 0 } + } + } + } + } + } + result: { + IDENT [15] { + name: @ac:0:0 + } + } + } + CALL [16] { + function: _||_ + args: { + IDENT [17] { + name: @ac:0:0 + } + CALL [18] { + function: _>_ + args: { + IDENT [19] { + name: @it:0:0 } + CONSTANT [20] { value: 1 } } } } } - CALL [31] { + } + } + CALL [21] { + function: _&&_ + args: { + CALL [22] { + function: _&&_ + args: { + IDENT [23] { + name: @index0 + } + IDENT [24] { + name: @index0 + } + } + } + CALL [25] { function: _&&_ args: { - COMPREHENSION [32] { - iter_var: @c:2 + COMPREHENSION [26] { + iter_var: @it:0:0 iter_range: { - IDENT [33] { - name: @index0 + LIST [27] { + elements: { + CONSTANT [28] { value: 1 } + } } } - accu_var: @x:2 + accu_var: @ac:0:0 accu_init: { - CONSTANT [34] { value: false } + CONSTANT [29] { value: false } } loop_condition: { - CALL [35] { + CALL [30] { function: @not_strictly_false args: { - CALL [36] { + CALL [31] { function: !_ args: { - IDENT [37] { - name: @x:2 + IDENT [32] { + name: @ac:0:0 } } } @@ -1845,52 +1595,38 @@ CALL [1] { } } loop_step: { - CALL [38] { - function: _||_ - args: { - IDENT [39] { - name: @x:2 - } - CALL [40] { - function: _>_ - args: { - IDENT [41] { - name: @c:2 - } - CONSTANT [42] { value: 1 } - } - } - } + IDENT [33] { + name: @index1 } } result: { - IDENT [43] { - name: @x:2 + IDENT [34] { + name: @ac:0:0 } } } - COMPREHENSION [44] { - iter_var: @c:3 + COMPREHENSION [35] { + iter_var: @it:0:0 iter_range: { - LIST [45] { + LIST [36] { elements: { - CONSTANT [46] { value: 2 } + CONSTANT [37] { value: 2 } } } } - accu_var: @x:3 + accu_var: @ac:0:0 accu_init: { - CONSTANT [47] { value: false } + CONSTANT [38] { value: false } } loop_condition: { - CALL [48] { + CALL [39] { function: @not_strictly_false args: { - CALL [49] { + CALL [40] { function: !_ args: { - IDENT [50] { - name: @x:3 + IDENT [41] { + name: @ac:0:0 } } } @@ -1898,27 +1634,13 @@ CALL [1] { } } loop_step: { - CALL [51] { - function: _||_ - args: { - IDENT [52] { - name: @x:3 - } - CALL [53] { - function: _>_ - args: { - IDENT [54] { - name: @c:3 - } - CONSTANT [55] { value: 1 } - } - } - } + IDENT [42] { + name: @index1 } } result: { - IDENT [56] { - name: @x:3 + IDENT [43] { + name: @ac:0:0 } } } @@ -1956,13 +1678,13 @@ CALL [1] { function: _==_ args: { COMPREHENSION [12] { - iter_var: @c:1 + iter_var: @it:0:0 iter_range: { IDENT [13] { name: @index0 } } - accu_var: @x:1 + accu_var: @ac:0:0 accu_init: { LIST [14] { elements: { @@ -1977,18 +1699,18 @@ CALL [1] { function: _+_ args: { IDENT [17] { - name: @x:1 + name: @ac:0:0 } LIST [18] { elements: { COMPREHENSION [19] { - iter_var: @c:0 + iter_var: @it:1:0 iter_range: { IDENT [20] { name: @index0 } } - accu_var: @x:0 + accu_var: @ac:1:0 accu_init: { LIST [21] { elements: { @@ -2003,7 +1725,7 @@ CALL [1] { function: _+_ args: { IDENT [24] { - name: @x:0 + name: @ac:1:0 } LIST [25] { elements: { @@ -2011,7 +1733,7 @@ CALL [1] { function: _+_ args: { IDENT [27] { - name: @c:0 + name: @it:1:0 } CONSTANT [28] { value: 1 } } @@ -2023,7 +1745,7 @@ CALL [1] { } result: { IDENT [29] { - name: @x:0 + name: @ac:1:0 } } } @@ -2034,7 +1756,7 @@ CALL [1] { } result: { IDENT [30] { - name: @x:1 + name: @ac:0:0 } } } @@ -2062,7 +1784,7 @@ CALL [31] { function: _==_ args: { COMPREHENSION [30] { - iter_var: @c:1 + iter_var: @it:0:0 iter_range: { LIST [1] { elements: { @@ -2071,7 +1793,7 @@ CALL [31] { } } } - accu_var: @x:1 + accu_var: @ac:0:0 accu_init: { LIST [24] { elements: { @@ -2086,12 +1808,12 @@ CALL [31] { function: _+_ args: { IDENT [26] { - name: @x:1 + name: @ac:0:0 } LIST [27] { elements: { COMPREHENSION [23] { - iter_var: @c:0 + iter_var: @it:1:0 iter_range: { LIST [6] { elements: { @@ -2101,7 +1823,7 @@ CALL [31] { } } } - accu_var: @x:0 + accu_var: @ac:1:0 accu_init: { LIST [15] { elements: { @@ -2119,10 +1841,10 @@ CALL [31] { function: _==_ args: { IDENT [12] { - name: @c:0 + name: @it:1:0 } IDENT [14] { - name: @c:1 + name: @it:0:0 } } } @@ -2130,26 +1852,26 @@ CALL [31] { function: _+_ args: { IDENT [17] { - name: @x:0 + name: @ac:1:0 } LIST [18] { elements: { IDENT [11] { - name: @c:0 + name: @it:1:0 } } } } } IDENT [20] { - name: @x:0 + name: @ac:1:0 } } } } result: { IDENT [22] { - name: @x:0 + name: @ac:1:0 } } } @@ -2160,7 +1882,7 @@ CALL [31] { } result: { IDENT [29] { - name: @x:1 + name: @ac:0:0 } } } @@ -2188,160 +1910,73 @@ CALL [1] { args: { LIST [2] { elements: { - LIST [3] { - elements: { - CONSTANT [4] { value: 1 } - CONSTANT [5] { value: 2 } - CONSTANT [6] { value: 3 } - } - } - } - } - CALL [7] { - function: _==_ - args: { - COMPREHENSION [8] { - iter_var: @c:1 + COMPREHENSION [3] { + iter_var: @it:0:0 iter_range: { - IDENT [9] { - name: @index0 - } - } - accu_var: @x:1 - accu_init: { - LIST [10] { + LIST [4] { elements: { + CONSTANT [5] { value: 1 } + CONSTANT [6] { value: 2 } + CONSTANT [7] { value: 3 } } } } - loop_condition: { - CONSTANT [11] { value: true } - } - loop_step: { - CALL [12] { - function: _+_ - args: { - IDENT [13] { - name: @x:1 - } - LIST [14] { - elements: { - COMPREHENSION [15] { - iter_var: @c:0 - iter_range: { - IDENT [16] { - name: @index0 - } - } - accu_var: @x:0 - accu_init: { - LIST [17] { - elements: { - } - } - } - loop_condition: { - CONSTANT [18] { value: true } - } - loop_step: { - CALL [19] { - function: _+_ - args: { - IDENT [20] { - name: @x:0 - } - LIST [21] { - elements: { - CALL [22] { - function: _+_ - args: { - IDENT [23] { - name: @c:0 - } - CONSTANT [24] { value: 1 } - } - } - } - } - } - } - } - result: { - IDENT [25] { - name: @x:0 - } - } - } - } - } - } - } - } - result: { - IDENT [26] { - name: @x:1 - } - } - } - COMPREHENSION [27] { - iter_var: @c:3 - iter_range: { - IDENT [28] { - name: @index0 - } - } - accu_var: @x:3 + accu_var: @ac:0:0 accu_init: { - LIST [29] { + LIST [8] { elements: { } } } loop_condition: { - CONSTANT [30] { value: true } + CONSTANT [9] { value: true } } loop_step: { - CALL [31] { + CALL [10] { function: _+_ args: { - IDENT [32] { - name: @x:3 + IDENT [11] { + name: @ac:0:0 } - LIST [33] { + LIST [12] { elements: { - COMPREHENSION [34] { - iter_var: @c:2 + COMPREHENSION [13] { + iter_var: @it:1:0 iter_range: { - IDENT [35] { - name: @index0 + LIST [14] { + elements: { + CONSTANT [15] { value: 1 } + CONSTANT [16] { value: 2 } + CONSTANT [17] { value: 3 } + } } } - accu_var: @x:2 + accu_var: @ac:1:0 accu_init: { - LIST [36] { + LIST [18] { elements: { } } } loop_condition: { - CONSTANT [37] { value: true } + CONSTANT [19] { value: true } } loop_step: { - CALL [38] { + CALL [20] { function: _+_ args: { - IDENT [39] { - name: @x:2 + IDENT [21] { + name: @ac:1:0 } - LIST [40] { + LIST [22] { elements: { - CALL [41] { + CALL [23] { function: _+_ args: { - IDENT [42] { - name: @c:2 + IDENT [24] { + name: @it:1:0 } - CONSTANT [43] { value: 1 } + CONSTANT [25] { value: 1 } } } } @@ -2350,8 +1985,8 @@ CALL [1] { } } result: { - IDENT [44] { - name: @x:2 + IDENT [26] { + name: @ac:1:0 } } } @@ -2361,13 +1996,24 @@ CALL [1] { } } result: { - IDENT [45] { - name: @x:3 + IDENT [27] { + name: @ac:0:0 } } } } } + CALL [28] { + function: _==_ + args: { + IDENT [29] { + name: @index0 + } + IDENT [30] { + name: @index0 + } + } + } } } Test case: INCLUSION_LIST @@ -2540,13 +2186,13 @@ CALL [1] { function: _==_ args: { COMPREHENSION [14] { - iter_var: @c:1 + iter_var: @it:0:0 iter_range: { IDENT [15] { name: @index1 } } - accu_var: @x:1 + accu_var: @ac:0:0 accu_init: { LIST [16] { elements: { @@ -2561,18 +2207,18 @@ CALL [1] { function: _+_ args: { IDENT [19] { - name: @x:1 + name: @ac:0:0 } LIST [20] { elements: { COMPREHENSION [21] { - iter_var: @c:0 + iter_var: @it:1:0 iter_range: { IDENT [22] { name: @index1 } } - accu_var: @x:0 + accu_var: @ac:1:0 accu_init: { LIST [23] { elements: { @@ -2587,7 +2233,7 @@ CALL [1] { function: _+_ args: { IDENT [26] { - name: @x:0 + name: @ac:1:0 } LIST [27] { elements: { @@ -2604,7 +2250,7 @@ CALL [1] { } result: { IDENT [31] { - name: @x:0 + name: @ac:1:0 } } } @@ -2615,7 +2261,7 @@ CALL [1] { } result: { IDENT [32] { - name: @x:1 + name: @ac:0:0 } } } @@ -2662,7 +2308,7 @@ CALL [1] { function: _||_ args: { COMPREHENSION [9] { - iter_var: @c:0 + iter_var: @it:0:0 iter_range: { LIST [10] { elements: { @@ -2687,7 +2333,7 @@ CALL [1] { } } } - accu_var: @x:0 + accu_var: @ac:0:0 accu_init: { CONSTANT [17] { value: false } } @@ -2699,7 +2345,7 @@ CALL [1] { function: !_ args: { IDENT [20] { - name: @x:0 + name: @ac:0:0 } } } @@ -2711,7 +2357,7 @@ CALL [1] { function: _||_ args: { IDENT [22] { - name: @x:0 + name: @ac:0:0 } CALL [23] { function: _>_ @@ -2720,7 +2366,7 @@ CALL [1] { function: _-_ args: { IDENT [25] { - name: @c:0 + name: @it:0:0 } CONSTANT [26] { value: 1 } } @@ -2733,7 +2379,7 @@ CALL [1] { } result: { IDENT [28] { - name: @x:0 + name: @ac:0:0 } } } @@ -2756,10 +2402,10 @@ CALL [1] { function: _+_ args: { IDENT [4] { - name: @c:0 + name: @it:1:0 } IDENT [5] { - name: @c:0 + name: @it:1:0 } } } @@ -2767,20 +2413,20 @@ CALL [1] { function: _+_ args: { IDENT [7] { - name: @c:1 + name: @it:0:0 } IDENT [8] { - name: @c:1 + name: @it:0:0 } } } } } COMPREHENSION [9] { - iter_var: @c:1 + iter_var: @it:0:0 iter_range: { COMPREHENSION [10] { - iter_var: @c:0 + iter_var: @it:1:0 iter_range: { LIST [11] { elements: { @@ -2789,7 +2435,7 @@ CALL [1] { } } } - accu_var: @x:0 + accu_var: @ac:1:0 accu_init: { LIST [14] { elements: { @@ -2804,7 +2450,7 @@ CALL [1] { function: _+_ args: { IDENT [17] { - name: @x:0 + name: @ac:1:0 } LIST [18] { elements: { @@ -2825,12 +2471,12 @@ CALL [1] { } result: { IDENT [22] { - name: @x:0 + name: @ac:1:0 } } } } - accu_var: @x:1 + accu_var: @ac:0:0 accu_init: { LIST [23] { elements: { @@ -2845,7 +2491,7 @@ CALL [1] { function: _+_ args: { IDENT [26] { - name: @x:1 + name: @ac:0:0 } LIST [27] { elements: { @@ -2866,7 +2512,7 @@ CALL [1] { } result: { IDENT [31] { - name: @x:1 + name: @ac:0:0 } } } diff --git a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_9.baseline b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_9.baseline index 025cd4769..b273bd6f2 100644 --- a/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_9.baseline +++ b/optimizer/src/test/resources/subexpression_ast_block_recursion_depth_9.baseline @@ -1130,504 +1130,95 @@ CALL [1] { args: { LIST [2] { elements: { - LIST [3] { - elements: { - CONSTANT [4] { value: 1 } - } - } - LIST [5] { - elements: { - CONSTANT [6] { value: 2 } - } - } - } - } - CALL [7] { - function: _==_ - args: { - CALL [8] { - function: _+_ + CALL [3] { + function: size args: { - CALL [9] { - function: _+_ - args: { - CALL [10] { - function: _+_ - args: { - CALL [11] { - function: size - args: { - LIST [12] { - elements: { - COMPREHENSION [13] { - iter_var: @c:0 - iter_range: { - IDENT [14] { - name: @index0 - } - } - accu_var: @x:0 - accu_init: { - CONSTANT [15] { value: false } - } - loop_condition: { - CALL [16] { - function: @not_strictly_false - args: { - CALL [17] { - function: !_ - args: { - IDENT [18] { - name: @x:0 - } - } - } - } - } - } - loop_step: { - CALL [19] { - function: _||_ - args: { - IDENT [20] { - name: @x:0 - } - CALL [21] { - function: _>_ - args: { - IDENT [22] { - name: @c:0 - } - CONSTANT [23] { value: 0 } - } - } - } - } - } - result: { - IDENT [24] { - name: @x:0 - } - } - } - } - } - } - } - CALL [25] { - function: size - args: { - LIST [26] { - elements: { - COMPREHENSION [27] { - iter_var: @c:1 - iter_range: { - IDENT [28] { - name: @index0 - } - } - accu_var: @x:1 - accu_init: { - CONSTANT [29] { value: false } - } - loop_condition: { - CALL [30] { - function: @not_strictly_false - args: { - CALL [31] { - function: !_ - args: { - IDENT [32] { - name: @x:1 - } - } - } - } - } - } - loop_step: { - CALL [33] { - function: _||_ - args: { - IDENT [34] { - name: @x:1 - } - CALL [35] { - function: _>_ - args: { - IDENT [36] { - name: @c:1 - } - CONSTANT [37] { value: 0 } - } - } - } - } - } - result: { - IDENT [38] { - name: @x:1 - } - } - } - } - } - } - } - } - } - CALL [39] { - function: size - args: { - LIST [40] { + LIST [4] { + elements: { + COMPREHENSION [5] { + iter_var: @it:0:0 + iter_range: { + LIST [6] { elements: { - COMPREHENSION [41] { - iter_var: @c:2 - iter_range: { - IDENT [42] { - name: @index1 - } - } - accu_var: @x:2 - accu_init: { - CONSTANT [43] { value: false } - } - loop_condition: { - CALL [44] { - function: @not_strictly_false - args: { - CALL [45] { - function: !_ - args: { - IDENT [46] { - name: @x:2 - } - } - } - } - } - } - loop_step: { - CALL [47] { - function: _||_ - args: { - IDENT [48] { - name: @x:2 - } - CALL [49] { - function: _>_ - args: { - IDENT [50] { - name: @c:2 - } - CONSTANT [51] { value: 1 } - } - } - } - } - } - result: { - IDENT [52] { - name: @x:2 - } - } - } + CONSTANT [7] { value: 1 } } } } - } - } - } - CALL [53] { - function: size - args: { - LIST [54] { - elements: { - COMPREHENSION [55] { - iter_var: @c:3 - iter_range: { - IDENT [56] { - name: @index1 - } - } - accu_var: @x:3 - accu_init: { - CONSTANT [57] { value: false } - } - loop_condition: { - CALL [58] { - function: @not_strictly_false + accu_var: @ac:0:0 + accu_init: { + CONSTANT [8] { value: false } + } + loop_condition: { + CALL [9] { + function: @not_strictly_false + args: { + CALL [10] { + function: !_ args: { - CALL [59] { - function: !_ - args: { - IDENT [60] { - name: @x:3 - } - } + IDENT [11] { + name: @ac:0:0 } } } } - loop_step: { - CALL [61] { - function: _||_ - args: { - IDENT [62] { - name: @x:3 - } - CALL [63] { - function: _>_ - args: { - IDENT [64] { - name: @c:3 - } - CONSTANT [65] { value: 1 } - } - } - } - } - } - result: { - IDENT [66] { - name: @x:3 - } - } } } - } - } - } - } - } - CONSTANT [67] { value: 4 } - } - } - } -} -Test case: MULTIPLE_MACROS_2 -Source: [[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == 'a')] + [['a'].exists(l, l == 'a')] == [true, true, true, true] -=====> -CALL [1] { - function: cel.@block - args: { - LIST [2] { - elements: { - LIST [3] { - elements: { - CONSTANT [4] { value: 1 } - } - } - LIST [5] { - elements: { - CONSTANT [6] { value: "a" } - } - } - } - } - CALL [7] { - function: _==_ - args: { - CALL [8] { - function: _+_ - args: { - CALL [9] { - function: _+_ - args: { - CALL [10] { - function: _+_ - args: { - LIST [11] { - elements: { - COMPREHENSION [12] { - iter_var: @c:0 - iter_range: { - IDENT [13] { - name: @index0 - } - } - accu_var: @x:0 - accu_init: { - CONSTANT [14] { value: false } - } - loop_condition: { - CALL [15] { - function: @not_strictly_false - args: { - CALL [16] { - function: !_ - args: { - IDENT [17] { - name: @x:0 - } - } - } - } - } - } - loop_step: { - CALL [18] { - function: _||_ - args: { - IDENT [19] { - name: @x:0 - } - CALL [20] { - function: _>_ - args: { - IDENT [21] { - name: @c:0 - } - CONSTANT [22] { value: 0 } - } - } - } - } - } - result: { - IDENT [23] { - name: @x:0 - } - } + loop_step: { + CALL [12] { + function: _||_ + args: { + IDENT [13] { + name: @ac:0:0 } - } - } - LIST [24] { - elements: { - COMPREHENSION [25] { - iter_var: @c:1 - iter_range: { - IDENT [26] { - name: @index0 - } - } - accu_var: @x:1 - accu_init: { - CONSTANT [27] { value: false } - } - loop_condition: { - CALL [28] { - function: @not_strictly_false - args: { - CALL [29] { - function: !_ - args: { - IDENT [30] { - name: @x:1 - } - } - } - } - } - } - loop_step: { - CALL [31] { - function: _||_ - args: { - IDENT [32] { - name: @x:1 - } - CALL [33] { - function: _>_ - args: { - IDENT [34] { - name: @c:1 - } - CONSTANT [35] { value: 0 } - } - } - } - } - } - result: { - IDENT [36] { - name: @x:1 + CALL [14] { + function: _>_ + args: { + IDENT [15] { + name: @it:0:0 } + CONSTANT [16] { value: 0 } } } } } } - } - LIST [37] { - elements: { - COMPREHENSION [38] { - iter_var: @c:2 - iter_range: { - IDENT [39] { - name: @index1 - } - } - accu_var: @x:2 - accu_init: { - CONSTANT [40] { value: false } - } - loop_condition: { - CALL [41] { - function: @not_strictly_false - args: { - CALL [42] { - function: !_ - args: { - IDENT [43] { - name: @x:2 - } - } - } - } - } - } - loop_step: { - CALL [44] { - function: _||_ - args: { - IDENT [45] { - name: @x:2 - } - CALL [46] { - function: _==_ - args: { - IDENT [47] { - name: @c:2 - } - CONSTANT [48] { value: "a" } - } - } - } - } - } - result: { - IDENT [49] { - name: @x:2 - } - } + result: { + IDENT [17] { + name: @ac:0:0 } } } } } - LIST [50] { + } + } + CALL [18] { + function: size + args: { + LIST [19] { elements: { - COMPREHENSION [51] { - iter_var: @c:3 + COMPREHENSION [20] { + iter_var: @it:0:0 iter_range: { - IDENT [52] { - name: @index1 + LIST [21] { + elements: { + CONSTANT [22] { value: 2 } + } } } - accu_var: @x:3 + accu_var: @ac:0:0 accu_init: { - CONSTANT [53] { value: false } + CONSTANT [23] { value: false } } loop_condition: { - CALL [54] { + CALL [24] { function: @not_strictly_false args: { - CALL [55] { + CALL [25] { function: !_ args: { - IDENT [56] { - name: @x:3 + IDENT [26] { + name: @ac:0:0 } } } @@ -1635,27 +1226,27 @@ CALL [1] { } } loop_step: { - CALL [57] { + CALL [27] { function: _||_ args: { - IDENT [58] { - name: @x:3 + IDENT [28] { + name: @ac:0:0 } - CALL [59] { - function: _==_ + CALL [29] { + function: _>_ args: { - IDENT [60] { - name: @c:3 + IDENT [30] { + name: @it:0:0 } - CONSTANT [61] { value: "a" } + CONSTANT [31] { value: 1 } } } } } } result: { - IDENT [62] { - name: @x:3 + IDENT [32] { + name: @ac:0:0 } } } @@ -1663,20 +1254,45 @@ CALL [1] { } } } - LIST [63] { - elements: { - CONSTANT [64] { value: true } - CONSTANT [65] { value: true } - CONSTANT [66] { value: true } - CONSTANT [67] { value: true } + } + } + CALL [33] { + function: _==_ + args: { + CALL [34] { + function: _+_ + args: { + CALL [35] { + function: _+_ + args: { + CALL [36] { + function: _+_ + args: { + IDENT [37] { + name: @index0 + } + IDENT [38] { + name: @index0 + } + } + } + IDENT [39] { + name: @index1 + } + } + } + IDENT [40] { + name: @index1 + } } } + CONSTANT [41] { value: 4 } } } } } -Test case: MULTIPLE_MACROS_3 -Source: [1].exists(i, i > 0) && [1].exists(j, j > 0) && [1].exists(k, k > 1) && [2].exists(l, l > 1) +Test case: MULTIPLE_MACROS_2 +Source: [[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == 'a')] + [['a'].exists(l, l == 'a')] == [true, true, true, true] =====> CALL [1] { function: cel.@block @@ -1685,37 +1301,28 @@ CALL [1] { elements: { LIST [3] { elements: { - CONSTANT [4] { value: 1 } - } - } - } - } - CALL [5] { - function: _&&_ - args: { - CALL [6] { - function: _&&_ - args: { - COMPREHENSION [7] { - iter_var: @c:0 - iter_range: { - IDENT [8] { - name: @index0 + COMPREHENSION [4] { + iter_var: @it:0:0 + iter_range: { + LIST [5] { + elements: { + CONSTANT [6] { value: 1 } + } } } - accu_var: @x:0 + accu_var: @ac:0:0 accu_init: { - CONSTANT [9] { value: false } + CONSTANT [7] { value: false } } loop_condition: { - CALL [10] { + CALL [8] { function: @not_strictly_false args: { - CALL [11] { + CALL [9] { function: !_ args: { - IDENT [12] { - name: @x:0 + IDENT [10] { + name: @ac:0:0 } } } @@ -1723,38 +1330,44 @@ CALL [1] { } } loop_step: { - CALL [13] { + CALL [11] { function: _||_ args: { - IDENT [14] { - name: @x:0 + IDENT [12] { + name: @ac:0:0 } - CALL [15] { + CALL [13] { function: _>_ args: { - IDENT [16] { - name: @c:0 + IDENT [14] { + name: @it:0:0 } - CONSTANT [17] { value: 0 } + CONSTANT [15] { value: 0 } } } } } } result: { - IDENT [18] { - name: @x:0 + IDENT [16] { + name: @ac:0:0 } } } - COMPREHENSION [19] { - iter_var: @c:1 + } + } + LIST [17] { + elements: { + COMPREHENSION [18] { + iter_var: @it:0:1 iter_range: { - IDENT [20] { - name: @index0 + LIST [19] { + elements: { + CONSTANT [20] { value: "a" } + } } } - accu_var: @x:1 + accu_var: @ac:0:1 accu_init: { CONSTANT [21] { value: false } } @@ -1766,7 +1379,7 @@ CALL [1] { function: !_ args: { IDENT [24] { - name: @x:1 + name: @ac:0:1 } } } @@ -1778,15 +1391,15 @@ CALL [1] { function: _||_ args: { IDENT [26] { - name: @x:1 + name: @ac:0:1 } CALL [27] { - function: _>_ + function: _==_ args: { IDENT [28] { - name: @c:1 + name: @it:0:1 } - CONSTANT [29] { value: 0 } + CONSTANT [29] { value: "a" } } } } @@ -1794,35 +1407,175 @@ CALL [1] { } result: { IDENT [30] { - name: @x:1 + name: @ac:0:1 + } + } + } + } + } + } + } + CALL [31] { + function: _==_ + args: { + CALL [32] { + function: _+_ + args: { + CALL [33] { + function: _+_ + args: { + CALL [34] { + function: _+_ + args: { + IDENT [35] { + name: @index0 + } + IDENT [36] { + name: @index0 + } + } + } + IDENT [37] { + name: @index1 + } + } + } + IDENT [38] { + name: @index1 + } + } + } + LIST [39] { + elements: { + CONSTANT [40] { value: true } + CONSTANT [41] { value: true } + CONSTANT [42] { value: true } + CONSTANT [43] { value: true } + } + } + } + } + } +} +Test case: MULTIPLE_MACROS_3 +Source: [1].exists(i, i > 0) && [1].exists(j, j > 0) && [1].exists(k, k > 1) && [2].exists(l, l > 1) +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + COMPREHENSION [3] { + iter_var: @it:0:0 + iter_range: { + LIST [4] { + elements: { + CONSTANT [5] { value: 1 } + } + } + } + accu_var: @ac:0:0 + accu_init: { + CONSTANT [6] { value: false } + } + loop_condition: { + CALL [7] { + function: @not_strictly_false + args: { + CALL [8] { + function: !_ + args: { + IDENT [9] { + name: @ac:0:0 + } + } + } + } + } + } + loop_step: { + CALL [10] { + function: _||_ + args: { + IDENT [11] { + name: @ac:0:0 + } + CALL [12] { + function: _>_ + args: { + IDENT [13] { + name: @it:0:0 + } + CONSTANT [14] { value: 0 } + } + } + } + } + } + result: { + IDENT [15] { + name: @ac:0:0 + } + } + } + CALL [16] { + function: _||_ + args: { + IDENT [17] { + name: @ac:0:0 + } + CALL [18] { + function: _>_ + args: { + IDENT [19] { + name: @it:0:0 } + CONSTANT [20] { value: 1 } } } } } - CALL [31] { + } + } + CALL [21] { + function: _&&_ + args: { + CALL [22] { + function: _&&_ + args: { + IDENT [23] { + name: @index0 + } + IDENT [24] { + name: @index0 + } + } + } + CALL [25] { function: _&&_ args: { - COMPREHENSION [32] { - iter_var: @c:2 + COMPREHENSION [26] { + iter_var: @it:0:0 iter_range: { - IDENT [33] { - name: @index0 + LIST [27] { + elements: { + CONSTANT [28] { value: 1 } + } } } - accu_var: @x:2 + accu_var: @ac:0:0 accu_init: { - CONSTANT [34] { value: false } + CONSTANT [29] { value: false } } loop_condition: { - CALL [35] { + CALL [30] { function: @not_strictly_false args: { - CALL [36] { + CALL [31] { function: !_ args: { - IDENT [37] { - name: @x:2 + IDENT [32] { + name: @ac:0:0 } } } @@ -1830,52 +1583,38 @@ CALL [1] { } } loop_step: { - CALL [38] { - function: _||_ - args: { - IDENT [39] { - name: @x:2 - } - CALL [40] { - function: _>_ - args: { - IDENT [41] { - name: @c:2 - } - CONSTANT [42] { value: 1 } - } - } - } + IDENT [33] { + name: @index1 } } result: { - IDENT [43] { - name: @x:2 + IDENT [34] { + name: @ac:0:0 } } } - COMPREHENSION [44] { - iter_var: @c:3 + COMPREHENSION [35] { + iter_var: @it:0:0 iter_range: { - LIST [45] { + LIST [36] { elements: { - CONSTANT [46] { value: 2 } + CONSTANT [37] { value: 2 } } } } - accu_var: @x:3 + accu_var: @ac:0:0 accu_init: { - CONSTANT [47] { value: false } + CONSTANT [38] { value: false } } loop_condition: { - CALL [48] { + CALL [39] { function: @not_strictly_false args: { - CALL [49] { + CALL [40] { function: !_ args: { - IDENT [50] { - name: @x:3 + IDENT [41] { + name: @ac:0:0 } } } @@ -1883,27 +1622,13 @@ CALL [1] { } } loop_step: { - CALL [51] { - function: _||_ - args: { - IDENT [52] { - name: @x:3 - } - CALL [53] { - function: _>_ - args: { - IDENT [54] { - name: @c:3 - } - CONSTANT [55] { value: 1 } - } - } - } + IDENT [42] { + name: @index1 } } result: { - IDENT [56] { - name: @x:3 + IDENT [43] { + name: @ac:0:0 } } } @@ -1941,13 +1666,13 @@ CALL [1] { function: _==_ args: { COMPREHENSION [12] { - iter_var: @c:1 + iter_var: @it:0:0 iter_range: { IDENT [13] { name: @index0 } } - accu_var: @x:1 + accu_var: @ac:0:0 accu_init: { LIST [14] { elements: { @@ -1962,18 +1687,18 @@ CALL [1] { function: _+_ args: { IDENT [17] { - name: @x:1 + name: @ac:0:0 } LIST [18] { elements: { COMPREHENSION [19] { - iter_var: @c:0 + iter_var: @it:1:0 iter_range: { IDENT [20] { name: @index0 } } - accu_var: @x:0 + accu_var: @ac:1:0 accu_init: { LIST [21] { elements: { @@ -1988,7 +1713,7 @@ CALL [1] { function: _+_ args: { IDENT [24] { - name: @x:0 + name: @ac:1:0 } LIST [25] { elements: { @@ -1996,7 +1721,7 @@ CALL [1] { function: _+_ args: { IDENT [27] { - name: @c:0 + name: @it:1:0 } CONSTANT [28] { value: 1 } } @@ -2008,7 +1733,7 @@ CALL [1] { } result: { IDENT [29] { - name: @x:0 + name: @ac:1:0 } } } @@ -2019,7 +1744,7 @@ CALL [1] { } result: { IDENT [30] { - name: @x:1 + name: @ac:0:0 } } } @@ -2047,7 +1772,7 @@ CALL [31] { function: _==_ args: { COMPREHENSION [30] { - iter_var: @c:1 + iter_var: @it:0:0 iter_range: { LIST [1] { elements: { @@ -2056,7 +1781,7 @@ CALL [31] { } } } - accu_var: @x:1 + accu_var: @ac:0:0 accu_init: { LIST [24] { elements: { @@ -2071,12 +1796,12 @@ CALL [31] { function: _+_ args: { IDENT [26] { - name: @x:1 + name: @ac:0:0 } LIST [27] { elements: { COMPREHENSION [23] { - iter_var: @c:0 + iter_var: @it:1:0 iter_range: { LIST [6] { elements: { @@ -2086,7 +1811,7 @@ CALL [31] { } } } - accu_var: @x:0 + accu_var: @ac:1:0 accu_init: { LIST [15] { elements: { @@ -2104,10 +1829,10 @@ CALL [31] { function: _==_ args: { IDENT [12] { - name: @c:0 + name: @it:1:0 } IDENT [14] { - name: @c:1 + name: @it:0:0 } } } @@ -2115,26 +1840,26 @@ CALL [31] { function: _+_ args: { IDENT [17] { - name: @x:0 + name: @ac:1:0 } LIST [18] { elements: { IDENT [11] { - name: @c:0 + name: @it:1:0 } } } } } IDENT [20] { - name: @x:0 + name: @ac:1:0 } } } } result: { IDENT [22] { - name: @x:0 + name: @ac:1:0 } } } @@ -2145,7 +1870,7 @@ CALL [31] { } result: { IDENT [29] { - name: @x:1 + name: @ac:0:0 } } } @@ -2173,160 +1898,73 @@ CALL [1] { args: { LIST [2] { elements: { - LIST [3] { - elements: { - CONSTANT [4] { value: 1 } - CONSTANT [5] { value: 2 } - CONSTANT [6] { value: 3 } - } - } - } - } - CALL [7] { - function: _==_ - args: { - COMPREHENSION [8] { - iter_var: @c:1 + COMPREHENSION [3] { + iter_var: @it:0:0 iter_range: { - IDENT [9] { - name: @index0 - } - } - accu_var: @x:1 - accu_init: { - LIST [10] { + LIST [4] { elements: { + CONSTANT [5] { value: 1 } + CONSTANT [6] { value: 2 } + CONSTANT [7] { value: 3 } } } } - loop_condition: { - CONSTANT [11] { value: true } - } - loop_step: { - CALL [12] { - function: _+_ - args: { - IDENT [13] { - name: @x:1 - } - LIST [14] { - elements: { - COMPREHENSION [15] { - iter_var: @c:0 - iter_range: { - IDENT [16] { - name: @index0 - } - } - accu_var: @x:0 - accu_init: { - LIST [17] { - elements: { - } - } - } - loop_condition: { - CONSTANT [18] { value: true } - } - loop_step: { - CALL [19] { - function: _+_ - args: { - IDENT [20] { - name: @x:0 - } - LIST [21] { - elements: { - CALL [22] { - function: _+_ - args: { - IDENT [23] { - name: @c:0 - } - CONSTANT [24] { value: 1 } - } - } - } - } - } - } - } - result: { - IDENT [25] { - name: @x:0 - } - } - } - } - } - } - } - } - result: { - IDENT [26] { - name: @x:1 - } - } - } - COMPREHENSION [27] { - iter_var: @c:3 - iter_range: { - IDENT [28] { - name: @index0 - } - } - accu_var: @x:3 + accu_var: @ac:0:0 accu_init: { - LIST [29] { + LIST [8] { elements: { } } } loop_condition: { - CONSTANT [30] { value: true } + CONSTANT [9] { value: true } } loop_step: { - CALL [31] { + CALL [10] { function: _+_ args: { - IDENT [32] { - name: @x:3 + IDENT [11] { + name: @ac:0:0 } - LIST [33] { + LIST [12] { elements: { - COMPREHENSION [34] { - iter_var: @c:2 + COMPREHENSION [13] { + iter_var: @it:1:0 iter_range: { - IDENT [35] { - name: @index0 + LIST [14] { + elements: { + CONSTANT [15] { value: 1 } + CONSTANT [16] { value: 2 } + CONSTANT [17] { value: 3 } + } } } - accu_var: @x:2 + accu_var: @ac:1:0 accu_init: { - LIST [36] { + LIST [18] { elements: { } } } loop_condition: { - CONSTANT [37] { value: true } + CONSTANT [19] { value: true } } loop_step: { - CALL [38] { + CALL [20] { function: _+_ args: { - IDENT [39] { - name: @x:2 + IDENT [21] { + name: @ac:1:0 } - LIST [40] { + LIST [22] { elements: { - CALL [41] { + CALL [23] { function: _+_ args: { - IDENT [42] { - name: @c:2 + IDENT [24] { + name: @it:1:0 } - CONSTANT [43] { value: 1 } + CONSTANT [25] { value: 1 } } } } @@ -2335,8 +1973,8 @@ CALL [1] { } } result: { - IDENT [44] { - name: @x:2 + IDENT [26] { + name: @ac:1:0 } } } @@ -2346,13 +1984,24 @@ CALL [1] { } } result: { - IDENT [45] { - name: @x:3 + IDENT [27] { + name: @ac:0:0 } } } } } + CALL [28] { + function: _==_ + args: { + IDENT [29] { + name: @index0 + } + IDENT [30] { + name: @index0 + } + } + } } } Test case: INCLUSION_LIST @@ -2525,13 +2174,13 @@ CALL [1] { function: _==_ args: { COMPREHENSION [14] { - iter_var: @c:1 + iter_var: @it:0:0 iter_range: { IDENT [15] { name: @index1 } } - accu_var: @x:1 + accu_var: @ac:0:0 accu_init: { LIST [16] { elements: { @@ -2546,18 +2195,18 @@ CALL [1] { function: _+_ args: { IDENT [19] { - name: @x:1 + name: @ac:0:0 } LIST [20] { elements: { COMPREHENSION [21] { - iter_var: @c:0 + iter_var: @it:1:0 iter_range: { IDENT [22] { name: @index1 } } - accu_var: @x:0 + accu_var: @ac:1:0 accu_init: { LIST [23] { elements: { @@ -2572,7 +2221,7 @@ CALL [1] { function: _+_ args: { IDENT [26] { - name: @x:0 + name: @ac:1:0 } LIST [27] { elements: { @@ -2589,7 +2238,7 @@ CALL [1] { } result: { IDENT [31] { - name: @x:0 + name: @ac:1:0 } } } @@ -2600,7 +2249,7 @@ CALL [1] { } result: { IDENT [32] { - name: @x:1 + name: @ac:0:0 } } } @@ -2647,7 +2296,7 @@ CALL [1] { function: _||_ args: { COMPREHENSION [9] { - iter_var: @c:0 + iter_var: @it:0:0 iter_range: { LIST [10] { elements: { @@ -2672,7 +2321,7 @@ CALL [1] { } } } - accu_var: @x:0 + accu_var: @ac:0:0 accu_init: { CONSTANT [17] { value: false } } @@ -2684,7 +2333,7 @@ CALL [1] { function: !_ args: { IDENT [20] { - name: @x:0 + name: @ac:0:0 } } } @@ -2696,7 +2345,7 @@ CALL [1] { function: _||_ args: { IDENT [22] { - name: @x:0 + name: @ac:0:0 } CALL [23] { function: _>_ @@ -2705,7 +2354,7 @@ CALL [1] { function: _-_ args: { IDENT [25] { - name: @c:0 + name: @it:0:0 } CONSTANT [26] { value: 1 } } @@ -2718,7 +2367,7 @@ CALL [1] { } result: { IDENT [28] { - name: @x:0 + name: @ac:0:0 } } } @@ -2741,10 +2390,10 @@ CALL [1] { function: _+_ args: { IDENT [4] { - name: @c:0 + name: @it:1:0 } IDENT [5] { - name: @c:0 + name: @it:1:0 } } } @@ -2752,20 +2401,20 @@ CALL [1] { function: _+_ args: { IDENT [7] { - name: @c:1 + name: @it:0:0 } IDENT [8] { - name: @c:1 + name: @it:0:0 } } } } } COMPREHENSION [9] { - iter_var: @c:1 + iter_var: @it:0:0 iter_range: { COMPREHENSION [10] { - iter_var: @c:0 + iter_var: @it:1:0 iter_range: { LIST [11] { elements: { @@ -2774,7 +2423,7 @@ CALL [1] { } } } - accu_var: @x:0 + accu_var: @ac:1:0 accu_init: { LIST [14] { elements: { @@ -2789,7 +2438,7 @@ CALL [1] { function: _+_ args: { IDENT [17] { - name: @x:0 + name: @ac:1:0 } LIST [18] { elements: { @@ -2810,12 +2459,12 @@ CALL [1] { } result: { IDENT [22] { - name: @x:0 + name: @ac:1:0 } } } } - accu_var: @x:1 + accu_var: @ac:0:0 accu_init: { LIST [23] { elements: { @@ -2830,7 +2479,7 @@ CALL [1] { function: _+_ args: { IDENT [26] { - name: @x:1 + name: @ac:0:0 } LIST [27] { elements: { @@ -2851,7 +2500,7 @@ CALL [1] { } result: { IDENT [31] { - name: @x:1 + name: @ac:0:0 } } } diff --git a/optimizer/src/test/resources/subexpression_ast_cascaded_binds.baseline b/optimizer/src/test/resources/subexpression_ast_cascaded_binds.baseline index 14ec4f9e6..bb02cd934 100644 --- a/optimizer/src/test/resources/subexpression_ast_cascaded_binds.baseline +++ b/optimizer/src/test/resources/subexpression_ast_cascaded_binds.baseline @@ -1607,13 +1607,13 @@ CALL [1] { LIST [18] { elements: { COMPREHENSION [19] { - iter_var: @c:0 + iter_var: @it:0 iter_range: { IDENT [20] { name: @r0 } } - accu_var: @x:0 + accu_var: @ac:0 accu_init: { CONSTANT [21] { value: false } } @@ -1625,7 +1625,7 @@ CALL [1] { function: !_ args: { IDENT [24] { - name: @x:0 + name: @ac:0 } } } @@ -1637,13 +1637,13 @@ CALL [1] { function: _||_ args: { IDENT [26] { - name: @x:0 + name: @ac:0 } CALL [27] { function: _>_ args: { IDENT [28] { - name: @c:0 + name: @it:0 } CONSTANT [29] { value: 0 } } @@ -1653,7 +1653,7 @@ CALL [1] { } result: { IDENT [30] { - name: @x:0 + name: @ac:0 } } } @@ -1667,13 +1667,13 @@ CALL [1] { LIST [32] { elements: { COMPREHENSION [33] { - iter_var: @c:1 + iter_var: @it:1 iter_range: { IDENT [34] { name: @r0 } } - accu_var: @x:1 + accu_var: @ac:1 accu_init: { CONSTANT [35] { value: false } } @@ -1685,7 +1685,7 @@ CALL [1] { function: !_ args: { IDENT [38] { - name: @x:1 + name: @ac:1 } } } @@ -1697,13 +1697,13 @@ CALL [1] { function: _||_ args: { IDENT [40] { - name: @x:1 + name: @ac:1 } CALL [41] { function: _>_ args: { IDENT [42] { - name: @c:1 + name: @it:1 } CONSTANT [43] { value: 0 } } @@ -1713,7 +1713,7 @@ CALL [1] { } result: { IDENT [44] { - name: @x:1 + name: @ac:1 } } } @@ -1731,13 +1731,13 @@ CALL [1] { LIST [46] { elements: { COMPREHENSION [47] { - iter_var: @c:2 + iter_var: @it:2 iter_range: { IDENT [48] { name: @r1 } } - accu_var: @x:2 + accu_var: @ac:2 accu_init: { CONSTANT [49] { value: false } } @@ -1749,7 +1749,7 @@ CALL [1] { function: !_ args: { IDENT [52] { - name: @x:2 + name: @ac:2 } } } @@ -1761,13 +1761,13 @@ CALL [1] { function: _||_ args: { IDENT [54] { - name: @x:2 + name: @ac:2 } CALL [55] { function: _>_ args: { IDENT [56] { - name: @c:2 + name: @it:2 } CONSTANT [57] { value: 1 } } @@ -1777,7 +1777,7 @@ CALL [1] { } result: { IDENT [58] { - name: @x:2 + name: @ac:2 } } } @@ -1793,13 +1793,13 @@ CALL [1] { LIST [60] { elements: { COMPREHENSION [61] { - iter_var: @c:3 + iter_var: @it:3 iter_range: { IDENT [62] { name: @r1 } } - accu_var: @x:3 + accu_var: @ac:3 accu_init: { CONSTANT [63] { value: false } } @@ -1811,7 +1811,7 @@ CALL [1] { function: !_ args: { IDENT [66] { - name: @x:3 + name: @ac:3 } } } @@ -1823,13 +1823,13 @@ CALL [1] { function: _||_ args: { IDENT [68] { - name: @x:3 + name: @ac:3 } CALL [69] { function: _>_ args: { IDENT [70] { - name: @c:3 + name: @it:3 } CONSTANT [71] { value: 1 } } @@ -1839,7 +1839,7 @@ CALL [1] { } result: { IDENT [72] { - name: @x:3 + name: @ac:3 } } } @@ -1922,13 +1922,13 @@ CALL [1] { LIST [17] { elements: { COMPREHENSION [18] { - iter_var: @c:0 + iter_var: @it:0 iter_range: { IDENT [19] { name: @r0 } } - accu_var: @x:0 + accu_var: @ac:0 accu_init: { CONSTANT [20] { value: false } } @@ -1940,7 +1940,7 @@ CALL [1] { function: !_ args: { IDENT [23] { - name: @x:0 + name: @ac:0 } } } @@ -1952,13 +1952,13 @@ CALL [1] { function: _||_ args: { IDENT [25] { - name: @x:0 + name: @ac:0 } CALL [26] { function: _>_ args: { IDENT [27] { - name: @c:0 + name: @it:0 } CONSTANT [28] { value: 0 } } @@ -1968,7 +1968,7 @@ CALL [1] { } result: { IDENT [29] { - name: @x:0 + name: @ac:0 } } } @@ -1977,13 +1977,13 @@ CALL [1] { LIST [30] { elements: { COMPREHENSION [31] { - iter_var: @c:1 + iter_var: @it:1 iter_range: { IDENT [32] { name: @r0 } } - accu_var: @x:1 + accu_var: @ac:1 accu_init: { CONSTANT [33] { value: false } } @@ -1995,7 +1995,7 @@ CALL [1] { function: !_ args: { IDENT [36] { - name: @x:1 + name: @ac:1 } } } @@ -2007,13 +2007,13 @@ CALL [1] { function: _||_ args: { IDENT [38] { - name: @x:1 + name: @ac:1 } CALL [39] { function: _>_ args: { IDENT [40] { - name: @c:1 + name: @it:1 } CONSTANT [41] { value: 0 } } @@ -2023,7 +2023,7 @@ CALL [1] { } result: { IDENT [42] { - name: @x:1 + name: @ac:1 } } } @@ -2036,13 +2036,13 @@ CALL [1] { LIST [43] { elements: { COMPREHENSION [44] { - iter_var: @c:2 + iter_var: @it:2 iter_range: { IDENT [45] { name: @r1 } } - accu_var: @x:2 + accu_var: @ac:2 accu_init: { CONSTANT [46] { value: false } } @@ -2054,7 +2054,7 @@ CALL [1] { function: !_ args: { IDENT [49] { - name: @x:2 + name: @ac:2 } } } @@ -2066,13 +2066,13 @@ CALL [1] { function: _||_ args: { IDENT [51] { - name: @x:2 + name: @ac:2 } CALL [52] { function: _==_ args: { IDENT [53] { - name: @c:2 + name: @it:2 } CONSTANT [54] { value: "a" } } @@ -2082,7 +2082,7 @@ CALL [1] { } result: { IDENT [55] { - name: @x:2 + name: @ac:2 } } } @@ -2093,13 +2093,13 @@ CALL [1] { LIST [56] { elements: { COMPREHENSION [57] { - iter_var: @c:3 + iter_var: @it:3 iter_range: { IDENT [58] { name: @r1 } } - accu_var: @x:3 + accu_var: @ac:3 accu_init: { CONSTANT [59] { value: false } } @@ -2111,7 +2111,7 @@ CALL [1] { function: !_ args: { IDENT [62] { - name: @x:3 + name: @ac:3 } } } @@ -2123,13 +2123,13 @@ CALL [1] { function: _||_ args: { IDENT [64] { - name: @x:3 + name: @ac:3 } CALL [65] { function: _==_ args: { IDENT [66] { - name: @c:3 + name: @it:3 } CONSTANT [67] { value: "a" } } @@ -2139,7 +2139,7 @@ CALL [1] { } result: { IDENT [68] { - name: @x:3 + name: @ac:3 } } } @@ -2194,13 +2194,13 @@ COMPREHENSION [1] { function: _&&_ args: { COMPREHENSION [9] { - iter_var: @c:0 + iter_var: @it:0 iter_range: { IDENT [10] { name: @r0 } } - accu_var: @x:0 + accu_var: @ac:0 accu_init: { CONSTANT [11] { value: false } } @@ -2212,7 +2212,7 @@ COMPREHENSION [1] { function: !_ args: { IDENT [14] { - name: @x:0 + name: @ac:0 } } } @@ -2224,13 +2224,13 @@ COMPREHENSION [1] { function: _||_ args: { IDENT [16] { - name: @x:0 + name: @ac:0 } CALL [17] { function: _>_ args: { IDENT [18] { - name: @c:0 + name: @it:0 } CONSTANT [19] { value: 0 } } @@ -2240,18 +2240,18 @@ COMPREHENSION [1] { } result: { IDENT [20] { - name: @x:0 + name: @ac:0 } } } COMPREHENSION [21] { - iter_var: @c:1 + iter_var: @it:1 iter_range: { IDENT [22] { name: @r0 } } - accu_var: @x:1 + accu_var: @ac:1 accu_init: { CONSTANT [23] { value: false } } @@ -2263,7 +2263,7 @@ COMPREHENSION [1] { function: !_ args: { IDENT [26] { - name: @x:1 + name: @ac:1 } } } @@ -2275,13 +2275,13 @@ COMPREHENSION [1] { function: _||_ args: { IDENT [28] { - name: @x:1 + name: @ac:1 } CALL [29] { function: _>_ args: { IDENT [30] { - name: @c:1 + name: @it:1 } CONSTANT [31] { value: 0 } } @@ -2291,7 +2291,7 @@ COMPREHENSION [1] { } result: { IDENT [32] { - name: @x:1 + name: @ac:1 } } } @@ -2301,13 +2301,13 @@ COMPREHENSION [1] { function: _&&_ args: { COMPREHENSION [34] { - iter_var: @c:2 + iter_var: @it:2 iter_range: { IDENT [35] { name: @r0 } } - accu_var: @x:2 + accu_var: @ac:2 accu_init: { CONSTANT [36] { value: false } } @@ -2319,7 +2319,7 @@ COMPREHENSION [1] { function: !_ args: { IDENT [39] { - name: @x:2 + name: @ac:2 } } } @@ -2331,13 +2331,13 @@ COMPREHENSION [1] { function: _||_ args: { IDENT [41] { - name: @x:2 + name: @ac:2 } CALL [42] { function: _>_ args: { IDENT [43] { - name: @c:2 + name: @it:2 } CONSTANT [44] { value: 1 } } @@ -2347,12 +2347,12 @@ COMPREHENSION [1] { } result: { IDENT [45] { - name: @x:2 + name: @ac:2 } } } COMPREHENSION [46] { - iter_var: @c:3 + iter_var: @it:3 iter_range: { LIST [47] { elements: { @@ -2360,7 +2360,7 @@ COMPREHENSION [1] { } } } - accu_var: @x:3 + accu_var: @ac:3 accu_init: { CONSTANT [49] { value: false } } @@ -2372,7 +2372,7 @@ COMPREHENSION [1] { function: !_ args: { IDENT [52] { - name: @x:3 + name: @ac:3 } } } @@ -2384,13 +2384,13 @@ COMPREHENSION [1] { function: _||_ args: { IDENT [54] { - name: @x:3 + name: @ac:3 } CALL [55] { function: _>_ args: { IDENT [56] { - name: @c:3 + name: @it:3 } CONSTANT [57] { value: 1 } } @@ -2400,7 +2400,7 @@ COMPREHENSION [1] { } result: { IDENT [58] { - name: @x:3 + name: @ac:3 } } } @@ -2444,13 +2444,13 @@ CALL [1] { } result: { COMPREHENSION [10] { - iter_var: @c:1 + iter_var: @it:1 iter_range: { IDENT [11] { name: @r0 } } - accu_var: @x:1 + accu_var: @ac:1 accu_init: { LIST [12] { elements: { @@ -2465,18 +2465,18 @@ CALL [1] { function: _+_ args: { IDENT [15] { - name: @x:1 + name: @ac:1 } LIST [16] { elements: { COMPREHENSION [17] { - iter_var: @c:0 + iter_var: @it:0 iter_range: { IDENT [18] { name: @r0 } } - accu_var: @x:0 + accu_var: @ac:0 accu_init: { LIST [19] { elements: { @@ -2491,7 +2491,7 @@ CALL [1] { function: _+_ args: { IDENT [22] { - name: @x:0 + name: @ac:0 } LIST [23] { elements: { @@ -2499,7 +2499,7 @@ CALL [1] { function: _+_ args: { IDENT [25] { - name: @c:0 + name: @it:0 } CONSTANT [26] { value: 1 } } @@ -2511,7 +2511,7 @@ CALL [1] { } result: { IDENT [27] { - name: @x:0 + name: @ac:0 } } } @@ -2522,7 +2522,7 @@ CALL [1] { } result: { IDENT [28] { - name: @x:1 + name: @ac:1 } } } @@ -2579,7 +2579,7 @@ CALL [31] { function: _==_ args: { COMPREHENSION [30] { - iter_var: @c:1 + iter_var: @it:1 iter_range: { LIST [1] { elements: { @@ -2588,7 +2588,7 @@ CALL [31] { } } } - accu_var: @x:1 + accu_var: @ac:1 accu_init: { LIST [24] { elements: { @@ -2603,12 +2603,12 @@ CALL [31] { function: _+_ args: { IDENT [26] { - name: @x:1 + name: @ac:1 } LIST [27] { elements: { COMPREHENSION [23] { - iter_var: @c:0 + iter_var: @it:0 iter_range: { LIST [6] { elements: { @@ -2618,7 +2618,7 @@ CALL [31] { } } } - accu_var: @x:0 + accu_var: @ac:0 accu_init: { LIST [15] { elements: { @@ -2636,10 +2636,10 @@ CALL [31] { function: _==_ args: { IDENT [12] { - name: @c:0 + name: @it:0 } IDENT [14] { - name: @c:1 + name: @it:1 } } } @@ -2647,26 +2647,26 @@ CALL [31] { function: _+_ args: { IDENT [17] { - name: @x:0 + name: @ac:0 } LIST [18] { elements: { IDENT [11] { - name: @c:0 + name: @it:0 } } } } } IDENT [20] { - name: @x:0 + name: @ac:0 } } } } result: { IDENT [22] { - name: @x:0 + name: @ac:0 } } } @@ -2677,7 +2677,7 @@ CALL [31] { } result: { IDENT [29] { - name: @x:1 + name: @ac:1 } } } @@ -2731,13 +2731,13 @@ COMPREHENSION [1] { function: _==_ args: { COMPREHENSION [10] { - iter_var: @c:1 + iter_var: @it:1 iter_range: { IDENT [11] { name: @r0 } } - accu_var: @x:1 + accu_var: @ac:1 accu_init: { LIST [12] { elements: { @@ -2752,18 +2752,18 @@ COMPREHENSION [1] { function: _+_ args: { IDENT [15] { - name: @x:1 + name: @ac:1 } LIST [16] { elements: { COMPREHENSION [17] { - iter_var: @c:0 + iter_var: @it:0 iter_range: { IDENT [18] { name: @r0 } } - accu_var: @x:0 + accu_var: @ac:0 accu_init: { LIST [19] { elements: { @@ -2778,7 +2778,7 @@ COMPREHENSION [1] { function: _+_ args: { IDENT [22] { - name: @x:0 + name: @ac:0 } LIST [23] { elements: { @@ -2786,7 +2786,7 @@ COMPREHENSION [1] { function: _+_ args: { IDENT [25] { - name: @c:0 + name: @it:0 } CONSTANT [26] { value: 1 } } @@ -2798,7 +2798,7 @@ COMPREHENSION [1] { } result: { IDENT [27] { - name: @x:0 + name: @ac:0 } } } @@ -2809,18 +2809,18 @@ COMPREHENSION [1] { } result: { IDENT [28] { - name: @x:1 + name: @ac:1 } } } COMPREHENSION [29] { - iter_var: @c:3 + iter_var: @it:3 iter_range: { IDENT [30] { name: @r0 } } - accu_var: @x:3 + accu_var: @ac:3 accu_init: { LIST [31] { elements: { @@ -2835,18 +2835,18 @@ COMPREHENSION [1] { function: _+_ args: { IDENT [34] { - name: @x:3 + name: @ac:3 } LIST [35] { elements: { COMPREHENSION [36] { - iter_var: @c:2 + iter_var: @it:2 iter_range: { IDENT [37] { name: @r0 } } - accu_var: @x:2 + accu_var: @ac:2 accu_init: { LIST [38] { elements: { @@ -2861,7 +2861,7 @@ COMPREHENSION [1] { function: _+_ args: { IDENT [41] { - name: @x:2 + name: @ac:2 } LIST [42] { elements: { @@ -2869,7 +2869,7 @@ COMPREHENSION [1] { function: _+_ args: { IDENT [44] { - name: @c:2 + name: @it:2 } CONSTANT [45] { value: 1 } } @@ -2881,7 +2881,7 @@ COMPREHENSION [1] { } result: { IDENT [46] { - name: @x:2 + name: @ac:2 } } } @@ -2892,7 +2892,7 @@ COMPREHENSION [1] { } result: { IDENT [47] { - name: @x:3 + name: @ac:3 } } } @@ -3137,13 +3137,13 @@ COMPREHENSION [1] { } result: { COMPREHENSION [16] { - iter_var: @c:1 + iter_var: @it:1 iter_range: { IDENT [17] { name: @r0 } } - accu_var: @x:1 + accu_var: @ac:1 accu_init: { LIST [18] { elements: { @@ -3158,18 +3158,18 @@ COMPREHENSION [1] { function: _+_ args: { IDENT [21] { - name: @x:1 + name: @ac:1 } LIST [22] { elements: { COMPREHENSION [23] { - iter_var: @c:0 + iter_var: @it:0 iter_range: { IDENT [24] { name: @r0 } } - accu_var: @x:0 + accu_var: @ac:0 accu_init: { LIST [25] { elements: { @@ -3184,7 +3184,7 @@ COMPREHENSION [1] { function: _+_ args: { IDENT [28] { - name: @x:0 + name: @ac:0 } LIST [29] { elements: { @@ -3198,7 +3198,7 @@ COMPREHENSION [1] { } result: { IDENT [31] { - name: @x:0 + name: @ac:0 } } } @@ -3209,7 +3209,7 @@ COMPREHENSION [1] { } result: { IDENT [32] { - name: @x:1 + name: @ac:1 } } } @@ -3326,7 +3326,7 @@ COMPREHENSION [1] { function: _||_ args: { COMPREHENSION [16] { - iter_var: @c:0 + iter_var: @it:0 iter_range: { LIST [17] { elements: { @@ -3345,7 +3345,7 @@ COMPREHENSION [1] { } } } - accu_var: @x:0 + accu_var: @ac:0 accu_init: { CONSTANT [22] { value: false } } @@ -3357,7 +3357,7 @@ COMPREHENSION [1] { function: !_ args: { IDENT [25] { - name: @x:0 + name: @ac:0 } } } @@ -3369,7 +3369,7 @@ COMPREHENSION [1] { function: _||_ args: { IDENT [27] { - name: @x:0 + name: @ac:0 } CALL [28] { function: _>_ @@ -3378,7 +3378,7 @@ COMPREHENSION [1] { function: _-_ args: { IDENT [30] { - name: @c:0 + name: @it:0 } CONSTANT [31] { value: 1 } } @@ -3391,7 +3391,7 @@ COMPREHENSION [1] { } result: { IDENT [33] { - name: @x:0 + name: @ac:0 } } } @@ -3408,10 +3408,10 @@ Test case: MACRO_SHADOWED_VARIABLE_2 Source: ["foo", "bar"].map(x, [x + x, x + x]).map(x, [x + x, x + x]) =====> COMPREHENSION [1] { - iter_var: @c:1 + iter_var: @it:1 iter_range: { COMPREHENSION [2] { - iter_var: @c:0 + iter_var: @it:0 iter_range: { LIST [3] { elements: { @@ -3420,7 +3420,7 @@ COMPREHENSION [1] { } } } - accu_var: @x:0 + accu_var: @ac:0 accu_init: { LIST [6] { elements: { @@ -3435,7 +3435,7 @@ COMPREHENSION [1] { function: _+_ args: { IDENT [9] { - name: @x:0 + name: @ac:0 } LIST [10] { elements: { @@ -3453,10 +3453,10 @@ COMPREHENSION [1] { function: _+_ args: { IDENT [14] { - name: @c:0 + name: @it:0 } IDENT [15] { - name: @c:0 + name: @it:0 } } } @@ -3489,12 +3489,12 @@ COMPREHENSION [1] { } result: { IDENT [21] { - name: @x:0 + name: @ac:0 } } } } - accu_var: @x:1 + accu_var: @ac:1 accu_init: { LIST [22] { elements: { @@ -3509,7 +3509,7 @@ COMPREHENSION [1] { function: _+_ args: { IDENT [25] { - name: @x:1 + name: @ac:1 } LIST [26] { elements: { @@ -3527,10 +3527,10 @@ COMPREHENSION [1] { function: _+_ args: { IDENT [30] { - name: @c:1 + name: @it:1 } IDENT [31] { - name: @c:1 + name: @it:1 } } } @@ -3563,7 +3563,7 @@ COMPREHENSION [1] { } result: { IDENT [37] { - name: @x:1 + name: @ac:1 } } } diff --git a/optimizer/src/test/resources/subexpression_unparsed.baseline b/optimizer/src/test/resources/subexpression_unparsed.baseline index 9675f3b3a..781f59990 100644 --- a/optimizer/src/test/resources/subexpression_unparsed.baseline +++ b/optimizer/src/test/resources/subexpression_unparsed.baseline @@ -274,97 +274,97 @@ Test case: MULTIPLE_MACROS_1 Source: size([[1].exists(i, i > 0)]) + size([[1].exists(j, j > 0)]) + size([[2].exists(k, k > 1)]) + size([[2].exists(l, l > 1)]) == 4 =====> Result: true -[CASCADED_BINDS]: cel.bind(@r1, [2], cel.bind(@r0, [1], size([@r0.exists(@c:0, @c:0 > 0)]) + size([@r0.exists(@c:1, @c:1 > 0)])) + size([@r1.exists(@c:2, @c:2 > 1)]) + size([@r1.exists(@c:3, @c:3 > 1)])) == 4 -[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([[1], [2]], size([@index0.exists(@c:0, @c:0 > 0)]) + size([@index0.exists(@c:1, @c:1 > 0)]) + size([@index1.exists(@c:2, @c:2 > 1)]) + size([@index1.exists(@c:3, @c:3 > 1)]) == 4) -[BLOCK_RECURSION_DEPTH_1]: cel.@block([[1], [2], @c:0 > 0, @x:0 || @index2, @c:1 > 0, @x:1 || @index4, @c:2 > 1, @x:2 || @index6, @c:3 > 1, @x:3 || @index8], size([@index0.exists(@c:0, @index2)]) + size([@index0.exists(@c:1, @index4)]) + size([@index1.exists(@c:2, @index6)]) + size([@index1.exists(@c:3, @index8)]) == 4) -[BLOCK_RECURSION_DEPTH_2]: cel.@block([[1], [2], @x:0 || @c:0 > 0, @x:1 || @c:1 > 0, @x:2 || @c:2 > 1, @x:3 || @c:3 > 1], size([@index0.exists(@c:0, @c:0 > 0)]) + size([@index0.exists(@c:1, @c:1 > 0)]) + size([@index1.exists(@c:2, @c:2 > 1)]) + size([@index1.exists(@c:3, @c:3 > 1)]) == 4) -[BLOCK_RECURSION_DEPTH_3]: cel.@block([[1], [2], @index0.exists(@c:0, @c:0 > 0), @index0.exists(@c:1, @c:1 > 0), size([@index2]) + size([@index3]), @index1.exists(@c:2, @c:2 > 1), @index4 + size([@index5]), @index1.exists(@c:3, @c:3 > 1), @index6 + size([@index7])], @index8 == 4) -[BLOCK_RECURSION_DEPTH_4]: cel.@block([[1], [2], [@index0.exists(@c:0, @c:0 > 0)], [@index0.exists(@c:1, @c:1 > 0)], [@index1.exists(@c:2, @c:2 > 1)], [@index1.exists(@c:3, @c:3 > 1)], size(@index2) + size(@index3) + size(@index4) + size(@index5)], @index6 == 4) -[BLOCK_RECURSION_DEPTH_5]: cel.@block([[1], [2], size([@index0.exists(@c:0, @c:0 > 0)]), size([@index0.exists(@c:1, @c:1 > 0)]), size([@index1.exists(@c:2, @c:2 > 1)]), size([@index1.exists(@c:3, @c:3 > 1)])], @index2 + @index3 + @index4 + @index5 == 4) -[BLOCK_RECURSION_DEPTH_6]: cel.@block([[1], [2], size([@index0.exists(@c:0, @c:0 > 0)]) + size([@index0.exists(@c:1, @c:1 > 0)]), @index2 + size([@index1.exists(@c:2, @c:2 > 1)]), @index3 + size([@index1.exists(@c:3, @c:3 > 1)])], @index4 == 4) -[BLOCK_RECURSION_DEPTH_7]: cel.@block([[1], [2], size([@index0.exists(@c:0, @c:0 > 0)]) + size([@index0.exists(@c:1, @c:1 > 0)]) + size([@index1.exists(@c:2, @c:2 > 1)])], @index2 + size([@index1.exists(@c:3, @c:3 > 1)]) == 4) -[BLOCK_RECURSION_DEPTH_8]: cel.@block([[1], [2], size([@index0.exists(@c:0, @c:0 > 0)]) + size([@index0.exists(@c:1, @c:1 > 0)]) + size([@index1.exists(@c:2, @c:2 > 1)]) + size([@index1.exists(@c:3, @c:3 > 1)])], @index2 == 4) -[BLOCK_RECURSION_DEPTH_9]: cel.@block([[1], [2]], size([@index0.exists(@c:0, @c:0 > 0)]) + size([@index0.exists(@c:1, @c:1 > 0)]) + size([@index1.exists(@c:2, @c:2 > 1)]) + size([@index1.exists(@c:3, @c:3 > 1)]) == 4) +[CASCADED_BINDS]: cel.bind(@r1, [2], cel.bind(@r0, [1], size([@r0.exists(@it:0, @it:0 > 0)]) + size([@r0.exists(@it:1, @it:1 > 0)])) + size([@r1.exists(@it:2, @it:2 > 1)]) + size([@r1.exists(@it:3, @it:3 > 1)])) == 4 +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([size([[1].exists(@it:0:0, @it:0:0 > 0)]), size([[2].exists(@it:0:0, @it:0:0 > 1)])], @index0 + @index0 + @index1 + @index1 == 4) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([[1], @it:0:0 > 0, @ac:0:0 || @index1, [2], @it:0:0 > 1, @ac:0:0 || @index4], size([@index0.exists(@it:0:0, @index1)]) + size([@index0.exists(@it:0:0, @index1)]) + size([@index3.exists(@it:0:0, @index4)]) + size([@index3.exists(@it:0:0, @index4)]) == 4) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([@ac:0:0 || @it:0:0 > 0, @ac:0:0 || @it:0:0 > 1, [1], [2]], size([@index2.exists(@it:0:0, @it:0:0 > 0)]) + size([@index2.exists(@it:0:0, @it:0:0 > 0)]) + size([@index3.exists(@it:0:0, @it:0:0 > 1)]) + size([@index3.exists(@it:0:0, @it:0:0 > 1)]) == 4) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([[1].exists(@it:0:0, @it:0:0 > 0), [2].exists(@it:0:0, @it:0:0 > 1), size([@index0]), size([@index1]), @index2 + @index2 + @index3 + @index3], @index4 == 4) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([[[1].exists(@it:0:0, @it:0:0 > 0)], [[2].exists(@it:0:0, @it:0:0 > 1)], size(@index0), size(@index1)], @index2 + @index2 + @index3 + @index3 == 4) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([size([[1].exists(@it:0:0, @it:0:0 > 0)]), size([[2].exists(@it:0:0, @it:0:0 > 1)])], @index0 + @index0 + @index1 + @index1 == 4) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([size([[1].exists(@it:0:0, @it:0:0 > 0)]), size([[2].exists(@it:0:0, @it:0:0 > 1)])], @index0 + @index0 + @index1 + @index1 == 4) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([size([[1].exists(@it:0:0, @it:0:0 > 0)]), size([[2].exists(@it:0:0, @it:0:0 > 1)])], @index0 + @index0 + @index1 + @index1 == 4) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([size([[1].exists(@it:0:0, @it:0:0 > 0)]), size([[2].exists(@it:0:0, @it:0:0 > 1)])], @index0 + @index0 + @index1 + @index1 == 4) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([size([[1].exists(@it:0:0, @it:0:0 > 0)]), size([[2].exists(@it:0:0, @it:0:0 > 1)])], @index0 + @index0 + @index1 + @index1 == 4) Test case: MULTIPLE_MACROS_2 Source: [[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == 'a')] + [['a'].exists(l, l == 'a')] == [true, true, true, true] =====> Result: true -[CASCADED_BINDS]: cel.bind(@r1, ["a"], cel.bind(@r0, [1], [@r0.exists(@c:0, @c:0 > 0)] + [@r0.exists(@c:1, @c:1 > 0)]) + [@r1.exists(@c:2, @c:2 == "a")] + [@r1.exists(@c:3, @c:3 == "a")]) == [true, true, true, true] -[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([[1], ["a"]], [@index0.exists(@c:0, @c:0 > 0)] + [@index0.exists(@c:1, @c:1 > 0)] + [@index1.exists(@c:2, @c:2 == "a")] + [@index1.exists(@c:3, @c:3 == "a")] == [true, true, true, true]) -[BLOCK_RECURSION_DEPTH_1]: cel.@block([[1], ["a"], @c:0 > 0, @x:0 || @index2, @c:1 > 0, @x:1 || @index4, @c:2 == "a", @x:2 || @index6, @c:3 == "a", @x:3 || @index8, [true, true, true, true]], [@index0.exists(@c:0, @index2)] + [@index0.exists(@c:1, @index4)] + [@index1.exists(@c:2, @index6)] + [@index1.exists(@c:3, @index8)] == @index10) -[BLOCK_RECURSION_DEPTH_2]: cel.@block([[1], ["a"], @x:0 || @c:0 > 0, @x:1 || @c:1 > 0, @x:2 || @c:2 == "a", @x:3 || @c:3 == "a", [true, true, true, true]], [@index0.exists(@c:0, @c:0 > 0)] + [@index0.exists(@c:1, @c:1 > 0)] + [@index1.exists(@c:2, @c:2 == "a")] + [@index1.exists(@c:3, @c:3 == "a")] == @index6) -[BLOCK_RECURSION_DEPTH_3]: cel.@block([[1], ["a"], @index0.exists(@c:0, @c:0 > 0), @index0.exists(@c:1, @c:1 > 0), @index1.exists(@c:2, @c:2 == "a"), [@index2] + [@index3] + [@index4], @index1.exists(@c:3, @c:3 == "a")], @index5 + [@index6] == [true, true, true, true]) -[BLOCK_RECURSION_DEPTH_4]: cel.@block([[1], ["a"], [@index0.exists(@c:0, @c:0 > 0)], [@index0.exists(@c:1, @c:1 > 0)], [@index1.exists(@c:2, @c:2 == "a")], [@index1.exists(@c:3, @c:3 == "a")]], @index2 + @index3 + @index4 + @index5 == [true, true, true, true]) -[BLOCK_RECURSION_DEPTH_5]: cel.@block([[1], ["a"], [@index0.exists(@c:0, @c:0 > 0)] + [@index0.exists(@c:1, @c:1 > 0)], @index2 + [@index1.exists(@c:2, @c:2 == "a")], @index3 + [@index1.exists(@c:3, @c:3 == "a")]], @index4 == [true, true, true, true]) -[BLOCK_RECURSION_DEPTH_6]: cel.@block([[1], ["a"], [@index0.exists(@c:0, @c:0 > 0)] + [@index0.exists(@c:1, @c:1 > 0)] + [@index1.exists(@c:2, @c:2 == "a")]], @index2 + [@index1.exists(@c:3, @c:3 == "a")] == [true, true, true, true]) -[BLOCK_RECURSION_DEPTH_7]: cel.@block([[1], ["a"], [@index0.exists(@c:0, @c:0 > 0)] + [@index0.exists(@c:1, @c:1 > 0)] + [@index1.exists(@c:2, @c:2 == "a")] + [@index1.exists(@c:3, @c:3 == "a")]], @index2 == [true, true, true, true]) -[BLOCK_RECURSION_DEPTH_8]: cel.@block([[1], ["a"]], [@index0.exists(@c:0, @c:0 > 0)] + [@index0.exists(@c:1, @c:1 > 0)] + [@index1.exists(@c:2, @c:2 == "a")] + [@index1.exists(@c:3, @c:3 == "a")] == [true, true, true, true]) -[BLOCK_RECURSION_DEPTH_9]: cel.@block([[1], ["a"]], [@index0.exists(@c:0, @c:0 > 0)] + [@index0.exists(@c:1, @c:1 > 0)] + [@index1.exists(@c:2, @c:2 == "a")] + [@index1.exists(@c:3, @c:3 == "a")] == [true, true, true, true]) +[CASCADED_BINDS]: cel.bind(@r1, ["a"], cel.bind(@r0, [1], [@r0.exists(@it:0, @it:0 > 0)] + [@r0.exists(@it:1, @it:1 > 0)]) + [@r1.exists(@it:2, @it:2 == "a")] + [@r1.exists(@it:3, @it:3 == "a")]) == [true, true, true, true] +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([[[1].exists(@it:0:0, @it:0:0 > 0)], [["a"].exists(@it:0:1, @it:0:1 == "a")]], @index0 + @index0 + @index1 + @index1 == [true, true, true, true]) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([[1], @it:0:0 > 0, @ac:0:0 || @index1, ["a"], @it:0:1 == "a", @ac:0:1 || @index4, [true, true, true, true]], [@index0.exists(@it:0:0, @index1)] + [@index0.exists(@it:0:0, @index1)] + [@index3.exists(@it:0:1, @index4)] + [@index3.exists(@it:0:1, @index4)] == @index6) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([@ac:0:0 || @it:0:0 > 0, @ac:0:1 || @it:0:1 == "a", [1], ["a"], [true, true, true, true]], [@index2.exists(@it:0:0, @it:0:0 > 0)] + [@index2.exists(@it:0:0, @it:0:0 > 0)] + [@index3.exists(@it:0:1, @it:0:1 == "a")] + [@index3.exists(@it:0:1, @it:0:1 == "a")] == @index4) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([[1].exists(@it:0:0, @it:0:0 > 0), ["a"].exists(@it:0:1, @it:0:1 == "a"), [@index0], [@index1], @index2 + @index2 + @index3 + @index3], @index4 == [true, true, true, true]) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([[[1].exists(@it:0:0, @it:0:0 > 0)], [["a"].exists(@it:0:1, @it:0:1 == "a")]], @index0 + @index0 + @index1 + @index1 == [true, true, true, true]) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([[[1].exists(@it:0:0, @it:0:0 > 0)], [["a"].exists(@it:0:1, @it:0:1 == "a")]], @index0 + @index0 + @index1 + @index1 == [true, true, true, true]) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([[[1].exists(@it:0:0, @it:0:0 > 0)], [["a"].exists(@it:0:1, @it:0:1 == "a")]], @index0 + @index0 + @index1 + @index1 == [true, true, true, true]) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([[[1].exists(@it:0:0, @it:0:0 > 0)], [["a"].exists(@it:0:1, @it:0:1 == "a")]], @index0 + @index0 + @index1 + @index1 == [true, true, true, true]) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([[[1].exists(@it:0:0, @it:0:0 > 0)], [["a"].exists(@it:0:1, @it:0:1 == "a")]], @index0 + @index0 + @index1 + @index1 == [true, true, true, true]) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([[[1].exists(@it:0:0, @it:0:0 > 0)], [["a"].exists(@it:0:1, @it:0:1 == "a")]], @index0 + @index0 + @index1 + @index1 == [true, true, true, true]) Test case: MULTIPLE_MACROS_3 Source: [1].exists(i, i > 0) && [1].exists(j, j > 0) && [1].exists(k, k > 1) && [2].exists(l, l > 1) =====> Result: false -[CASCADED_BINDS]: cel.bind(@r0, [1], @r0.exists(@c:0, @c:0 > 0) && @r0.exists(@c:1, @c:1 > 0) && @r0.exists(@c:2, @c:2 > 1) && [2].exists(@c:3, @c:3 > 1)) -[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([[1]], @index0.exists(@c:0, @c:0 > 0) && @index0.exists(@c:1, @c:1 > 0) && @index0.exists(@c:2, @c:2 > 1) && [2].exists(@c:3, @c:3 > 1)) -[BLOCK_RECURSION_DEPTH_1]: cel.@block([[1], @c:0 > 0, @x:0 || @index1, @c:1 > 0, @x:1 || @index3, @c:2 > 1, @x:2 || @index5, [2], @c:3 > 1, @x:3 || @index8], @index0.exists(@c:0, @index1) && @index0.exists(@c:1, @index3) && @index0.exists(@c:2, @index5) && @index7.exists(@c:3, @index8)) -[BLOCK_RECURSION_DEPTH_2]: cel.@block([[1], @x:0 || @c:0 > 0, @x:1 || @c:1 > 0, @x:2 || @c:2 > 1, @x:3 || @c:3 > 1, [2]], @index0.exists(@c:0, @c:0 > 0) && @index0.exists(@c:1, @c:1 > 0) && @index0.exists(@c:2, @c:2 > 1) && @index5.exists(@c:3, @c:3 > 1)) -[BLOCK_RECURSION_DEPTH_3]: cel.@block([[1], @index0.exists(@c:0, @c:0 > 0), @index0.exists(@c:1, @c:1 > 0), @index0.exists(@c:2, @c:2 > 1), [2].exists(@c:3, @c:3 > 1)], @index1 && @index2 && @index3 && @index4) -[BLOCK_RECURSION_DEPTH_4]: cel.@block([[1], @index0.exists(@c:0, @c:0 > 0) && @index0.exists(@c:1, @c:1 > 0), @index0.exists(@c:2, @c:2 > 1) && [2].exists(@c:3, @c:3 > 1)], @index1 && @index2) -[BLOCK_RECURSION_DEPTH_5]: cel.@block([[1]], @index0.exists(@c:0, @c:0 > 0) && @index0.exists(@c:1, @c:1 > 0) && @index0.exists(@c:2, @c:2 > 1) && [2].exists(@c:3, @c:3 > 1)) -[BLOCK_RECURSION_DEPTH_6]: cel.@block([[1]], @index0.exists(@c:0, @c:0 > 0) && @index0.exists(@c:1, @c:1 > 0) && @index0.exists(@c:2, @c:2 > 1) && [2].exists(@c:3, @c:3 > 1)) -[BLOCK_RECURSION_DEPTH_7]: cel.@block([[1]], @index0.exists(@c:0, @c:0 > 0) && @index0.exists(@c:1, @c:1 > 0) && @index0.exists(@c:2, @c:2 > 1) && [2].exists(@c:3, @c:3 > 1)) -[BLOCK_RECURSION_DEPTH_8]: cel.@block([[1]], @index0.exists(@c:0, @c:0 > 0) && @index0.exists(@c:1, @c:1 > 0) && @index0.exists(@c:2, @c:2 > 1) && [2].exists(@c:3, @c:3 > 1)) -[BLOCK_RECURSION_DEPTH_9]: cel.@block([[1]], @index0.exists(@c:0, @c:0 > 0) && @index0.exists(@c:1, @c:1 > 0) && @index0.exists(@c:2, @c:2 > 1) && [2].exists(@c:3, @c:3 > 1)) +[CASCADED_BINDS]: cel.bind(@r0, [1], @r0.exists(@it:0, @it:0 > 0) && @r0.exists(@it:1, @it:1 > 0) && @r0.exists(@it:2, @it:2 > 1) && [2].exists(@it:3, @it:3 > 1)) +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([[1].exists(@it:0:0, @it:0:0 > 0), @ac:0:0 || @it:0:0 > 1], @index0 && @index0 && [1].exists(@it:0:0, @it:0:0 > 1) && [2].exists(@it:0:0, @it:0:0 > 1)) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([[1], @it:0:0 > 0, @ac:0:0 || @index1, @it:0:0 > 1, @ac:0:0 || @index3, [2]], @index0.exists(@it:0:0, @index1) && @index0.exists(@it:0:0, @index1) && @index0.exists(@it:0:0, @index3) && @index5.exists(@it:0:0, @index3)) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([@ac:0:0 || @it:0:0 > 0, @ac:0:0 || @it:0:0 > 1, [1], [2]], @index2.exists(@it:0:0, @it:0:0 > 0) && @index2.exists(@it:0:0, @it:0:0 > 0) && @index2.exists(@it:0:0, @it:0:0 > 1) && @index3.exists(@it:0:0, @it:0:0 > 1)) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([[1].exists(@it:0:0, @it:0:0 > 0), @ac:0:0 || @it:0:0 > 1, [1].exists(@it:0:0, @it:0:0 > 1), [2].exists(@it:0:0, @it:0:0 > 1)], @index0 && @index0 && @index2 && @index3) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([[1].exists(@it:0:0, @it:0:0 > 0), @ac:0:0 || @it:0:0 > 1, [1].exists(@it:0:0, @it:0:0 > 1) && [2].exists(@it:0:0, @it:0:0 > 1)], @index0 && @index0 && @index2) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([[1].exists(@it:0:0, @it:0:0 > 0), @ac:0:0 || @it:0:0 > 1], @index0 && @index0 && [1].exists(@it:0:0, @it:0:0 > 1) && [2].exists(@it:0:0, @it:0:0 > 1)) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([[1].exists(@it:0:0, @it:0:0 > 0), @ac:0:0 || @it:0:0 > 1], @index0 && @index0 && [1].exists(@it:0:0, @it:0:0 > 1) && [2].exists(@it:0:0, @it:0:0 > 1)) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([[1].exists(@it:0:0, @it:0:0 > 0), @ac:0:0 || @it:0:0 > 1], @index0 && @index0 && [1].exists(@it:0:0, @it:0:0 > 1) && [2].exists(@it:0:0, @it:0:0 > 1)) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([[1].exists(@it:0:0, @it:0:0 > 0), @ac:0:0 || @it:0:0 > 1], @index0 && @index0 && [1].exists(@it:0:0, @it:0:0 > 1) && [2].exists(@it:0:0, @it:0:0 > 1)) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([[1].exists(@it:0:0, @it:0:0 > 0), @ac:0:0 || @it:0:0 > 1], @index0 && @index0 && [1].exists(@it:0:0, @it:0:0 > 1) && [2].exists(@it:0:0, @it:0:0 > 1)) Test case: NESTED_MACROS Source: [1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [[2, 3, 4], [2, 3, 4], [2, 3, 4]] =====> Result: true -[CASCADED_BINDS]: cel.bind(@r0, [1, 2, 3], @r0.map(@c:1, @r0.map(@c:0, @c:0 + 1))) == cel.bind(@r1, [2, 3, 4], [@r1, @r1, @r1]) -[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([[1, 2, 3], [2, 3, 4]], @index0.map(@c:1, @index0.map(@c:0, @c:0 + 1)) == [@index1, @index1, @index1]) -[BLOCK_RECURSION_DEPTH_1]: cel.@block([[1, 2, 3], [2, 3, 4], @c:0 + 1, [@index2], @x:0 + @index3, [@index1, @index1, @index1]], @index0.map(@c:1, @index0.map(@c:0, @index2)) == @index5) -[BLOCK_RECURSION_DEPTH_2]: cel.@block([[1, 2, 3], [2, 3, 4], [@c:0 + 1], @index0.map(@c:0, @c:0 + 1), @x:1 + [@index3], @index0.map(@c:1, @index3)], @index5 == [@index1, @index1, @index1]) -[BLOCK_RECURSION_DEPTH_3]: cel.@block([[1, 2, 3], [2, 3, 4], @x:0 + [@c:0 + 1], [@index0.map(@c:0, @c:0 + 1)]], @index0.map(@c:1) == [@index1, @index1, @index1]) -[BLOCK_RECURSION_DEPTH_4]: cel.@block([[1, 2, 3], [2, 3, 4], @index0.map(@c:0, @c:0 + 1)], @index0.map(@c:1, @index2) == [@index1, @index1, @index1]) -[BLOCK_RECURSION_DEPTH_5]: cel.@block([[1, 2, 3], [2, 3, 4], [@index0.map(@c:0, @c:0 + 1)]], @index0.map(@c:1) == [@index1, @index1, @index1]) -[BLOCK_RECURSION_DEPTH_6]: cel.@block([[1, 2, 3], [2, 3, 4], @x:1 + [@index0.map(@c:0, @c:0 + 1)]], @index0.map(@c:1) == [@index1, @index1, @index1]) -[BLOCK_RECURSION_DEPTH_7]: cel.@block([[1, 2, 3], [2, 3, 4], @index0.map(@c:1, @index0.map(@c:0, @c:0 + 1))], @index2 == [@index1, @index1, @index1]) -[BLOCK_RECURSION_DEPTH_8]: cel.@block([[1, 2, 3], [2, 3, 4]], @index0.map(@c:1, @index0.map(@c:0, @c:0 + 1)) == [@index1, @index1, @index1]) -[BLOCK_RECURSION_DEPTH_9]: cel.@block([[1, 2, 3], [2, 3, 4]], @index0.map(@c:1, @index0.map(@c:0, @c:0 + 1)) == [@index1, @index1, @index1]) +[CASCADED_BINDS]: cel.bind(@r0, [1, 2, 3], @r0.map(@it:1, @r0.map(@it:0, @it:0 + 1))) == cel.bind(@r1, [2, 3, 4], [@r1, @r1, @r1]) +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([[1, 2, 3], [2, 3, 4]], @index0.map(@it:0:0, @index0.map(@it:1:0, @it:1:0 + 1)) == [@index1, @index1, @index1]) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([[1, 2, 3], [2, 3, 4], @it:1:0 + 1, [@index2], @ac:1:0 + @index3, [@index1, @index1, @index1]], @index0.map(@it:0:0, @index0.map(@it:1:0, @index2)) == @index5) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([[1, 2, 3], [2, 3, 4], [@it:1:0 + 1], @index0.map(@it:1:0, @it:1:0 + 1), @ac:0:0 + [@index3], @index0.map(@it:0:0, @index3)], @index5 == [@index1, @index1, @index1]) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([[1, 2, 3], [2, 3, 4], @ac:1:0 + [@it:1:0 + 1], [@index0.map(@it:1:0, @it:1:0 + 1)]], @index0.map(@it:0:0) == [@index1, @index1, @index1]) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([[1, 2, 3], [2, 3, 4], @index0.map(@it:1:0, @it:1:0 + 1)], @index0.map(@it:0:0, @index2) == [@index1, @index1, @index1]) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([[1, 2, 3], [2, 3, 4], [@index0.map(@it:1:0, @it:1:0 + 1)]], @index0.map(@it:0:0) == [@index1, @index1, @index1]) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([[1, 2, 3], [2, 3, 4], @ac:0:0 + [@index0.map(@it:1:0, @it:1:0 + 1)]], @index0.map(@it:0:0) == [@index1, @index1, @index1]) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([[1, 2, 3], [2, 3, 4], @index0.map(@it:0:0, @index0.map(@it:1:0, @it:1:0 + 1))], @index2 == [@index1, @index1, @index1]) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([[1, 2, 3], [2, 3, 4]], @index0.map(@it:0:0, @index0.map(@it:1:0, @it:1:0 + 1)) == [@index1, @index1, @index1]) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([[1, 2, 3], [2, 3, 4]], @index0.map(@it:0:0, @index0.map(@it:1:0, @it:1:0 + 1)) == [@index1, @index1, @index1]) Test case: NESTED_MACROS_2 Source: [1, 2].map(y, [1, 2, 3].filter(x, x == y)) == [[1], [2]] =====> Result: true -[CASCADED_BINDS]: [1, 2].map(@c:1, [1, 2, 3].filter(@c:0, @c:0 == @c:1)) == [[1], [2]] -[BLOCK_COMMON_SUBEXPR_ONLY]: [1, 2].map(@c:1, [1, 2, 3].filter(@c:0, @c:0 == @c:1)) == [[1], [2]] -[BLOCK_RECURSION_DEPTH_1]: cel.@block([[1, 2], [1, 2, 3], @c:0 == @c:1, [@c:0], @x:0 + @index3, @index2 ? @index4 : @x:0, [1], [2], [@index6, @index7]], @index0.map(@c:1, @index1.filter(@c:0, @index2)) == @index8) -[BLOCK_RECURSION_DEPTH_2]: cel.@block([@x:0 + [@c:0], (@c:0 == @c:1) ? @index0 : @x:0, [1, 2, 3].filter(@c:0, @c:0 == @c:1), @x:1 + [@index2], [1, 2].map(@c:1, @index2), [[1], [2]]], @index4 == @index5) -[BLOCK_RECURSION_DEPTH_3]: cel.@block([(@c:0 == @c:1) ? (@x:0 + [@c:0]) : @x:0, [[1, 2, 3].filter(@c:0, @c:0 == @c:1)]], [1, 2].map(@c:1) == [[1], [2]]) -[BLOCK_RECURSION_DEPTH_4]: cel.@block([[1, 2, 3].filter(@c:0, @c:0 == @c:1)], [1, 2].map(@c:1, @index0) == [[1], [2]]) -[BLOCK_RECURSION_DEPTH_5]: cel.@block([[[1, 2, 3].filter(@c:0, @c:0 == @c:1)]], [1, 2].map(@c:1) == [[1], [2]]) -[BLOCK_RECURSION_DEPTH_6]: cel.@block([@x:1 + [[1, 2, 3].filter(@c:0, @c:0 == @c:1)]], [1, 2].map(@c:1) == [[1], [2]]) -[BLOCK_RECURSION_DEPTH_7]: cel.@block([[1, 2].map(@c:1, [1, 2, 3].filter(@c:0, @c:0 == @c:1))], @index0 == [[1], [2]]) -[BLOCK_RECURSION_DEPTH_8]: [1, 2].map(@c:1, [1, 2, 3].filter(@c:0, @c:0 == @c:1)) == [[1], [2]] -[BLOCK_RECURSION_DEPTH_9]: [1, 2].map(@c:1, [1, 2, 3].filter(@c:0, @c:0 == @c:1)) == [[1], [2]] +[CASCADED_BINDS]: [1, 2].map(@it:1, [1, 2, 3].filter(@it:0, @it:0 == @it:1)) == [[1], [2]] +[BLOCK_COMMON_SUBEXPR_ONLY]: [1, 2].map(@it:0:0, [1, 2, 3].filter(@it:1:0, @it:1:0 == @it:0:0)) == [[1], [2]] +[BLOCK_RECURSION_DEPTH_1]: cel.@block([[1, 2], [1, 2, 3], @it:1:0 == @it:0:0, [@it:1:0], @ac:1:0 + @index3, @index2 ? @index4 : @ac:1:0, [1], [2], [@index6, @index7]], @index0.map(@it:0:0, @index1.filter(@it:1:0, @index2)) == @index8) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([@ac:1:0 + [@it:1:0], (@it:1:0 == @it:0:0) ? @index0 : @ac:1:0, [1, 2, 3].filter(@it:1:0, @it:1:0 == @it:0:0), @ac:0:0 + [@index2], [1, 2].map(@it:0:0, @index2), [[1], [2]]], @index4 == @index5) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([(@it:1:0 == @it:0:0) ? (@ac:1:0 + [@it:1:0]) : @ac:1:0, [[1, 2, 3].filter(@it:1:0, @it:1:0 == @it:0:0)]], [1, 2].map(@it:0:0) == [[1], [2]]) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([[1, 2, 3].filter(@it:1:0, @it:1:0 == @it:0:0)], [1, 2].map(@it:0:0, @index0) == [[1], [2]]) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([[[1, 2, 3].filter(@it:1:0, @it:1:0 == @it:0:0)]], [1, 2].map(@it:0:0) == [[1], [2]]) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([@ac:0:0 + [[1, 2, 3].filter(@it:1:0, @it:1:0 == @it:0:0)]], [1, 2].map(@it:0:0) == [[1], [2]]) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([[1, 2].map(@it:0:0, [1, 2, 3].filter(@it:1:0, @it:1:0 == @it:0:0))], @index0 == [[1], [2]]) +[BLOCK_RECURSION_DEPTH_8]: [1, 2].map(@it:0:0, [1, 2, 3].filter(@it:1:0, @it:1:0 == @it:0:0)) == [[1], [2]] +[BLOCK_RECURSION_DEPTH_9]: [1, 2].map(@it:0:0, [1, 2, 3].filter(@it:1:0, @it:1:0 == @it:0:0)) == [[1], [2]] Test case: ADJACENT_NESTED_MACROS Source: [1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [1,2,3].map(j, [1, 2, 3].map(j, j + 1)) =====> Result: true -[CASCADED_BINDS]: cel.bind(@r0, [1, 2, 3], @r0.map(@c:1, @r0.map(@c:0, @c:0 + 1)) == @r0.map(@c:3, @r0.map(@c:2, @c:2 + 1))) -[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([[1, 2, 3]], @index0.map(@c:1, @index0.map(@c:0, @c:0 + 1)) == @index0.map(@c:3, @index0.map(@c:2, @c:2 + 1))) -[BLOCK_RECURSION_DEPTH_1]: cel.@block([[1, 2, 3], @c:0 + 1, [@index1], @x:0 + @index2, @c:2 + 1, [@index4], @x:2 + @index5], @index0.map(@c:1, @index0.map(@c:0, @index1)) == @index0.map(@c:3, @index0.map(@c:2, @index4))) -[BLOCK_RECURSION_DEPTH_2]: cel.@block([[1, 2, 3], [@c:0 + 1], @index0.map(@c:0, @c:0 + 1), @x:1 + [@index2], @index0.map(@c:1, @index2), [@c:2 + 1], @index0.map(@c:2, @c:2 + 1), @x:3 + [@index6], @index0.map(@c:3, @index6)], @index4 == @index8) -[BLOCK_RECURSION_DEPTH_3]: cel.@block([[1, 2, 3], @x:0 + [@c:0 + 1], [@index0.map(@c:0, @c:0 + 1)], @x:2 + [@c:2 + 1], [@index0.map(@c:2, @c:2 + 1)]], @index0.map(@c:1) == @index0.map(@c:3)) -[BLOCK_RECURSION_DEPTH_4]: cel.@block([[1, 2, 3], @index0.map(@c:0, @c:0 + 1), @index0.map(@c:2, @c:2 + 1)], @index0.map(@c:1, @index1) == @index0.map(@c:3, @index2)) -[BLOCK_RECURSION_DEPTH_5]: cel.@block([[1, 2, 3], [@index0.map(@c:0, @c:0 + 1)], [@index0.map(@c:2, @c:2 + 1)]], @index0.map(@c:1) == @index0.map(@c:3)) -[BLOCK_RECURSION_DEPTH_6]: cel.@block([[1, 2, 3], @x:1 + [@index0.map(@c:0, @c:0 + 1)], @x:3 + [@index0.map(@c:2, @c:2 + 1)]], @index0.map(@c:1) == @index0.map(@c:3)) -[BLOCK_RECURSION_DEPTH_7]: cel.@block([[1, 2, 3], @index0.map(@c:1, @index0.map(@c:0, @c:0 + 1)), @index0.map(@c:3, @index0.map(@c:2, @c:2 + 1))], @index1 == @index2) -[BLOCK_RECURSION_DEPTH_8]: cel.@block([[1, 2, 3]], @index0.map(@c:1, @index0.map(@c:0, @c:0 + 1)) == @index0.map(@c:3, @index0.map(@c:2, @c:2 + 1))) -[BLOCK_RECURSION_DEPTH_9]: cel.@block([[1, 2, 3]], @index0.map(@c:1, @index0.map(@c:0, @c:0 + 1)) == @index0.map(@c:3, @index0.map(@c:2, @c:2 + 1))) +[CASCADED_BINDS]: cel.bind(@r0, [1, 2, 3], @r0.map(@it:1, @r0.map(@it:0, @it:0 + 1)) == @r0.map(@it:3, @r0.map(@it:2, @it:2 + 1))) +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([[1, 2, 3], @index0.map(@it:0:0, @index0.map(@it:1:0, @it:1:0 + 1))], @index1 == @index1) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([[1, 2, 3], @it:1:0 + 1, [@index1], @ac:1:0 + @index2], @index0.map(@it:0:0, @index0.map(@it:1:0, @index1)) == @index0.map(@it:0:0, @index0.map(@it:1:0, @index1))) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([[@it:1:0 + 1], [1, 2, 3].map(@it:1:0, @it:1:0 + 1), @ac:0:0 + [@index1], [1, 2, 3].map(@it:0:0, @index1)], @index3 == @index3) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([@ac:1:0 + [@it:1:0 + 1], [[1, 2, 3].map(@it:1:0, @it:1:0 + 1)], [1, 2, 3].map(@it:0:0)], @index2 == @index2) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([[1, 2, 3].map(@it:1:0, @it:1:0 + 1), [1, 2, 3].map(@it:0:0, @index0)], @index1 == @index1) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([[[1, 2, 3].map(@it:1:0, @it:1:0 + 1)], [1, 2, 3].map(@it:0:0)], @index1 == @index1) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([@ac:0:0 + [[1, 2, 3].map(@it:1:0, @it:1:0 + 1)], [1, 2, 3].map(@it:0:0)], @index1 == @index1) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([[1, 2, 3].map(@it:0:0, [1, 2, 3].map(@it:1:0, @it:1:0 + 1))], @index0 == @index0) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([[1, 2, 3].map(@it:0:0, [1, 2, 3].map(@it:1:0, @it:1:0 + 1))], @index0 == @index0) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([[1, 2, 3].map(@it:0:0, [1, 2, 3].map(@it:1:0, @it:1:0 + 1))], @index0 == @index0) Test case: INCLUSION_LIST Source: 1 in [1,2,3] && 2 in [1,2,3] && 3 in [3, [1,2,3]] && 1 in [1,2,3] @@ -402,49 +402,49 @@ Test case: MACRO_ITER_VAR_NOT_REFERENCED Source: [1,2].map(i, [1, 2].map(i, [3,4])) == [[[3, 4], [3, 4]], [[3, 4], [3, 4]]] =====> Result: true -[CASCADED_BINDS]: cel.bind(@r1, [3, 4], cel.bind(@r0, [1, 2], @r0.map(@c:1, @r0.map(@c:0, @r1))) == cel.bind(@r2, [@r1, @r1], [@r2, @r2])) -[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([[1, 2], [3, 4], [@index1, @index1]], @index0.map(@c:1, @index0.map(@c:0, @index1)) == [@index2, @index2]) -[BLOCK_RECURSION_DEPTH_1]: cel.@block([[1, 2], [3, 4], [@index1, @index1], [@index1], @x:0 + @index3, [@index2, @index2]], @index0.map(@c:1, @index0.map(@c:0, @index1)) == @index5) -[BLOCK_RECURSION_DEPTH_2]: cel.@block([[[3, 4], [3, 4]], [1, 2], [[3, 4]], @index1.map(@c:0, [3, 4]), @x:1 + [@index3], @index1.map(@c:1, @index3)], @index5 == [@index0, @index0]) -[BLOCK_RECURSION_DEPTH_3]: cel.@block([[[3, 4], [3, 4]], [1, 2], @x:0 + [[3, 4]], [@index1.map(@c:0, [3, 4])]], @index1.map(@c:1) == [@index0, @index0]) -[BLOCK_RECURSION_DEPTH_4]: cel.@block([[[3, 4], [3, 4]], [1, 2], @index1.map(@c:0, [3, 4])], @index1.map(@c:1, @index2) == [@index0, @index0]) -[BLOCK_RECURSION_DEPTH_5]: cel.@block([[[3, 4], [3, 4]], [1, 2], [@index1.map(@c:0, [3, 4])]], @index1.map(@c:1) == [@index0, @index0]) -[BLOCK_RECURSION_DEPTH_6]: cel.@block([[[3, 4], [3, 4]], [1, 2], @x:1 + [@index1.map(@c:0, [3, 4])]], @index1.map(@c:1) == [@index0, @index0]) -[BLOCK_RECURSION_DEPTH_7]: cel.@block([[[3, 4], [3, 4]], [1, 2], @index1.map(@c:1, @index1.map(@c:0, [3, 4]))], @index2 == [@index0, @index0]) -[BLOCK_RECURSION_DEPTH_8]: cel.@block([[[3, 4], [3, 4]], [1, 2]], @index1.map(@c:1, @index1.map(@c:0, [3, 4])) == [@index0, @index0]) -[BLOCK_RECURSION_DEPTH_9]: cel.@block([[[3, 4], [3, 4]], [1, 2]], @index1.map(@c:1, @index1.map(@c:0, [3, 4])) == [@index0, @index0]) +[CASCADED_BINDS]: cel.bind(@r1, [3, 4], cel.bind(@r0, [1, 2], @r0.map(@it:1, @r0.map(@it:0, @r1))) == cel.bind(@r2, [@r1, @r1], [@r2, @r2])) +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([[1, 2], [3, 4], [@index1, @index1]], @index0.map(@it:0:0, @index0.map(@it:1:0, @index1)) == [@index2, @index2]) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([[1, 2], [3, 4], [@index1, @index1], [@index1], @ac:1:0 + @index3, [@index2, @index2]], @index0.map(@it:0:0, @index0.map(@it:1:0, @index1)) == @index5) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([[[3, 4], [3, 4]], [1, 2], [[3, 4]], @index1.map(@it:1:0, [3, 4]), @ac:0:0 + [@index3], @index1.map(@it:0:0, @index3)], @index5 == [@index0, @index0]) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([[[3, 4], [3, 4]], [1, 2], @ac:1:0 + [[3, 4]], [@index1.map(@it:1:0, [3, 4])]], @index1.map(@it:0:0) == [@index0, @index0]) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([[[3, 4], [3, 4]], [1, 2], @index1.map(@it:1:0, [3, 4])], @index1.map(@it:0:0, @index2) == [@index0, @index0]) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([[[3, 4], [3, 4]], [1, 2], [@index1.map(@it:1:0, [3, 4])]], @index1.map(@it:0:0) == [@index0, @index0]) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([[[3, 4], [3, 4]], [1, 2], @ac:0:0 + [@index1.map(@it:1:0, [3, 4])]], @index1.map(@it:0:0) == [@index0, @index0]) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([[[3, 4], [3, 4]], [1, 2], @index1.map(@it:0:0, @index1.map(@it:1:0, [3, 4]))], @index2 == [@index0, @index0]) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([[[3, 4], [3, 4]], [1, 2]], @index1.map(@it:0:0, @index1.map(@it:1:0, [3, 4])) == [@index0, @index0]) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([[[3, 4], [3, 4]], [1, 2]], @index1.map(@it:0:0, @index1.map(@it:1:0, [3, 4])) == [@index0, @index0]) Test case: MACRO_SHADOWED_VARIABLE Source: [x - 1 > 3 ? x - 1 : 5].exists(x, x - 1 > 3) || x - 1 > 3 =====> Result: true -[CASCADED_BINDS]: cel.bind(@r0, x - 1, cel.bind(@r1, @r0 > 3, [@r1 ? @r0 : 5].exists(@c:0, @c:0 - 1 > 3) || @r1)) -[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([x - 1, @index0 > 3], [@index1 ? @index0 : 5].exists(@c:0, @c:0 - 1 > 3) || @index1) -[BLOCK_RECURSION_DEPTH_1]: cel.@block([x - 1, @index0 > 3, @index1 ? @index0 : 5, [@index2], @c:0 - 1, @index4 > 3, @x:0 || @index5], @index3.exists(@c:0, @index5) || @index1) -[BLOCK_RECURSION_DEPTH_2]: cel.@block([x - 1 > 3, @index0 ? (x - 1) : 5, @c:0 - 1 > 3, [@index1], @x:0 || @index2], @index3.exists(@c:0, @index2) || @index0) -[BLOCK_RECURSION_DEPTH_3]: cel.@block([x - 1 > 3, [@index0 ? (x - 1) : 5], @x:0 || @c:0 - 1 > 3, @index1.exists(@c:0, @c:0 - 1 > 3)], @index3 || @index0) -[BLOCK_RECURSION_DEPTH_4]: cel.@block([x - 1 > 3, [@index0 ? (x - 1) : 5].exists(@c:0, @c:0 - 1 > 3)], @index1 || @index0) -[BLOCK_RECURSION_DEPTH_5]: cel.@block([x - 1 > 3], [@index0 ? (x - 1) : 5].exists(@c:0, @c:0 - 1 > 3) || @index0) -[BLOCK_RECURSION_DEPTH_6]: cel.@block([x - 1 > 3], [@index0 ? (x - 1) : 5].exists(@c:0, @c:0 - 1 > 3) || @index0) -[BLOCK_RECURSION_DEPTH_7]: cel.@block([x - 1 > 3], [@index0 ? (x - 1) : 5].exists(@c:0, @c:0 - 1 > 3) || @index0) -[BLOCK_RECURSION_DEPTH_8]: cel.@block([x - 1 > 3], [@index0 ? (x - 1) : 5].exists(@c:0, @c:0 - 1 > 3) || @index0) -[BLOCK_RECURSION_DEPTH_9]: cel.@block([x - 1 > 3], [@index0 ? (x - 1) : 5].exists(@c:0, @c:0 - 1 > 3) || @index0) +[CASCADED_BINDS]: cel.bind(@r0, x - 1, cel.bind(@r1, @r0 > 3, [@r1 ? @r0 : 5].exists(@it:0, @it:0 - 1 > 3) || @r1)) +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([x - 1, @index0 > 3], [@index1 ? @index0 : 5].exists(@it:0:0, @it:0:0 - 1 > 3) || @index1) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([x - 1, @index0 > 3, @index1 ? @index0 : 5, [@index2], @it:0:0 - 1, @index4 > 3, @ac:0:0 || @index5], @index3.exists(@it:0:0, @index5) || @index1) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([x - 1 > 3, @index0 ? (x - 1) : 5, @it:0:0 - 1 > 3, [@index1], @ac:0:0 || @index2], @index3.exists(@it:0:0, @index2) || @index0) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([x - 1 > 3, [@index0 ? (x - 1) : 5], @ac:0:0 || @it:0:0 - 1 > 3, @index1.exists(@it:0:0, @it:0:0 - 1 > 3)], @index3 || @index0) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([x - 1 > 3, [@index0 ? (x - 1) : 5].exists(@it:0:0, @it:0:0 - 1 > 3)], @index1 || @index0) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([x - 1 > 3], [@index0 ? (x - 1) : 5].exists(@it:0:0, @it:0:0 - 1 > 3) || @index0) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([x - 1 > 3], [@index0 ? (x - 1) : 5].exists(@it:0:0, @it:0:0 - 1 > 3) || @index0) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([x - 1 > 3], [@index0 ? (x - 1) : 5].exists(@it:0:0, @it:0:0 - 1 > 3) || @index0) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([x - 1 > 3], [@index0 ? (x - 1) : 5].exists(@it:0:0, @it:0:0 - 1 > 3) || @index0) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([x - 1 > 3], [@index0 ? (x - 1) : 5].exists(@it:0:0, @it:0:0 - 1 > 3) || @index0) Test case: MACRO_SHADOWED_VARIABLE_2 Source: ["foo", "bar"].map(x, [x + x, x + x]).map(x, [x + x, x + x]) =====> Result: [[[foofoo, foofoo, foofoo, foofoo], [foofoo, foofoo, foofoo, foofoo]], [[barbar, barbar, barbar, barbar], [barbar, barbar, barbar, barbar]]] -[CASCADED_BINDS]: ["foo", "bar"].map(@c:0, cel.bind(@r0, @c:0 + @c:0, [@r0, @r0])).map(@c:1, cel.bind(@r1, @c:1 + @c:1, [@r1, @r1])) -[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([@c:0 + @c:0, @c:1 + @c:1], ["foo", "bar"].map(@c:0, [@index0, @index0]).map(@c:1, [@index1, @index1])) -[BLOCK_RECURSION_DEPTH_1]: cel.@block([@c:0 + @c:0, @c:1 + @c:1, ["foo", "bar"], [@index0, @index0], [@index3], @x:0 + @index4, [@index1, @index1], [@index6], @x:1 + @index7], @index2.map(@c:0, @index3).map(@c:1, @index6)) -[BLOCK_RECURSION_DEPTH_2]: cel.@block([@c:0 + @c:0, @c:1 + @c:1, [[@index0, @index0]], ["foo", "bar"].map(@c:0, [@index0, @index0]), [[@index1, @index1]]], @index3.map(@c:1, [@index1, @index1])) -[BLOCK_RECURSION_DEPTH_3]: cel.@block([@c:0 + @c:0, @c:1 + @c:1, @x:0 + [[@index0, @index0]], @x:1 + [[@index1, @index1]]], ["foo", "bar"].map(@c:0, [@index0, @index0]).map(@c:1, [@index1, @index1])) -[BLOCK_RECURSION_DEPTH_4]: cel.@block([@c:0 + @c:0, @c:1 + @c:1, ["foo", "bar"].map(@c:0, [@index0, @index0])], @index2.map(@c:1, [@index1, @index1])) -[BLOCK_RECURSION_DEPTH_5]: cel.@block([@c:0 + @c:0, @c:1 + @c:1], ["foo", "bar"].map(@c:0, [@index0, @index0]).map(@c:1, [@index1, @index1])) -[BLOCK_RECURSION_DEPTH_6]: cel.@block([@c:0 + @c:0, @c:1 + @c:1], ["foo", "bar"].map(@c:0, [@index0, @index0]).map(@c:1, [@index1, @index1])) -[BLOCK_RECURSION_DEPTH_7]: cel.@block([@c:0 + @c:0, @c:1 + @c:1], ["foo", "bar"].map(@c:0, [@index0, @index0]).map(@c:1, [@index1, @index1])) -[BLOCK_RECURSION_DEPTH_8]: cel.@block([@c:0 + @c:0, @c:1 + @c:1], ["foo", "bar"].map(@c:0, [@index0, @index0]).map(@c:1, [@index1, @index1])) -[BLOCK_RECURSION_DEPTH_9]: cel.@block([@c:0 + @c:0, @c:1 + @c:1], ["foo", "bar"].map(@c:0, [@index0, @index0]).map(@c:1, [@index1, @index1])) +[CASCADED_BINDS]: ["foo", "bar"].map(@it:0, cel.bind(@r0, @it:0 + @it:0, [@r0, @r0])).map(@it:1, cel.bind(@r1, @it:1 + @it:1, [@r1, @r1])) +[BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([@it:1:0 + @it:1:0, @it:0:0 + @it:0:0], ["foo", "bar"].map(@it:1:0, [@index0, @index0]).map(@it:0:0, [@index1, @index1])) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([@it:1:0 + @it:1:0, @it:0:0 + @it:0:0, ["foo", "bar"], [@index0, @index0], [@index3], @ac:1:0 + @index4, [@index1, @index1], [@index6], @ac:0:0 + @index7], @index2.map(@it:1:0, @index3).map(@it:0:0, @index6)) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([@it:1:0 + @it:1:0, @it:0:0 + @it:0:0, [[@index0, @index0]], ["foo", "bar"].map(@it:1:0, [@index0, @index0]), [[@index1, @index1]]], @index3.map(@it:0:0, [@index1, @index1])) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([@it:1:0 + @it:1:0, @it:0:0 + @it:0:0, @ac:1:0 + [[@index0, @index0]], @ac:0:0 + [[@index1, @index1]]], ["foo", "bar"].map(@it:1:0, [@index0, @index0]).map(@it:0:0, [@index1, @index1])) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([@it:1:0 + @it:1:0, @it:0:0 + @it:0:0, ["foo", "bar"].map(@it:1:0, [@index0, @index0])], @index2.map(@it:0:0, [@index1, @index1])) +[BLOCK_RECURSION_DEPTH_5]: cel.@block([@it:1:0 + @it:1:0, @it:0:0 + @it:0:0], ["foo", "bar"].map(@it:1:0, [@index0, @index0]).map(@it:0:0, [@index1, @index1])) +[BLOCK_RECURSION_DEPTH_6]: cel.@block([@it:1:0 + @it:1:0, @it:0:0 + @it:0:0], ["foo", "bar"].map(@it:1:0, [@index0, @index0]).map(@it:0:0, [@index1, @index1])) +[BLOCK_RECURSION_DEPTH_7]: cel.@block([@it:1:0 + @it:1:0, @it:0:0 + @it:0:0], ["foo", "bar"].map(@it:1:0, [@index0, @index0]).map(@it:0:0, [@index1, @index1])) +[BLOCK_RECURSION_DEPTH_8]: cel.@block([@it:1:0 + @it:1:0, @it:0:0 + @it:0:0], ["foo", "bar"].map(@it:1:0, [@index0, @index0]).map(@it:0:0, [@index1, @index1])) +[BLOCK_RECURSION_DEPTH_9]: cel.@block([@it:1:0 + @it:1:0, @it:0:0 + @it:0:0], ["foo", "bar"].map(@it:1:0, [@index0, @index0]).map(@it:0:0, [@index1, @index1])) Test case: PRESENCE_TEST Source: has({'a': true}.a) && {'a':true}['a'] From 78dfcb527526de25e1b5f498bdde6f140c302801 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Wed, 21 Aug 2024 11:31:43 -0700 Subject: [PATCH 183/486] Enable UnsignedLongs by default in CelOptions PiperOrigin-RevId: 665962755 --- common/src/main/java/dev/cel/common/CelOptions.java | 1 + common/src/main/java/dev/cel/common/ExprFeatures.java | 3 ++- .../java/dev/cel/common/internal/ProtoAdapterTest.java | 2 +- .../cel/common/values/ProtoMessageValueProviderTest.java | 8 ++++---- .../java/dev/cel/extensions/CelMathExtensionsTest.java | 2 ++ testing/src/test/java/dev/cel/testing/EvalSyncTest.java | 5 +++-- 6 files changed, 13 insertions(+), 8 deletions(-) diff --git a/common/src/main/java/dev/cel/common/CelOptions.java b/common/src/main/java/dev/cel/common/CelOptions.java index c5288aa2f..2568099fb 100644 --- a/common/src/main/java/dev/cel/common/CelOptions.java +++ b/common/src/main/java/dev/cel/common/CelOptions.java @@ -211,6 +211,7 @@ public static Builder current() { return newBuilder() .enableReservedIds(true) .enableUnsignedComparisonAndArithmeticIsUnsigned(true) + .enableUnsignedLongs(true) .enableRegexPartialMatch(true) .errorOnDuplicateMapKeys(true) .errorOnIntWrap(true) diff --git a/common/src/main/java/dev/cel/common/ExprFeatures.java b/common/src/main/java/dev/cel/common/ExprFeatures.java index 2bc36b6e6..c4170bbb9 100644 --- a/common/src/main/java/dev/cel/common/ExprFeatures.java +++ b/common/src/main/java/dev/cel/common/ExprFeatures.java @@ -159,7 +159,8 @@ public enum ExprFeatures { UNSIGNED_COMPARISON_AND_ARITHMETIC_IS_UNSIGNED, ENABLE_NAMESPACED_DECLARATIONS, ERROR_ON_WRAP, - ERROR_ON_DUPLICATE_KEYS); + ERROR_ON_DUPLICATE_KEYS, + ENABLE_UNSIGNED_LONGS); public static final ImmutableSet LEGACY = ImmutableSet.of(LEGACY_JAVA_EQUALITY); } diff --git a/common/src/test/java/dev/cel/common/internal/ProtoAdapterTest.java b/common/src/test/java/dev/cel/common/internal/ProtoAdapterTest.java index 151f79f49..8126ec949 100644 --- a/common/src/test/java/dev/cel/common/internal/ProtoAdapterTest.java +++ b/common/src/test/java/dev/cel/common/internal/ProtoAdapterTest.java @@ -106,7 +106,7 @@ public static List data() { }, {1L, Int64Value.of(1L), LEGACY}, {1L, Any.pack(Int64Value.of(1L)), LEGACY}, - {1L, UInt64Value.of(1L), LEGACY}, + {UnsignedLong.valueOf(1L), UInt64Value.of(1L), LEGACY}, {"hello", StringValue.of("hello"), LEGACY}, {"hello", Any.pack(StringValue.of("hello")), LEGACY}, {"hello", Value.newBuilder().setStringValue("hello").build(), LEGACY}, diff --git a/common/src/test/java/dev/cel/common/values/ProtoMessageValueProviderTest.java b/common/src/test/java/dev/cel/common/values/ProtoMessageValueProviderTest.java index de08149f0..6dfb01344 100644 --- a/common/src/test/java/dev/cel/common/values/ProtoMessageValueProviderTest.java +++ b/common/src/test/java/dev/cel/common/values/ProtoMessageValueProviderTest.java @@ -106,9 +106,9 @@ public void newValue_createProtoMessage_fieldsPopulated() { assertThat(protoMessageValue.select(StringValue.create("single_int64"))) .isEqualTo(IntValue.create(2L)); assertThat(protoMessageValue.select(StringValue.create("single_uint32"))) - .isEqualTo(UintValue.create(3L, false)); + .isEqualTo(UintValue.create(3L, true)); assertThat(protoMessageValue.select(StringValue.create("single_uint64"))) - .isEqualTo(UintValue.create(4L, false)); + .isEqualTo(UintValue.create(4L, true)); assertThat(protoMessageValue.select(StringValue.create("single_double"))) .isEqualTo(DoubleValue.create(5.5d)); assertThat(protoMessageValue.select(StringValue.create("single_bool"))) @@ -178,9 +178,9 @@ public void newValue_createProtoMessage_wrappersPopulated() { assertThat(protoMessageValue.select(StringValue.create("single_int64_wrapper")).value()) .isEqualTo(2L); assertThat(protoMessageValue.select(StringValue.create("single_uint32_wrapper")).value()) - .isEqualTo(3L); + .isEqualTo(UnsignedLong.valueOf(3L)); assertThat(protoMessageValue.select(StringValue.create("single_uint64_wrapper")).value()) - .isEqualTo(4L); + .isEqualTo(UnsignedLong.valueOf(4L)); assertThat(protoMessageValue.select(StringValue.create("single_double_wrapper")).value()) .isEqualTo(5.5d); assertThat(protoMessageValue.select(StringValue.create("single_bool_wrapper")).value()) diff --git a/extensions/src/test/java/dev/cel/extensions/CelMathExtensionsTest.java b/extensions/src/test/java/dev/cel/extensions/CelMathExtensionsTest.java index 320e7dfea..a0bf39e77 100644 --- a/extensions/src/test/java/dev/cel/extensions/CelMathExtensionsTest.java +++ b/extensions/src/test/java/dev/cel/extensions/CelMathExtensionsTest.java @@ -44,10 +44,12 @@ public class CelMathExtensionsTest { CelOptions.current().enableUnsignedLongs(false).build(); private static final CelCompiler CEL_COMPILER = CelCompilerFactory.standardCelCompilerBuilder() + .setOptions(CEL_OPTIONS) .addLibraries(CelExtensions.math(CEL_OPTIONS)) .build(); private static final CelRuntime CEL_RUNTIME = CelRuntimeFactory.standardCelRuntimeBuilder() + .setOptions(CEL_OPTIONS) .addLibraries(CelExtensions.math(CEL_OPTIONS)) .build(); diff --git a/testing/src/test/java/dev/cel/testing/EvalSyncTest.java b/testing/src/test/java/dev/cel/testing/EvalSyncTest.java index e516d9780..438ba0c43 100644 --- a/testing/src/test/java/dev/cel/testing/EvalSyncTest.java +++ b/testing/src/test/java/dev/cel/testing/EvalSyncTest.java @@ -17,6 +17,7 @@ import static com.google.common.truth.Truth.assertThat; import com.google.common.collect.ImmutableList; +import com.google.common.primitives.UnsignedLong; import com.google.protobuf.Any; import com.google.protobuf.BoolValue; import com.google.protobuf.ByteString; @@ -80,8 +81,8 @@ public static List data() { {StringValue.of("test"), "test"}, {Int32Value.of(1), 1L}, {Int64Value.of(1), 1L}, - {UInt32Value.of(1), 1L}, - {UInt64Value.of(1), 1L}, + {UInt32Value.of(1), UnsignedLong.valueOf(1L)}, + {UInt64Value.of(1), UnsignedLong.valueOf(1L)}, {BytesValue.of(ByteString.copyFromUtf8("test")), ByteString.copyFromUtf8("test")}, }); } From 2e97ede352ebeee5c3a41616b47e05a036ad10c4 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Wed, 21 Aug 2024 11:40:33 -0700 Subject: [PATCH 184/486] Add an option to prevent breaking apart a comprehension in CSE PiperOrigin-RevId: 665966630 --- .../optimizers/SubexpressionOptimizer.java | 68 +- .../SubexpressionOptimizerBaselineTest.java | 3 + .../SubexpressionOptimizerTest.java | 20 + ...old_before_subexpression_unparsed.baseline | 44 + ..._comprehension_structure_retained.baseline | 3422 +++++++++++++++++ .../resources/subexpression_unparsed.baseline | 44 + 6 files changed, 3600 insertions(+), 1 deletion(-) create mode 100644 optimizer/src/test/resources/subexpression_ast_block_common_subexpr_comprehension_structure_retained.baseline diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java index e6c327915..293481d8f 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java @@ -551,7 +551,51 @@ private boolean canEliminate( && !(navigableExpr.getKind().equals(Kind.LIST) && navigableExpr.expr().list().elements().isEmpty()) && containsEliminableFunctionOnly(navigableExpr) - && !ineligibleExprs.contains(navigableExpr.expr()); + && !ineligibleExprs.contains(navigableExpr.expr()) + && containsComprehensionIdentInSubexpr(navigableExpr); + } + + private boolean containsComprehensionIdentInSubexpr(CelNavigableMutableExpr navExpr) { + if (!cseOptions.retainComprehensionStructure()) { + return true; + } + + if (navExpr.getKind().equals(Kind.COMPREHENSION)) { + return true; + } + + ImmutableList comprehensionIdents = + navExpr + .allNodes() + .filter( + node -> + node.getKind().equals(Kind.IDENT) + && (node.expr() + .ident() + .name() + .startsWith(MANGLED_COMPREHENSION_ITER_VAR_PREFIX) + || node.expr() + .ident() + .name() + .startsWith(MANGLED_COMPREHENSION_ACCU_VAR_PREFIX))) + .collect(toImmutableList()); + + if (comprehensionIdents.isEmpty()) { + return true; + } + + for (CelNavigableMutableExpr ident : comprehensionIdents) { + CelNavigableMutableExpr parent = ident.parent().orElse(null); + while (parent != null) { + if (parent.getKind().equals(Kind.COMPREHENSION)) { + return false; + } + + parent = parent.parent().orElse(null); + } + } + + return true; } /** @@ -628,6 +672,8 @@ public abstract static class SubexpressionOptimizerOptions { public abstract boolean enableCelBlock(); + public abstract boolean retainComprehensionStructure(); + public abstract int subexpressionMaxRecursionDepth(); public abstract ImmutableSet eliminableFunctions(); @@ -684,6 +730,25 @@ public abstract static class Builder { */ public abstract Builder subexpressionMaxRecursionDepth(int value); + /** + * If configured true, SubexpressionOptimizer will not break apart a subexpression containing + * a comprehension's iter_var and accu_var without the surrounding comprehension. + * + *

An example expression {@code ['foo'].map(x, [x+x]) + ['foo'].map(x, [x+x, x+x])} is + * optimized as (note the common subexpr x+x that leverage the iteration variable): + * + *

+       *   Disabled: {@code cel.@block([["foo"], @it0 + @it0], @index0.map(@it0, [@index1])
+       *       + @index0.map(@it0, [@index1, @index1]))}
+       *   Enabled: {@code cel.@block([["foo"]], @index0.map(@it0, [@it0 + @it0])
+       *       + @index0.map(@it0, [@it0 + @it0, @it0 + @it0]))}
+       *  
+ * + * If targeting CEL-Java for the runtime, the recommended setting is to + * leave this disabled for maximal optimization efficiency. + */ + public abstract Builder retainComprehensionStructure(boolean value); + abstract ImmutableSet.Builder eliminableFunctionsBuilder(); /** @@ -718,6 +783,7 @@ public static Builder newBuilder() { .iterationLimit(500) .populateMacroCalls(false) .enableCelBlock(false) + .retainComprehensionStructure(false) .subexpressionMaxRecursionDepth(0); } diff --git a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerBaselineTest.java b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerBaselineTest.java index 2cb3df813..e2035be1b 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerBaselineTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerBaselineTest.java @@ -71,6 +71,7 @@ public class SubexpressionOptimizerBaselineTest extends BaselineTestCase { private static final SubexpressionOptimizerOptions OPTIMIZER_COMMON_OPTIONS = SubexpressionOptimizerOptions.newBuilder() + .retainComprehensionStructure(false) .populateMacroCalls(true) .enableCelBlock(true) .addEliminableFunctions("pure_custom_func") @@ -352,6 +353,8 @@ private static CelOptimizer newCseOptimizer(Cel cel, SubexpressionOptimizerOptio private enum CseTestOptimizer { CASCADED_BINDS(OPTIMIZER_COMMON_OPTIONS.toBuilder().enableCelBlock(false).build()), BLOCK_COMMON_SUBEXPR_ONLY(OPTIMIZER_COMMON_OPTIONS), + BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED( + OPTIMIZER_COMMON_OPTIONS.toBuilder().retainComprehensionStructure(true).build()), BLOCK_RECURSION_DEPTH_1( OPTIMIZER_COMMON_OPTIONS.toBuilder().subexpressionMaxRecursionDepth(1).build()), BLOCK_RECURSION_DEPTH_2( diff --git a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java index f4cec706d..3febca67c 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java @@ -201,6 +201,26 @@ public void cse_withCelBlock_noop(@TestParameter CseNoOpTestCase testCase) throw assertThat(CEL_UNPARSER.unparse(optimizedAst)).isEqualTo(testCase.source); } + @Test + public void cse_withComprehensionStructureRetained() throws Exception { + CelAbstractSyntaxTree ast = + CEL.compile("['foo'].map(x, [x+x]) + ['foo'].map(x, [x+x, x+x])").getAst(); + CelOptimizer celOptimizer = + newCseOptimizer( + SubexpressionOptimizerOptions.newBuilder() + .populateMacroCalls(true) + .enableCelBlock(true) + .retainComprehensionStructure(true) + .build()); + + CelAbstractSyntaxTree optimizedAst = celOptimizer.optimize(ast); + + assertThat(CEL_UNPARSER.unparse(optimizedAst)) + .isEqualTo( + "cel.@block([[\"foo\"]], @index0.map(@it:0:0, [@it:0:0 + @it:0:0]) +" + + " @index0.map(@it:0:0, [@it:0:0 + @it:0:0, @it:0:0 + @it:0:0]))"); + } + @Test public void cse_applyConstFoldingAfter() throws Exception { CelAbstractSyntaxTree ast = diff --git a/optimizer/src/test/resources/constfold_before_subexpression_unparsed.baseline b/optimizer/src/test/resources/constfold_before_subexpression_unparsed.baseline index 7324d1716..54207adf1 100644 --- a/optimizer/src/test/resources/constfold_before_subexpression_unparsed.baseline +++ b/optimizer/src/test/resources/constfold_before_subexpression_unparsed.baseline @@ -4,6 +4,7 @@ Source: size([1,2]) + size([1,2]) + 1 == 5 Result: true [CASCADED_BINDS]: true [BLOCK_COMMON_SUBEXPR_ONLY]: true +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: true [BLOCK_RECURSION_DEPTH_1]: true [BLOCK_RECURSION_DEPTH_2]: true [BLOCK_RECURSION_DEPTH_3]: true @@ -20,6 +21,7 @@ Source: 2 + size([1,2]) + size([1,2]) + 1 == 7 Result: true [CASCADED_BINDS]: true [BLOCK_COMMON_SUBEXPR_ONLY]: true +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: true [BLOCK_RECURSION_DEPTH_1]: true [BLOCK_RECURSION_DEPTH_2]: true [BLOCK_RECURSION_DEPTH_3]: true @@ -36,6 +38,7 @@ Source: size([0]) + size([0]) + size([1,2]) + size([1,2]) == 6 Result: true [CASCADED_BINDS]: true [BLOCK_COMMON_SUBEXPR_ONLY]: true +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: true [BLOCK_RECURSION_DEPTH_1]: true [BLOCK_RECURSION_DEPTH_2]: true [BLOCK_RECURSION_DEPTH_3]: true @@ -52,6 +55,7 @@ Source: 5 + size([0]) + size([0]) + size([1,2]) + size([1,2]) + size([1,2,3]) + Result: true [CASCADED_BINDS]: true [BLOCK_COMMON_SUBEXPR_ONLY]: true +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: true [BLOCK_RECURSION_DEPTH_1]: true [BLOCK_RECURSION_DEPTH_2]: true [BLOCK_RECURSION_DEPTH_3]: true @@ -68,6 +72,7 @@ Source: timestamp(int(timestamp(1000000000))).getFullYear() + timestamp(int(time Result: true [CASCADED_BINDS]: true [BLOCK_COMMON_SUBEXPR_ONLY]: true +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: true [BLOCK_RECURSION_DEPTH_1]: true [BLOCK_RECURSION_DEPTH_2]: true [BLOCK_RECURSION_DEPTH_3]: true @@ -84,6 +89,7 @@ Source: {"a": 2}["a"] + {"a": 2}["a"] * {"a": 2}["a"] == 6 Result: true [CASCADED_BINDS]: true [BLOCK_COMMON_SUBEXPR_ONLY]: true +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: true [BLOCK_RECURSION_DEPTH_1]: true [BLOCK_RECURSION_DEPTH_2]: true [BLOCK_RECURSION_DEPTH_3]: true @@ -100,6 +106,7 @@ Source: {'a': {'b': 1}, 'c': {'b': 1}, 'd': {'e': {'b': 1}}, 'e': {'e': {'b': 1} Result: {a={b=1}, c={b=1}, d={e={b=1}}, e={e={b=1}}} [CASCADED_BINDS]: cel.bind(@r0, {"b": 1}, cel.bind(@r1, {"e": @r0}, {"a": @r0, "c": @r0, "d": @r1, "e": @r1})) [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([{"b": 1}, {"e": @index0}], {"a": @index0, "c": @index0, "d": @index1, "e": @index1}) +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: cel.@block([{"b": 1}, {"e": @index0}], {"a": @index0, "c": @index0, "d": @index1, "e": @index1}) [BLOCK_RECURSION_DEPTH_1]: cel.@block([{"b": 1}, {"e": @index0}], {"a": @index0, "c": @index0, "d": @index1, "e": @index1}) [BLOCK_RECURSION_DEPTH_2]: cel.@block([{"e": {"b": 1}}, {"b": 1}], {"a": @index1, "c": @index1, "d": @index0, "e": @index0}) [BLOCK_RECURSION_DEPTH_3]: cel.@block([{"e": {"b": 1}}, {"b": 1}], {"a": @index1, "c": @index1, "d": @index0, "e": @index0}) @@ -116,6 +123,7 @@ Source: [1, [1,2,3,4], 2, [1,2,3,4], 5, [1,2,3,4], 7, [[1,2], [1,2,3,4]], [1,2]] Result: [1, [1, 2, 3, 4], 2, [1, 2, 3, 4], 5, [1, 2, 3, 4], 7, [[1, 2], [1, 2, 3, 4]], [1, 2]] [CASCADED_BINDS]: cel.bind(@r0, [1, 2, 3, 4], cel.bind(@r1, [1, 2], [1, @r0, 2, @r0, 5, @r0, 7, [@r1, @r0], @r1])) [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([[1, 2, 3, 4], [1, 2]], [1, @index0, 2, @index0, 5, @index0, 7, [@index1, @index0], @index1]) +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: cel.@block([[1, 2, 3, 4], [1, 2]], [1, @index0, 2, @index0, 5, @index0, 7, [@index1, @index0], @index1]) [BLOCK_RECURSION_DEPTH_1]: cel.@block([[1, 2, 3, 4], [1, 2], [@index1, @index0]], [1, @index0, 2, @index0, 5, @index0, 7, @index2, @index1]) [BLOCK_RECURSION_DEPTH_2]: cel.@block([[1, 2, 3, 4], [1, 2]], [1, @index0, 2, @index0, 5, @index0, 7, [@index1, @index0], @index1]) [BLOCK_RECURSION_DEPTH_3]: cel.@block([[1, 2, 3, 4], [1, 2]], [1, @index0, 2, @index0, 5, @index0, 7, [@index1, @index0], @index1]) @@ -132,6 +140,7 @@ Source: msg.single_int64 + msg.single_int64 == 6 Result: true [CASCADED_BINDS]: cel.bind(@r0, msg.single_int64, @r0 + @r0) == 6 [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.single_int64], @index0 + @index0 == 6) +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: cel.@block([msg.single_int64], @index0 + @index0 == 6) [BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.single_int64, @index0 + @index0], @index1 == 6) [BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.single_int64], @index0 + @index0 == 6) [BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.single_int64], @index0 + @index0 == 6) @@ -148,6 +157,7 @@ Source: msg.oneof_type.payload.single_int64 + msg.oneof_type.payload.single_int3 Result: true [CASCADED_BINDS]: cel.bind(@r0, msg.oneof_type.payload, cel.bind(@r1, @r0.single_int64, @r1 + @r0.single_int32 + @r1) + msg.single_int64 + @r0.oneof_type.payload.single_int64) == 31 [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.oneof_type.payload, @index0.single_int64], @index1 + @index0.single_int32 + @index1 + msg.single_int64 + @index0.oneof_type.payload.single_int64 == 31) +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: cel.@block([msg.oneof_type.payload, @index0.single_int64], @index1 + @index0.single_int32 + @index1 + msg.single_int64 + @index0.oneof_type.payload.single_int64 == 31) [BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, @index1.single_int32, @index2 + @index3, @index4 + @index2, msg.single_int64, @index5 + @index6, @index1.oneof_type, @index8.payload, @index9.single_int64, @index7 + @index10], @index11 == 31) [BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type.payload, @index0.single_int64, @index1 + @index0.single_int32, @index2 + @index1 + msg.single_int64, @index0.oneof_type.payload, @index3 + @index4.single_int64], @index5 == 31) [BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type.payload.single_int64, msg.oneof_type.payload, @index0 + @index1.single_int32 + @index0, @index1.oneof_type.payload.single_int64, @index2 + msg.single_int64 + @index3], @index4 == 31) @@ -164,6 +174,7 @@ Source: true || msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.one Result: true [CASCADED_BINDS]: true [BLOCK_COMMON_SUBEXPR_ONLY]: true +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: true [BLOCK_RECURSION_DEPTH_1]: true [BLOCK_RECURSION_DEPTH_2]: true [BLOCK_RECURSION_DEPTH_3]: true @@ -180,6 +191,7 @@ Source: msg.oneof_type.payload.map_int32_int64[1] + msg.oneof_type.payload.map_i Result: true [CASCADED_BINDS]: cel.bind(@r0, msg.oneof_type.payload.map_int32_int64[1], @r0 + @r0 + @r0) == 15 [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.oneof_type.payload.map_int32_int64[1]], @index0 + @index0 + @index0 == 15) +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: cel.@block([msg.oneof_type.payload.map_int32_int64[1]], @index0 + @index0 + @index0 == 15) [BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_int32_int64, @index2[1], @index3 + @index3, @index4 + @index3], @index5 == 15) [BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type.payload, @index0.map_int32_int64[1], @index1 + @index1 + @index1], @index2 == 15) [BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type.payload.map_int32_int64, @index0[1]], @index1 + @index1 + @index1 == 15) @@ -196,6 +208,7 @@ Source: msg.oneof_type.payload.map_int32_int64[0] + msg.oneof_type.payload.map_i Result: true [CASCADED_BINDS]: cel.bind(@r0, msg.oneof_type.payload.map_int32_int64, @r0[0] + @r0[1] + @r0[2]) == 8 [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.oneof_type.payload.map_int32_int64], @index0[0] + @index0[1] + @index0[2] == 8) +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: cel.@block([msg.oneof_type.payload.map_int32_int64], @index0[0] + @index0[1] + @index0[2] == 8) [BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_int32_int64, @index2[0], @index2[1], @index3 + @index4, @index2[2], @index5 + @index6], @index7 == 8) [BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type.payload, @index0.map_int32_int64, @index1[0] + @index1[1], @index2 + @index1[2]], @index3 == 8) [BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type.payload.map_int32_int64, @index0[0] + @index0[1] + @index0[2]], @index1 == 8) @@ -212,6 +225,7 @@ Source: msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type. Result: 0 [CASCADED_BINDS]: msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload.single_int64 [BLOCK_COMMON_SUBEXPR_ONLY]: msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload.single_int64 +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload.single_int64 [BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.oneof_type, @index2.payload, @index3.oneof_type, @index4.payload, @index5.oneof_type, @index6.payload], @index7.single_int64) [BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type.payload, @index0.oneof_type.payload, @index1.oneof_type.payload, @index2.oneof_type.payload], @index3.single_int64) [BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type.payload.oneof_type, @index0.payload.oneof_type.payload], @index1.oneof_type.payload.single_int64) @@ -228,6 +242,7 @@ Source: (msg.single_int64 > 0 ? msg.single_int64 : 0) == 3 Result: true [CASCADED_BINDS]: cel.bind(@r0, msg.single_int64, (@r0 > 0) ? @r0 : 0) == 3 [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.single_int64], ((@index0 > 0) ? @index0 : 0) == 3) +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: cel.@block([msg.single_int64], ((@index0 > 0) ? @index0 : 0) == 3) [BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.single_int64, @index0 > 0, @index1 ? @index0 : 0], @index2 == 3) [BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.single_int64, (@index0 > 0) ? @index0 : 0], @index1 == 3) [BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.single_int64], ((@index0 > 0) ? @index0 : 0) == 3) @@ -244,6 +259,7 @@ Source: false ? false : (msg.single_int64) + ((msg.single_int64 + 1) * 2) == 11 Result: true [CASCADED_BINDS]: cel.bind(@r0, msg.single_int64, @r0 + (@r0 + 1) * 2) == 11 [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.single_int64], @index0 + (@index0 + 1) * 2 == 11) +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: cel.@block([msg.single_int64], @index0 + (@index0 + 1) * 2 == 11) [BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.single_int64, @index0 + 1, @index1 * 2, @index0 + @index2], @index3 == 11) [BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.single_int64, (@index0 + 1) * 2], @index0 + @index1 == 11) [BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.single_int64, @index0 + (@index0 + 1) * 2], @index1 == 11) @@ -260,6 +276,7 @@ Source: (msg.single_int64 > 0 ? (msg.single_int32 > 0 ? msg.single_int64 + msg.s Result: true [CASCADED_BINDS]: cel.bind(@r0, msg.single_int64, (@r0 > 0) ? cel.bind(@r1, msg.single_int32, (@r1 > 0) ? (@r0 + @r1) : 0) : 0) == 8 [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.single_int64, msg.single_int32], ((@index0 > 0) ? ((@index1 > 0) ? (@index0 + @index1) : 0) : 0) == 8) +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: cel.@block([msg.single_int64, msg.single_int32], ((@index0 > 0) ? ((@index1 > 0) ? (@index0 + @index1) : 0) : 0) == 8) [BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.single_int64, msg.single_int32, @index0 > 0, @index1 > 0, @index0 + @index1, @index3 ? @index4 : 0, @index2 ? @index5 : 0], @index6 == 8) [BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.single_int64, msg.single_int32, (@index1 > 0) ? (@index0 + @index1) : 0, (@index0 > 0) ? @index2 : 0], @index3 == 8) [BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.single_int64, msg.single_int32, (@index0 > 0) ? ((@index1 > 0) ? (@index0 + @index1) : 0) : 0], @index2 == 8) @@ -276,6 +293,7 @@ Source: size([[1].exists(i, i > 0)]) + size([[1].exists(j, j > 0)]) + size([[2]. Result: true [CASCADED_BINDS]: true [BLOCK_COMMON_SUBEXPR_ONLY]: true +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: true [BLOCK_RECURSION_DEPTH_1]: true [BLOCK_RECURSION_DEPTH_2]: true [BLOCK_RECURSION_DEPTH_3]: true @@ -292,6 +310,7 @@ Source: [[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == Result: true [CASCADED_BINDS]: true [BLOCK_COMMON_SUBEXPR_ONLY]: true +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: true [BLOCK_RECURSION_DEPTH_1]: true [BLOCK_RECURSION_DEPTH_2]: true [BLOCK_RECURSION_DEPTH_3]: true @@ -308,6 +327,7 @@ Source: [1].exists(i, i > 0) && [1].exists(j, j > 0) && [1].exists(k, k > 1) && Result: false [CASCADED_BINDS]: false [BLOCK_COMMON_SUBEXPR_ONLY]: false +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: false [BLOCK_RECURSION_DEPTH_1]: false [BLOCK_RECURSION_DEPTH_2]: false [BLOCK_RECURSION_DEPTH_3]: false @@ -324,6 +344,7 @@ Source: [1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [[2, 3, 4], [2, 3, 4], [2, 3, Result: true [CASCADED_BINDS]: true [BLOCK_COMMON_SUBEXPR_ONLY]: true +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: true [BLOCK_RECURSION_DEPTH_1]: true [BLOCK_RECURSION_DEPTH_2]: true [BLOCK_RECURSION_DEPTH_3]: true @@ -340,6 +361,7 @@ Source: [1, 2].map(y, [1, 2, 3].filter(x, x == y)) == [[1], [2]] Result: true [CASCADED_BINDS]: true [BLOCK_COMMON_SUBEXPR_ONLY]: true +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: true [BLOCK_RECURSION_DEPTH_1]: true [BLOCK_RECURSION_DEPTH_2]: true [BLOCK_RECURSION_DEPTH_3]: true @@ -356,6 +378,7 @@ Source: [1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [1,2,3].map(j, [1, 2, 3].map( Result: true [CASCADED_BINDS]: true [BLOCK_COMMON_SUBEXPR_ONLY]: true +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: true [BLOCK_RECURSION_DEPTH_1]: true [BLOCK_RECURSION_DEPTH_2]: true [BLOCK_RECURSION_DEPTH_3]: true @@ -372,6 +395,7 @@ Source: 1 in [1,2,3] && 2 in [1,2,3] && 3 in [3, [1,2,3]] && 1 in [1,2,3] Result: true [CASCADED_BINDS]: true [BLOCK_COMMON_SUBEXPR_ONLY]: true +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: true [BLOCK_RECURSION_DEPTH_1]: true [BLOCK_RECURSION_DEPTH_2]: true [BLOCK_RECURSION_DEPTH_3]: true @@ -388,6 +412,7 @@ Source: 2 in {'a': 1, 2: {true: false}, 3: {true: false}} Result: true [CASCADED_BINDS]: true [BLOCK_COMMON_SUBEXPR_ONLY]: true +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: true [BLOCK_RECURSION_DEPTH_1]: true [BLOCK_RECURSION_DEPTH_2]: true [BLOCK_RECURSION_DEPTH_3]: true @@ -404,6 +429,7 @@ Source: [1,2].map(i, [1, 2].map(i, [3,4])) == [[[3, 4], [3, 4]], [[3, 4], [3, 4] Result: true [CASCADED_BINDS]: true [BLOCK_COMMON_SUBEXPR_ONLY]: true +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: true [BLOCK_RECURSION_DEPTH_1]: true [BLOCK_RECURSION_DEPTH_2]: true [BLOCK_RECURSION_DEPTH_3]: true @@ -420,6 +446,7 @@ Source: [x - 1 > 3 ? x - 1 : 5].exists(x, x - 1 > 3) || x - 1 > 3 Result: true [CASCADED_BINDS]: cel.bind(@r0, x - 1, cel.bind(@r1, @r0 > 3, [@r1 ? @r0 : 5].exists(@it:0, @it:0 - 1 > 3) || @r1)) [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([x - 1, @index0 > 3], [@index1 ? @index0 : 5].exists(@it:0:0, @it:0:0 - 1 > 3) || @index1) +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: cel.@block([x - 1, @index0 > 3], [@index1 ? @index0 : 5].exists(@it:0:0, @it:0:0 - 1 > 3) || @index1) [BLOCK_RECURSION_DEPTH_1]: cel.@block([x - 1, @index0 > 3, @index1 ? @index0 : 5, [@index2], @it:0:0 - 1, @index4 > 3, @ac:0:0 || @index5], @index3.exists(@it:0:0, @index5) || @index1) [BLOCK_RECURSION_DEPTH_2]: cel.@block([x - 1 > 3, @index0 ? (x - 1) : 5, @it:0:0 - 1 > 3, [@index1], @ac:0:0 || @index2], @index3.exists(@it:0:0, @index2) || @index0) [BLOCK_RECURSION_DEPTH_3]: cel.@block([x - 1 > 3, [@index0 ? (x - 1) : 5], @ac:0:0 || @it:0:0 - 1 > 3, @index1.exists(@it:0:0, @it:0:0 - 1 > 3)], @index3 || @index0) @@ -436,6 +463,7 @@ Source: ["foo", "bar"].map(x, [x + x, x + x]).map(x, [x + x, x + x]) Result: [[[foofoo, foofoo, foofoo, foofoo], [foofoo, foofoo, foofoo, foofoo]], [[barbar, barbar, barbar, barbar], [barbar, barbar, barbar, barbar]]] [CASCADED_BINDS]: [cel.bind(@r0, ["foofoo", "foofoo", "foofoo", "foofoo"], [@r0, @r0]), cel.bind(@r1, ["barbar", "barbar", "barbar", "barbar"], [@r1, @r1])] [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([["foofoo", "foofoo", "foofoo", "foofoo"], ["barbar", "barbar", "barbar", "barbar"]], [[@index0, @index0], [@index1, @index1]]) +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: cel.@block([["foofoo", "foofoo", "foofoo", "foofoo"], ["barbar", "barbar", "barbar", "barbar"]], [[@index0, @index0], [@index1, @index1]]) [BLOCK_RECURSION_DEPTH_1]: cel.@block([["foofoo", "foofoo", "foofoo", "foofoo"], ["barbar", "barbar", "barbar", "barbar"], [@index0, @index0], [@index1, @index1]], [@index2, @index3]) [BLOCK_RECURSION_DEPTH_2]: cel.@block([["foofoo", "foofoo", "foofoo", "foofoo"], ["barbar", "barbar", "barbar", "barbar"]], [[@index0, @index0], [@index1, @index1]]) [BLOCK_RECURSION_DEPTH_3]: cel.@block([["foofoo", "foofoo", "foofoo", "foofoo"], ["barbar", "barbar", "barbar", "barbar"]], [[@index0, @index0], [@index1, @index1]]) @@ -452,6 +480,7 @@ Source: has({'a': true}.a) && {'a':true}['a'] Result: true [CASCADED_BINDS]: true [BLOCK_COMMON_SUBEXPR_ONLY]: true +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: true [BLOCK_RECURSION_DEPTH_1]: true [BLOCK_RECURSION_DEPTH_2]: true [BLOCK_RECURSION_DEPTH_3]: true @@ -468,6 +497,7 @@ Source: has({'a': true}.a) && has({'a': true}.a) Result: true [CASCADED_BINDS]: true [BLOCK_COMMON_SUBEXPR_ONLY]: true +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: true [BLOCK_RECURSION_DEPTH_1]: true [BLOCK_RECURSION_DEPTH_2]: true [BLOCK_RECURSION_DEPTH_3]: true @@ -484,6 +514,7 @@ Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : 0) Result: true [CASCADED_BINDS]: cel.bind(@r0, msg.oneof_type, has(@r0.payload) ? @r0.payload.single_int64 : 0) == 10 [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.oneof_type], (has(@index0.payload) ? @index0.payload.single_int64 : 0) == 10) +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: cel.@block([msg.oneof_type], (has(@index0.payload) ? @index0.payload.single_int64 : 0) == 10) [BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, has(@index0.payload), @index0.payload, @index2.single_int64, @index1 ? @index3 : 0], @index4 == 10) [BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type, @index0.payload.single_int64, has(@index0.payload) ? @index1 : 0], @index2 == 10) [BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type, has(@index0.payload) ? @index0.payload.single_int64 : 0], @index1 == 10) @@ -500,6 +531,7 @@ Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : msg Result: true [CASCADED_BINDS]: cel.bind(@r0, msg.oneof_type, cel.bind(@r1, @r0.payload.single_int64, has(@r0.payload) ? @r1 : (@r1 * 0))) == 10 [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.oneof_type, @index0.payload.single_int64], (has(@index0.payload) ? @index1 : (@index1 * 0)) == 10) +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: cel.@block([msg.oneof_type, @index0.payload.single_int64], (has(@index0.payload) ? @index1 : (@index1 * 0)) == 10) [BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, has(@index0.payload), @index2 * 0, @index3 ? @index2 : @index4], @index5 == 10) [BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type.payload, @index0.single_int64, has(msg.oneof_type.payload), @index2 ? @index1 : (@index1 * 0)], @index3 == 10) [BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type.payload.single_int64, has(msg.oneof_type.payload) ? @index0 : (@index0 * 0)], @index1 == 10) @@ -516,6 +548,7 @@ Source: (has(msg.oneof_type.payload.single_int64) ? msg.oneof_type.payload.singl Result: true [CASCADED_BINDS]: cel.bind(@r0, msg.oneof_type.payload, cel.bind(@r1, @r0.single_int64, has(@r0.single_int64) ? @r1 : (@r1 * 0))) == 10 [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.oneof_type.payload, @index0.single_int64], (has(@index0.single_int64) ? @index1 : (@index1 * 0)) == 10) +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: cel.@block([msg.oneof_type.payload, @index0.single_int64], (has(@index0.single_int64) ? @index1 : (@index1 * 0)) == 10) [BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, has(@index1.single_int64), @index2 * 0, @index3 ? @index2 : @index4], @index5 == 10) [BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type.payload, @index0.single_int64, has(@index0.single_int64) ? @index1 : (@index1 * 0)], @index2 == 10) [BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type.payload.single_int64, has(msg.oneof_type.payload.single_int64)], (@index1 ? @index0 : (@index0 * 0)) == 10) @@ -532,6 +565,7 @@ Source: (has(msg.oneof_type) && has(msg.oneof_type.payload) && has(msg.oneof_typ Result: true [CASCADED_BINDS]: cel.bind(@r0, msg.oneof_type, cel.bind(@r1, @r0.payload, (has(msg.oneof_type) && has(@r0.payload) && has(@r1.single_int64)) ? cel.bind(@r2, @r1.map_string_string, (has(@r1.map_string_string) && has(@r2.key)) ? (@r2.key == "A") : false) : false)) [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_string_string], (has(msg.oneof_type) && has(@index0.payload) && has(@index1.single_int64)) ? ((has(@index1.map_string_string) && has(@index2.key)) ? (@index2.key == "A") : false) : false) +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_string_string], (has(msg.oneof_type) && has(@index0.payload) && has(@index1.single_int64)) ? ((has(@index1.map_string_string) && has(@index2.key)) ? (@index2.key == "A") : false) : false) [BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_string_string, has(msg.oneof_type), has(@index0.payload), @index3 && @index4, has(@index1.single_int64), @index5 && @index6, has(@index1.map_string_string), has(@index2.key), @index8 && @index9, @index2.key, @index11 == "A", @index10 ? @index12 : false], @index7 ? @index13 : false) [BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type.payload, @index0.map_string_string, has(msg.oneof_type.payload), has(msg.oneof_type) && @index2, @index3 && has(@index0.single_int64), has(@index0.map_string_string) && has(@index1.key), @index1.key == "A"], @index4 ? (@index5 ? @index6 : false) : false) [BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type.payload.map_string_string, msg.oneof_type.payload, has(msg.oneof_type) && has(msg.oneof_type.payload), (has(@index1.map_string_string) && has(@index0.key)) ? (@index0.key == "A") : false], (@index2 && has(@index1.single_int64)) ? @index3 : false) @@ -548,6 +582,7 @@ Source: [10, ?optional.none(), [?optional.none(), ?opt_x], [?optional.none(), ?o Result: true [CASCADED_BINDS]: cel.bind(@r0, [?opt_x], [10, @r0, @r0]) == cel.bind(@r1, [5], [10, @r1, @r1]) [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([[?opt_x], [5]], [10, @index0, @index0] == [10, @index1, @index1]) +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: cel.@block([[?opt_x], [5]], [10, @index0, @index0] == [10, @index1, @index1]) [BLOCK_RECURSION_DEPTH_1]: cel.@block([[?opt_x], [5], [10, @index0, @index0], [10, @index1, @index1]], @index2 == @index3) [BLOCK_RECURSION_DEPTH_2]: cel.@block([[?opt_x], [5]], [10, @index0, @index0] == [10, @index1, @index1]) [BLOCK_RECURSION_DEPTH_3]: cel.@block([[?opt_x], [5]], [10, @index0, @index0] == [10, @index1, @index1]) @@ -564,6 +599,7 @@ Source: {?'hello': optional.of('hello')}['hello'] + {?'hello': optional.of('hell Result: true [CASCADED_BINDS]: true [BLOCK_COMMON_SUBEXPR_ONLY]: true +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: true [BLOCK_RECURSION_DEPTH_1]: true [BLOCK_RECURSION_DEPTH_2]: true [BLOCK_RECURSION_DEPTH_3]: true @@ -580,6 +616,7 @@ Source: {?'key': optional.of('test')}[?'bogus'].or({'key': 'test'}[?'bogus']).or Result: true [CASCADED_BINDS]: true [BLOCK_COMMON_SUBEXPR_ONLY]: true +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: true [BLOCK_RECURSION_DEPTH_1]: true [BLOCK_RECURSION_DEPTH_2]: true [BLOCK_RECURSION_DEPTH_3]: true @@ -596,6 +633,7 @@ Source: TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: o Result: true [CASCADED_BINDS]: true [BLOCK_COMMON_SUBEXPR_ONLY]: true +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: true [BLOCK_RECURSION_DEPTH_1]: true [BLOCK_RECURSION_DEPTH_2]: true [BLOCK_RECURSION_DEPTH_3]: true @@ -612,6 +650,7 @@ Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('h' + 'e' + 'l' + 'l' + Result: true [CASCADED_BINDS]: true [BLOCK_COMMON_SUBEXPR_ONLY]: true +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: true [BLOCK_RECURSION_DEPTH_1]: true [BLOCK_RECURSION_DEPTH_2]: true [BLOCK_RECURSION_DEPTH_3]: true @@ -628,6 +667,7 @@ Source: 'hello world'.matches('h' + 'e' + 'l' + 'l' + 'o') Result: true [CASCADED_BINDS]: true [BLOCK_COMMON_SUBEXPR_ONLY]: true +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: true [BLOCK_RECURSION_DEPTH_1]: true [BLOCK_RECURSION_DEPTH_2]: true [BLOCK_RECURSION_DEPTH_3]: true @@ -644,6 +684,7 @@ Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('hello') Result: true [CASCADED_BINDS]: true [BLOCK_COMMON_SUBEXPR_ONLY]: true +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: true [BLOCK_RECURSION_DEPTH_1]: true [BLOCK_RECURSION_DEPTH_2]: true [BLOCK_RECURSION_DEPTH_3]: true @@ -660,6 +701,7 @@ Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('w' + 'o' + 'r' + 'l' + Result: true [CASCADED_BINDS]: true [BLOCK_COMMON_SUBEXPR_ONLY]: true +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: true [BLOCK_RECURSION_DEPTH_1]: true [BLOCK_RECURSION_DEPTH_2]: true [BLOCK_RECURSION_DEPTH_3]: true @@ -676,6 +718,7 @@ Source: non_pure_custom_func(msg.oneof_type.payload.single_int64) + non_pure_cus Result: 31 [CASCADED_BINDS]: cel.bind(@r0, msg.oneof_type.payload, cel.bind(@r1, @r0.single_int64, non_pure_custom_func(@r1) + non_pure_custom_func(@r0.single_int32) + non_pure_custom_func(@r1))) + non_pure_custom_func(msg.single_int64) [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.oneof_type.payload, @index0.single_int64], non_pure_custom_func(@index1) + non_pure_custom_func(@index0.single_int32) + non_pure_custom_func(@index1) + non_pure_custom_func(msg.single_int64)) +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: cel.@block([msg.oneof_type.payload, @index0.single_int64], non_pure_custom_func(@index1) + non_pure_custom_func(@index0.single_int32) + non_pure_custom_func(@index1) + non_pure_custom_func(msg.single_int64)) [BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64], non_pure_custom_func(@index2) + non_pure_custom_func(@index1.single_int32) + non_pure_custom_func(@index2) + non_pure_custom_func(msg.single_int64)) [BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type.payload, @index0.single_int64], non_pure_custom_func(@index1) + non_pure_custom_func(@index0.single_int32) + non_pure_custom_func(@index1) + non_pure_custom_func(msg.single_int64)) [BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type.payload.single_int64], non_pure_custom_func(@index0) + non_pure_custom_func(msg.oneof_type.payload.single_int32) + non_pure_custom_func(@index0) + non_pure_custom_func(msg.single_int64)) @@ -692,6 +735,7 @@ Source: pure_custom_func(msg.oneof_type.payload.single_int64) + pure_custom_func Result: 31 [CASCADED_BINDS]: cel.bind(@r0, msg.oneof_type.payload, cel.bind(@r1, pure_custom_func(@r0.single_int64), @r1 + pure_custom_func(@r0.single_int32) + @r1)) + pure_custom_func(msg.single_int64) [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.oneof_type.payload, pure_custom_func(@index0.single_int64)], @index1 + pure_custom_func(@index0.single_int32) + @index1 + pure_custom_func(msg.single_int64)) +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: cel.@block([msg.oneof_type.payload, pure_custom_func(@index0.single_int64)], @index1 + pure_custom_func(@index0.single_int32) + @index1 + pure_custom_func(msg.single_int64)) [BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, pure_custom_func(@index2), @index1.single_int32, pure_custom_func(@index4), @index3 + @index5, @index6 + @index3, msg.single_int64, pure_custom_func(@index8)], @index7 + @index9) [BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type.payload, pure_custom_func(@index0.single_int64), pure_custom_func(@index0.single_int32), @index1 + @index2 + @index1, pure_custom_func(msg.single_int64)], @index3 + @index4) [BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type.payload.single_int64, pure_custom_func(@index0), msg.oneof_type.payload.single_int32, @index1 + pure_custom_func(@index2) + @index1], @index3 + pure_custom_func(msg.single_int64)) diff --git a/optimizer/src/test/resources/subexpression_ast_block_common_subexpr_comprehension_structure_retained.baseline b/optimizer/src/test/resources/subexpression_ast_block_common_subexpr_comprehension_structure_retained.baseline new file mode 100644 index 000000000..61dc23350 --- /dev/null +++ b/optimizer/src/test/resources/subexpression_ast_block_common_subexpr_comprehension_structure_retained.baseline @@ -0,0 +1,3422 @@ +Test case: SIZE_1 +Source: size([1,2]) + size([1,2]) + 1 == 5 +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + CALL [3] { + function: size + args: { + LIST [4] { + elements: { + CONSTANT [5] { value: 1 } + CONSTANT [6] { value: 2 } + } + } + } + } + } + } + CALL [7] { + function: _==_ + args: { + CALL [8] { + function: _+_ + args: { + CALL [9] { + function: _+_ + args: { + IDENT [10] { + name: @index0 + } + IDENT [11] { + name: @index0 + } + } + } + CONSTANT [12] { value: 1 } + } + } + CONSTANT [13] { value: 5 } + } + } + } +} +Test case: SIZE_2 +Source: 2 + size([1,2]) + size([1,2]) + 1 == 7 +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + CALL [3] { + function: size + args: { + LIST [4] { + elements: { + CONSTANT [5] { value: 1 } + CONSTANT [6] { value: 2 } + } + } + } + } + } + } + CALL [7] { + function: _==_ + args: { + CALL [8] { + function: _+_ + args: { + CALL [9] { + function: _+_ + args: { + CALL [10] { + function: _+_ + args: { + CONSTANT [11] { value: 2 } + IDENT [12] { + name: @index0 + } + } + } + IDENT [13] { + name: @index0 + } + } + } + CONSTANT [14] { value: 1 } + } + } + CONSTANT [15] { value: 7 } + } + } + } +} +Test case: SIZE_3 +Source: size([0]) + size([0]) + size([1,2]) + size([1,2]) == 6 +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + CALL [3] { + function: size + args: { + LIST [4] { + elements: { + CONSTANT [5] { value: 0 } + } + } + } + } + CALL [6] { + function: size + args: { + LIST [7] { + elements: { + CONSTANT [8] { value: 1 } + CONSTANT [9] { value: 2 } + } + } + } + } + } + } + CALL [10] { + function: _==_ + args: { + CALL [11] { + function: _+_ + args: { + CALL [12] { + function: _+_ + args: { + CALL [13] { + function: _+_ + args: { + IDENT [14] { + name: @index0 + } + IDENT [15] { + name: @index0 + } + } + } + IDENT [16] { + name: @index1 + } + } + } + IDENT [17] { + name: @index1 + } + } + } + CONSTANT [18] { value: 6 } + } + } + } +} +Test case: SIZE_4 +Source: 5 + size([0]) + size([0]) + size([1,2]) + size([1,2]) + size([1,2,3]) + size([1,2,3]) == 17 +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + CALL [3] { + function: size + args: { + LIST [4] { + elements: { + CONSTANT [5] { value: 0 } + } + } + } + } + CALL [6] { + function: size + args: { + LIST [7] { + elements: { + CONSTANT [8] { value: 1 } + CONSTANT [9] { value: 2 } + } + } + } + } + CALL [10] { + function: size + args: { + LIST [11] { + elements: { + CONSTANT [12] { value: 1 } + CONSTANT [13] { value: 2 } + CONSTANT [14] { value: 3 } + } + } + } + } + } + } + CALL [15] { + function: _==_ + args: { + CALL [16] { + function: _+_ + args: { + CALL [17] { + function: _+_ + args: { + CALL [18] { + function: _+_ + args: { + CALL [19] { + function: _+_ + args: { + CALL [20] { + function: _+_ + args: { + CALL [21] { + function: _+_ + args: { + CONSTANT [22] { value: 5 } + IDENT [23] { + name: @index0 + } + } + } + IDENT [24] { + name: @index0 + } + } + } + IDENT [25] { + name: @index1 + } + } + } + IDENT [26] { + name: @index1 + } + } + } + IDENT [27] { + name: @index2 + } + } + } + IDENT [28] { + name: @index2 + } + } + } + CONSTANT [29] { value: 17 } + } + } + } +} +Test case: TIMESTAMP +Source: timestamp(int(timestamp(1000000000))).getFullYear() + timestamp(int(timestamp(75))).getFullYear() + timestamp(int(timestamp(50))).getFullYear() + timestamp(int(timestamp(1000000000))).getFullYear() + timestamp(int(timestamp(50))).getSeconds() + timestamp(int(timestamp(200))).getFullYear() + timestamp(int(timestamp(200))).getFullYear() + timestamp(int(timestamp(75))).getMinutes() + timestamp(int(timestamp(1000000000))).getFullYear() == 13934 +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + CALL [3] { + function: getFullYear + target: { + CALL [4] { + function: timestamp + args: { + CALL [5] { + function: int + args: { + CALL [6] { + function: timestamp + args: { + CONSTANT [7] { value: 1000000000 } + } + } + } + } + } + } + } + args: { + } + } + CALL [8] { + function: timestamp + args: { + CALL [9] { + function: int + args: { + CALL [10] { + function: timestamp + args: { + CONSTANT [11] { value: 50 } + } + } + } + } + } + } + CALL [12] { + function: getFullYear + target: { + CALL [13] { + function: timestamp + args: { + CALL [14] { + function: int + args: { + CALL [15] { + function: timestamp + args: { + CONSTANT [16] { value: 200 } + } + } + } + } + } + } + } + args: { + } + } + CALL [17] { + function: timestamp + args: { + CALL [18] { + function: int + args: { + CALL [19] { + function: timestamp + args: { + CONSTANT [20] { value: 75 } + } + } + } + } + } + } + } + } + CALL [21] { + function: _==_ + args: { + CALL [22] { + function: _+_ + args: { + CALL [23] { + function: _+_ + args: { + CALL [24] { + function: _+_ + args: { + CALL [25] { + function: _+_ + args: { + CALL [26] { + function: _+_ + args: { + CALL [27] { + function: _+_ + args: { + CALL [28] { + function: _+_ + args: { + CALL [29] { + function: _+_ + args: { + IDENT [30] { + name: @index0 + } + CALL [31] { + function: getFullYear + target: { + IDENT [32] { + name: @index3 + } + } + args: { + } + } + } + } + CALL [33] { + function: getFullYear + target: { + IDENT [34] { + name: @index1 + } + } + args: { + } + } + } + } + IDENT [35] { + name: @index0 + } + } + } + CALL [36] { + function: getSeconds + target: { + IDENT [37] { + name: @index1 + } + } + args: { + } + } + } + } + IDENT [38] { + name: @index2 + } + } + } + IDENT [39] { + name: @index2 + } + } + } + CALL [40] { + function: getMinutes + target: { + IDENT [41] { + name: @index3 + } + } + args: { + } + } + } + } + IDENT [42] { + name: @index0 + } + } + } + CONSTANT [43] { value: 13934 } + } + } + } +} +Test case: MAP_INDEX +Source: {"a": 2}["a"] + {"a": 2}["a"] * {"a": 2}["a"] == 6 +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + CALL [3] { + function: _[_] + args: { + MAP [4] { + MAP_ENTRY [5] { + key: { + CONSTANT [6] { value: "a" } + } + value: { + CONSTANT [7] { value: 2 } + } + } + } + CONSTANT [8] { value: "a" } + } + } + } + } + CALL [9] { + function: _==_ + args: { + CALL [10] { + function: _+_ + args: { + IDENT [11] { + name: @index0 + } + CALL [12] { + function: _*_ + args: { + IDENT [13] { + name: @index0 + } + IDENT [14] { + name: @index0 + } + } + } + } + } + CONSTANT [15] { value: 6 } + } + } + } +} +Test case: NESTED_MAP_CONSTRUCTION +Source: {'a': {'b': 1}, 'c': {'b': 1}, 'd': {'e': {'b': 1}}, 'e': {'e': {'b': 1}}} +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: "b" } + } + value: { + CONSTANT [6] { value: 1 } + } + } + } + MAP [7] { + MAP_ENTRY [8] { + key: { + CONSTANT [9] { value: "e" } + } + value: { + IDENT [10] { + name: @index0 + } + } + } + } + } + } + MAP [11] { + MAP_ENTRY [12] { + key: { + CONSTANT [13] { value: "a" } + } + value: { + IDENT [14] { + name: @index0 + } + } + } + MAP_ENTRY [15] { + key: { + CONSTANT [16] { value: "c" } + } + value: { + IDENT [17] { + name: @index0 + } + } + } + MAP_ENTRY [18] { + key: { + CONSTANT [19] { value: "d" } + } + value: { + IDENT [20] { + name: @index1 + } + } + } + MAP_ENTRY [21] { + key: { + CONSTANT [22] { value: "e" } + } + value: { + IDENT [23] { + name: @index1 + } + } + } + } + } +} +Test case: NESTED_LIST_CONSTRUCTION +Source: [1, [1,2,3,4], 2, [1,2,3,4], 5, [1,2,3,4], 7, [[1,2], [1,2,3,4]], [1,2]] +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + CONSTANT [6] { value: 3 } + CONSTANT [7] { value: 4 } + } + } + LIST [8] { + elements: { + CONSTANT [9] { value: 1 } + CONSTANT [10] { value: 2 } + } + } + } + } + LIST [11] { + elements: { + CONSTANT [12] { value: 1 } + IDENT [13] { + name: @index0 + } + CONSTANT [14] { value: 2 } + IDENT [15] { + name: @index0 + } + CONSTANT [16] { value: 5 } + IDENT [17] { + name: @index0 + } + CONSTANT [18] { value: 7 } + LIST [19] { + elements: { + IDENT [20] { + name: @index1 + } + IDENT [21] { + name: @index0 + } + } + } + IDENT [22] { + name: @index1 + } + } + } + } +} +Test case: SELECT +Source: msg.single_int64 + msg.single_int64 == 6 +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.single_int64 + } + } + } + CALL [5] { + function: _==_ + args: { + CALL [6] { + function: _+_ + args: { + IDENT [7] { + name: @index0 + } + IDENT [8] { + name: @index0 + } + } + } + CONSTANT [9] { value: 6 } + } + } + } +} +Test case: SELECT_NESTED_1 +Source: msg.oneof_type.payload.single_int64 + msg.oneof_type.payload.single_int32 + msg.oneof_type.payload.single_int64 + msg.single_int64 + msg.oneof_type.payload.oneof_type.payload.single_int64 == 31 +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + SELECT [3] { + SELECT [4] { + IDENT [5] { + name: msg + }.oneof_type + }.payload + } + SELECT [6] { + IDENT [7] { + name: @index0 + }.single_int64 + } + } + } + CALL [8] { + function: _==_ + args: { + CALL [9] { + function: _+_ + args: { + CALL [10] { + function: _+_ + args: { + CALL [11] { + function: _+_ + args: { + CALL [12] { + function: _+_ + args: { + IDENT [13] { + name: @index1 + } + SELECT [14] { + IDENT [15] { + name: @index0 + }.single_int32 + } + } + } + IDENT [16] { + name: @index1 + } + } + } + SELECT [17] { + IDENT [18] { + name: msg + }.single_int64 + } + } + } + SELECT [19] { + SELECT [20] { + SELECT [21] { + IDENT [22] { + name: @index0 + }.oneof_type + }.payload + }.single_int64 + } + } + } + CONSTANT [23] { value: 31 } + } + } + } +} +Test case: SELECT_NESTED_2 +Source: true || msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload.single_bool || msg.oneof_type.payload.oneof_type.payload.oneof_type.child.child.payload.single_bool +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + SELECT [3] { + SELECT [4] { + SELECT [5] { + SELECT [6] { + SELECT [7] { + IDENT [8] { + name: msg + }.oneof_type + }.payload + }.oneof_type + }.payload + }.oneof_type + } + } + } + CALL [9] { + function: _||_ + args: { + CALL [10] { + function: _||_ + args: { + CONSTANT [11] { value: true } + SELECT [12] { + SELECT [13] { + SELECT [14] { + SELECT [15] { + IDENT [16] { + name: @index0 + }.payload + }.oneof_type + }.payload + }.single_bool + } + } + } + SELECT [17] { + SELECT [18] { + SELECT [19] { + SELECT [20] { + IDENT [21] { + name: @index0 + }.child + }.child + }.payload + }.single_bool + } + } + } + } +} +Test case: SELECT_NESTED_MESSAGE_MAP_INDEX_1 +Source: msg.oneof_type.payload.map_int32_int64[1] + msg.oneof_type.payload.map_int32_int64[1] + msg.oneof_type.payload.map_int32_int64[1] == 15 +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + CALL [3] { + function: _[_] + args: { + SELECT [4] { + SELECT [5] { + SELECT [6] { + IDENT [7] { + name: msg + }.oneof_type + }.payload + }.map_int32_int64 + } + CONSTANT [8] { value: 1 } + } + } + } + } + CALL [9] { + function: _==_ + args: { + CALL [10] { + function: _+_ + args: { + CALL [11] { + function: _+_ + args: { + IDENT [12] { + name: @index0 + } + IDENT [13] { + name: @index0 + } + } + } + IDENT [14] { + name: @index0 + } + } + } + CONSTANT [15] { value: 15 } + } + } + } +} +Test case: SELECT_NESTED_MESSAGE_MAP_INDEX_2 +Source: msg.oneof_type.payload.map_int32_int64[0] + msg.oneof_type.payload.map_int32_int64[1] + msg.oneof_type.payload.map_int32_int64[2] == 8 +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + SELECT [3] { + SELECT [4] { + SELECT [5] { + IDENT [6] { + name: msg + }.oneof_type + }.payload + }.map_int32_int64 + } + } + } + CALL [7] { + function: _==_ + args: { + CALL [8] { + function: _+_ + args: { + CALL [9] { + function: _+_ + args: { + CALL [10] { + function: _[_] + args: { + IDENT [11] { + name: @index0 + } + CONSTANT [12] { value: 0 } + } + } + CALL [13] { + function: _[_] + args: { + IDENT [14] { + name: @index0 + } + CONSTANT [15] { value: 1 } + } + } + } + } + CALL [16] { + function: _[_] + args: { + IDENT [17] { + name: @index0 + } + CONSTANT [18] { value: 2 } + } + } + } + } + CONSTANT [19] { value: 8 } + } + } + } +} +Test case: SELECT_NESTED_NO_COMMON_SUBEXPR +Source: msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload.single_int64 +=====> +SELECT [10] { + SELECT [9] { + SELECT [8] { + SELECT [7] { + SELECT [6] { + SELECT [5] { + SELECT [4] { + SELECT [3] { + SELECT [2] { + IDENT [1] { + name: msg + }.oneof_type + }.payload + }.oneof_type + }.payload + }.oneof_type + }.payload + }.oneof_type + }.payload + }.single_int64 +} +Test case: TERNARY +Source: (msg.single_int64 > 0 ? msg.single_int64 : 0) == 3 +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.single_int64 + } + } + } + CALL [5] { + function: _==_ + args: { + CALL [6] { + function: _?_:_ + args: { + CALL [7] { + function: _>_ + args: { + IDENT [8] { + name: @index0 + } + CONSTANT [9] { value: 0 } + } + } + IDENT [10] { + name: @index0 + } + CONSTANT [11] { value: 0 } + } + } + CONSTANT [12] { value: 3 } + } + } + } +} +Test case: TERNARY_BIND_RHS_ONLY +Source: false ? false : (msg.single_int64) + ((msg.single_int64 + 1) * 2) == 11 +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.single_int64 + } + } + } + CALL [5] { + function: _?_:_ + args: { + CONSTANT [6] { value: false } + CONSTANT [7] { value: false } + CALL [8] { + function: _==_ + args: { + CALL [9] { + function: _+_ + args: { + IDENT [10] { + name: @index0 + } + CALL [11] { + function: _*_ + args: { + CALL [12] { + function: _+_ + args: { + IDENT [13] { + name: @index0 + } + CONSTANT [14] { value: 1 } + } + } + CONSTANT [15] { value: 2 } + } + } + } + } + CONSTANT [16] { value: 11 } + } + } + } + } + } +} +Test case: NESTED_TERNARY +Source: (msg.single_int64 > 0 ? (msg.single_int32 > 0 ? msg.single_int64 + msg.single_int32 : 0) : 0) == 8 +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.single_int64 + } + SELECT [5] { + IDENT [6] { + name: msg + }.single_int32 + } + } + } + CALL [7] { + function: _==_ + args: { + CALL [8] { + function: _?_:_ + args: { + CALL [9] { + function: _>_ + args: { + IDENT [10] { + name: @index0 + } + CONSTANT [11] { value: 0 } + } + } + CALL [12] { + function: _?_:_ + args: { + CALL [13] { + function: _>_ + args: { + IDENT [14] { + name: @index1 + } + CONSTANT [15] { value: 0 } + } + } + CALL [16] { + function: _+_ + args: { + IDENT [17] { + name: @index0 + } + IDENT [18] { + name: @index1 + } + } + } + CONSTANT [19] { value: 0 } + } + } + CONSTANT [20] { value: 0 } + } + } + CONSTANT [21] { value: 8 } + } + } + } +} +Test case: MULTIPLE_MACROS_1 +Source: size([[1].exists(i, i > 0)]) + size([[1].exists(j, j > 0)]) + size([[2].exists(k, k > 1)]) + size([[2].exists(l, l > 1)]) == 4 +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + COMPREHENSION [3] { + iter_var: @it:0:0 + iter_range: { + LIST [4] { + elements: { + CONSTANT [5] { value: 1 } + } + } + } + accu_var: @ac:0:0 + accu_init: { + CONSTANT [6] { value: false } + } + loop_condition: { + CALL [7] { + function: @not_strictly_false + args: { + CALL [8] { + function: !_ + args: { + IDENT [9] { + name: @ac:0:0 + } + } + } + } + } + } + loop_step: { + CALL [10] { + function: _||_ + args: { + IDENT [11] { + name: @ac:0:0 + } + CALL [12] { + function: _>_ + args: { + IDENT [13] { + name: @it:0:0 + } + CONSTANT [14] { value: 0 } + } + } + } + } + } + result: { + IDENT [15] { + name: @ac:0:0 + } + } + } + CALL [16] { + function: size + args: { + LIST [17] { + elements: { + IDENT [18] { + name: @index0 + } + } + } + } + } + COMPREHENSION [19] { + iter_var: @it:0:0 + iter_range: { + LIST [20] { + elements: { + CONSTANT [21] { value: 2 } + } + } + } + accu_var: @ac:0:0 + accu_init: { + CONSTANT [22] { value: false } + } + loop_condition: { + CALL [23] { + function: @not_strictly_false + args: { + CALL [24] { + function: !_ + args: { + IDENT [25] { + name: @ac:0:0 + } + } + } + } + } + } + loop_step: { + CALL [26] { + function: _||_ + args: { + IDENT [27] { + name: @ac:0:0 + } + CALL [28] { + function: _>_ + args: { + IDENT [29] { + name: @it:0:0 + } + CONSTANT [30] { value: 1 } + } + } + } + } + } + result: { + IDENT [31] { + name: @ac:0:0 + } + } + } + CALL [32] { + function: size + args: { + LIST [33] { + elements: { + IDENT [34] { + name: @index2 + } + } + } + } + } + } + } + CALL [35] { + function: _==_ + args: { + CALL [36] { + function: _+_ + args: { + CALL [37] { + function: _+_ + args: { + CALL [38] { + function: _+_ + args: { + IDENT [39] { + name: @index1 + } + IDENT [40] { + name: @index1 + } + } + } + IDENT [41] { + name: @index3 + } + } + } + IDENT [42] { + name: @index3 + } + } + } + CONSTANT [43] { value: 4 } + } + } + } +} +Test case: MULTIPLE_MACROS_2 +Source: [[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == 'a')] + [['a'].exists(l, l == 'a')] == [true, true, true, true] +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + COMPREHENSION [3] { + iter_var: @it:0:0 + iter_range: { + LIST [4] { + elements: { + CONSTANT [5] { value: 1 } + } + } + } + accu_var: @ac:0:0 + accu_init: { + CONSTANT [6] { value: false } + } + loop_condition: { + CALL [7] { + function: @not_strictly_false + args: { + CALL [8] { + function: !_ + args: { + IDENT [9] { + name: @ac:0:0 + } + } + } + } + } + } + loop_step: { + CALL [10] { + function: _||_ + args: { + IDENT [11] { + name: @ac:0:0 + } + CALL [12] { + function: _>_ + args: { + IDENT [13] { + name: @it:0:0 + } + CONSTANT [14] { value: 0 } + } + } + } + } + } + result: { + IDENT [15] { + name: @ac:0:0 + } + } + } + LIST [16] { + elements: { + IDENT [17] { + name: @index0 + } + } + } + COMPREHENSION [18] { + iter_var: @it:0:1 + iter_range: { + LIST [19] { + elements: { + CONSTANT [20] { value: "a" } + } + } + } + accu_var: @ac:0:1 + accu_init: { + CONSTANT [21] { value: false } + } + loop_condition: { + CALL [22] { + function: @not_strictly_false + args: { + CALL [23] { + function: !_ + args: { + IDENT [24] { + name: @ac:0:1 + } + } + } + } + } + } + loop_step: { + CALL [25] { + function: _||_ + args: { + IDENT [26] { + name: @ac:0:1 + } + CALL [27] { + function: _==_ + args: { + IDENT [28] { + name: @it:0:1 + } + CONSTANT [29] { value: "a" } + } + } + } + } + } + result: { + IDENT [30] { + name: @ac:0:1 + } + } + } + LIST [31] { + elements: { + IDENT [32] { + name: @index2 + } + } + } + } + } + CALL [33] { + function: _==_ + args: { + CALL [34] { + function: _+_ + args: { + CALL [35] { + function: _+_ + args: { + CALL [36] { + function: _+_ + args: { + IDENT [37] { + name: @index1 + } + IDENT [38] { + name: @index1 + } + } + } + IDENT [39] { + name: @index3 + } + } + } + IDENT [40] { + name: @index3 + } + } + } + LIST [41] { + elements: { + CONSTANT [42] { value: true } + CONSTANT [43] { value: true } + CONSTANT [44] { value: true } + CONSTANT [45] { value: true } + } + } + } + } + } +} +Test case: MULTIPLE_MACROS_3 +Source: [1].exists(i, i > 0) && [1].exists(j, j > 0) && [1].exists(k, k > 1) && [2].exists(l, l > 1) +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + COMPREHENSION [3] { + iter_var: @it:0:0 + iter_range: { + LIST [4] { + elements: { + CONSTANT [5] { value: 1 } + } + } + } + accu_var: @ac:0:0 + accu_init: { + CONSTANT [6] { value: false } + } + loop_condition: { + CALL [7] { + function: @not_strictly_false + args: { + CALL [8] { + function: !_ + args: { + IDENT [9] { + name: @ac:0:0 + } + } + } + } + } + } + loop_step: { + CALL [10] { + function: _||_ + args: { + IDENT [11] { + name: @ac:0:0 + } + CALL [12] { + function: _>_ + args: { + IDENT [13] { + name: @it:0:0 + } + CONSTANT [14] { value: 0 } + } + } + } + } + } + result: { + IDENT [15] { + name: @ac:0:0 + } + } + } + } + } + CALL [16] { + function: _&&_ + args: { + CALL [17] { + function: _&&_ + args: { + IDENT [18] { + name: @index0 + } + IDENT [19] { + name: @index0 + } + } + } + CALL [20] { + function: _&&_ + args: { + COMPREHENSION [21] { + iter_var: @it:0:0 + iter_range: { + LIST [22] { + elements: { + CONSTANT [23] { value: 1 } + } + } + } + accu_var: @ac:0:0 + accu_init: { + CONSTANT [24] { value: false } + } + loop_condition: { + CALL [25] { + function: @not_strictly_false + args: { + CALL [26] { + function: !_ + args: { + IDENT [27] { + name: @ac:0:0 + } + } + } + } + } + } + loop_step: { + CALL [28] { + function: _||_ + args: { + IDENT [29] { + name: @ac:0:0 + } + CALL [30] { + function: _>_ + args: { + IDENT [31] { + name: @it:0:0 + } + CONSTANT [32] { value: 1 } + } + } + } + } + } + result: { + IDENT [33] { + name: @ac:0:0 + } + } + } + COMPREHENSION [34] { + iter_var: @it:0:0 + iter_range: { + LIST [35] { + elements: { + CONSTANT [36] { value: 2 } + } + } + } + accu_var: @ac:0:0 + accu_init: { + CONSTANT [37] { value: false } + } + loop_condition: { + CALL [38] { + function: @not_strictly_false + args: { + CALL [39] { + function: !_ + args: { + IDENT [40] { + name: @ac:0:0 + } + } + } + } + } + } + loop_step: { + CALL [41] { + function: _||_ + args: { + IDENT [42] { + name: @ac:0:0 + } + CALL [43] { + function: _>_ + args: { + IDENT [44] { + name: @it:0:0 + } + CONSTANT [45] { value: 1 } + } + } + } + } + } + result: { + IDENT [46] { + name: @ac:0:0 + } + } + } + } + } + } + } + } +} +Test case: NESTED_MACROS +Source: [1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [[2, 3, 4], [2, 3, 4], [2, 3, 4]] +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + CONSTANT [6] { value: 3 } + } + } + LIST [7] { + elements: { + CONSTANT [8] { value: 2 } + CONSTANT [9] { value: 3 } + CONSTANT [10] { value: 4 } + } + } + } + } + CALL [11] { + function: _==_ + args: { + COMPREHENSION [12] { + iter_var: @it:0:0 + iter_range: { + IDENT [13] { + name: @index0 + } + } + accu_var: @ac:0:0 + accu_init: { + LIST [14] { + elements: { + } + } + } + loop_condition: { + CONSTANT [15] { value: true } + } + loop_step: { + CALL [16] { + function: _+_ + args: { + IDENT [17] { + name: @ac:0:0 + } + LIST [18] { + elements: { + COMPREHENSION [19] { + iter_var: @it:1:0 + iter_range: { + IDENT [20] { + name: @index0 + } + } + accu_var: @ac:1:0 + accu_init: { + LIST [21] { + elements: { + } + } + } + loop_condition: { + CONSTANT [22] { value: true } + } + loop_step: { + CALL [23] { + function: _+_ + args: { + IDENT [24] { + name: @ac:1:0 + } + LIST [25] { + elements: { + CALL [26] { + function: _+_ + args: { + IDENT [27] { + name: @it:1:0 + } + CONSTANT [28] { value: 1 } + } + } + } + } + } + } + } + result: { + IDENT [29] { + name: @ac:1:0 + } + } + } + } + } + } + } + } + result: { + IDENT [30] { + name: @ac:0:0 + } + } + } + LIST [31] { + elements: { + IDENT [32] { + name: @index1 + } + IDENT [33] { + name: @index1 + } + IDENT [34] { + name: @index1 + } + } + } + } + } + } +} +Test case: NESTED_MACROS_2 +Source: [1, 2].map(y, [1, 2, 3].filter(x, x == y)) == [[1], [2]] +=====> +CALL [31] { + function: _==_ + args: { + COMPREHENSION [30] { + iter_var: @it:0:0 + iter_range: { + LIST [1] { + elements: { + CONSTANT [2] { value: 1 } + CONSTANT [3] { value: 2 } + } + } + } + accu_var: @ac:0:0 + accu_init: { + LIST [24] { + elements: { + } + } + } + loop_condition: { + CONSTANT [25] { value: true } + } + loop_step: { + CALL [28] { + function: _+_ + args: { + IDENT [26] { + name: @ac:0:0 + } + LIST [27] { + elements: { + COMPREHENSION [23] { + iter_var: @it:1:0 + iter_range: { + LIST [6] { + elements: { + CONSTANT [7] { value: 1 } + CONSTANT [8] { value: 2 } + CONSTANT [9] { value: 3 } + } + } + } + accu_var: @ac:1:0 + accu_init: { + LIST [15] { + elements: { + } + } + } + loop_condition: { + CONSTANT [16] { value: true } + } + loop_step: { + CALL [21] { + function: _?_:_ + args: { + CALL [13] { + function: _==_ + args: { + IDENT [12] { + name: @it:1:0 + } + IDENT [14] { + name: @it:0:0 + } + } + } + CALL [19] { + function: _+_ + args: { + IDENT [17] { + name: @ac:1:0 + } + LIST [18] { + elements: { + IDENT [11] { + name: @it:1:0 + } + } + } + } + } + IDENT [20] { + name: @ac:1:0 + } + } + } + } + result: { + IDENT [22] { + name: @ac:1:0 + } + } + } + } + } + } + } + } + result: { + IDENT [29] { + name: @ac:0:0 + } + } + } + LIST [32] { + elements: { + LIST [33] { + elements: { + CONSTANT [34] { value: 1 } + } + } + LIST [35] { + elements: { + CONSTANT [36] { value: 2 } + } + } + } + } + } +} +Test case: ADJACENT_NESTED_MACROS +Source: [1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [1,2,3].map(j, [1, 2, 3].map(j, j + 1)) +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + CONSTANT [6] { value: 3 } + } + } + COMPREHENSION [7] { + iter_var: @it:0:0 + iter_range: { + IDENT [8] { + name: @index0 + } + } + accu_var: @ac:0:0 + accu_init: { + LIST [9] { + elements: { + } + } + } + loop_condition: { + CONSTANT [10] { value: true } + } + loop_step: { + CALL [11] { + function: _+_ + args: { + IDENT [12] { + name: @ac:0:0 + } + LIST [13] { + elements: { + COMPREHENSION [14] { + iter_var: @it:1:0 + iter_range: { + IDENT [15] { + name: @index0 + } + } + accu_var: @ac:1:0 + accu_init: { + LIST [16] { + elements: { + } + } + } + loop_condition: { + CONSTANT [17] { value: true } + } + loop_step: { + CALL [18] { + function: _+_ + args: { + IDENT [19] { + name: @ac:1:0 + } + LIST [20] { + elements: { + CALL [21] { + function: _+_ + args: { + IDENT [22] { + name: @it:1:0 + } + CONSTANT [23] { value: 1 } + } + } + } + } + } + } + } + result: { + IDENT [24] { + name: @ac:1:0 + } + } + } + } + } + } + } + } + result: { + IDENT [25] { + name: @ac:0:0 + } + } + } + } + } + CALL [26] { + function: _==_ + args: { + IDENT [27] { + name: @index1 + } + IDENT [28] { + name: @index1 + } + } + } + } +} +Test case: INCLUSION_LIST +Source: 1 in [1,2,3] && 2 in [1,2,3] && 3 in [3, [1,2,3]] && 1 in [1,2,3] +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + CONSTANT [6] { value: 3 } + } + } + CALL [7] { + function: @in + args: { + CONSTANT [8] { value: 1 } + IDENT [9] { + name: @index0 + } + } + } + } + } + CALL [10] { + function: _&&_ + args: { + CALL [11] { + function: _&&_ + args: { + IDENT [12] { + name: @index1 + } + CALL [13] { + function: @in + args: { + CONSTANT [14] { value: 2 } + IDENT [15] { + name: @index0 + } + } + } + } + } + CALL [16] { + function: _&&_ + args: { + CALL [17] { + function: @in + args: { + CONSTANT [18] { value: 3 } + LIST [19] { + elements: { + CONSTANT [20] { value: 3 } + IDENT [21] { + name: @index0 + } + } + } + } + } + IDENT [22] { + name: @index1 + } + } + } + } + } + } +} +Test case: INCLUSION_MAP +Source: 2 in {'a': 1, 2: {true: false}, 3: {true: false}} +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: true } + } + value: { + CONSTANT [6] { value: false } + } + } + } + } + } + CALL [7] { + function: @in + args: { + CONSTANT [8] { value: 2 } + MAP [9] { + MAP_ENTRY [10] { + key: { + CONSTANT [11] { value: "a" } + } + value: { + CONSTANT [12] { value: 1 } + } + } + MAP_ENTRY [13] { + key: { + CONSTANT [14] { value: 2 } + } + value: { + IDENT [15] { + name: @index0 + } + } + } + MAP_ENTRY [16] { + key: { + CONSTANT [17] { value: 3 } + } + value: { + IDENT [18] { + name: @index0 + } + } + } + } + } + } + } +} +Test case: MACRO_ITER_VAR_NOT_REFERENCED +Source: [1,2].map(i, [1, 2].map(i, [3,4])) == [[[3, 4], [3, 4]], [[3, 4], [3, 4]]] +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + } + } + LIST [6] { + elements: { + CONSTANT [7] { value: 3 } + CONSTANT [8] { value: 4 } + } + } + LIST [9] { + elements: { + IDENT [10] { + name: @index1 + } + IDENT [11] { + name: @index1 + } + } + } + } + } + CALL [12] { + function: _==_ + args: { + COMPREHENSION [13] { + iter_var: @it:0:0 + iter_range: { + IDENT [14] { + name: @index0 + } + } + accu_var: @ac:0:0 + accu_init: { + LIST [15] { + elements: { + } + } + } + loop_condition: { + CONSTANT [16] { value: true } + } + loop_step: { + CALL [17] { + function: _+_ + args: { + IDENT [18] { + name: @ac:0:0 + } + LIST [19] { + elements: { + COMPREHENSION [20] { + iter_var: @it:1:0 + iter_range: { + IDENT [21] { + name: @index0 + } + } + accu_var: @ac:1:0 + accu_init: { + LIST [22] { + elements: { + } + } + } + loop_condition: { + CONSTANT [23] { value: true } + } + loop_step: { + CALL [24] { + function: _+_ + args: { + IDENT [25] { + name: @ac:1:0 + } + LIST [26] { + elements: { + IDENT [27] { + name: @index1 + } + } + } + } + } + } + result: { + IDENT [28] { + name: @ac:1:0 + } + } + } + } + } + } + } + } + result: { + IDENT [29] { + name: @ac:0:0 + } + } + } + LIST [30] { + elements: { + IDENT [31] { + name: @index2 + } + IDENT [32] { + name: @index2 + } + } + } + } + } + } +} +Test case: MACRO_SHADOWED_VARIABLE +Source: [x - 1 > 3 ? x - 1 : 5].exists(x, x - 1 > 3) || x - 1 > 3 +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + CALL [3] { + function: _-_ + args: { + IDENT [4] { + name: x + } + CONSTANT [5] { value: 1 } + } + } + CALL [6] { + function: _>_ + args: { + IDENT [7] { + name: @index0 + } + CONSTANT [8] { value: 3 } + } + } + } + } + CALL [9] { + function: _||_ + args: { + COMPREHENSION [10] { + iter_var: @it:0:0 + iter_range: { + LIST [11] { + elements: { + CALL [12] { + function: _?_:_ + args: { + IDENT [13] { + name: @index1 + } + IDENT [14] { + name: @index0 + } + CONSTANT [15] { value: 5 } + } + } + } + } + } + accu_var: @ac:0:0 + accu_init: { + CONSTANT [16] { value: false } + } + loop_condition: { + CALL [17] { + function: @not_strictly_false + args: { + CALL [18] { + function: !_ + args: { + IDENT [19] { + name: @ac:0:0 + } + } + } + } + } + } + loop_step: { + CALL [20] { + function: _||_ + args: { + IDENT [21] { + name: @ac:0:0 + } + CALL [22] { + function: _>_ + args: { + CALL [23] { + function: _-_ + args: { + IDENT [24] { + name: @it:0:0 + } + CONSTANT [25] { value: 1 } + } + } + CONSTANT [26] { value: 3 } + } + } + } + } + } + result: { + IDENT [27] { + name: @ac:0:0 + } + } + } + IDENT [28] { + name: @index1 + } + } + } + } +} +Test case: MACRO_SHADOWED_VARIABLE_2 +Source: ["foo", "bar"].map(x, [x + x, x + x]).map(x, [x + x, x + x]) +=====> +COMPREHENSION [35] { + iter_var: @it:0:0 + iter_range: { + COMPREHENSION [19] { + iter_var: @it:1:0 + iter_range: { + LIST [1] { + elements: { + CONSTANT [2] { value: "foo" } + CONSTANT [3] { value: "bar" } + } + } + } + accu_var: @ac:1:0 + accu_init: { + LIST [13] { + elements: { + } + } + } + loop_condition: { + CONSTANT [14] { value: true } + } + loop_step: { + CALL [17] { + function: _+_ + args: { + IDENT [15] { + name: @ac:1:0 + } + LIST [16] { + elements: { + LIST [6] { + elements: { + CALL [8] { + function: _+_ + args: { + IDENT [7] { + name: @it:1:0 + } + IDENT [9] { + name: @it:1:0 + } + } + } + CALL [11] { + function: _+_ + args: { + IDENT [10] { + name: @it:1:0 + } + IDENT [12] { + name: @it:1:0 + } + } + } + } + } + } + } + } + } + } + result: { + IDENT [18] { + name: @ac:1:0 + } + } + } + } + accu_var: @ac:0:0 + accu_init: { + LIST [29] { + elements: { + } + } + } + loop_condition: { + CONSTANT [30] { value: true } + } + loop_step: { + CALL [33] { + function: _+_ + args: { + IDENT [31] { + name: @ac:0:0 + } + LIST [32] { + elements: { + LIST [22] { + elements: { + CALL [24] { + function: _+_ + args: { + IDENT [23] { + name: @it:0:0 + } + IDENT [25] { + name: @it:0:0 + } + } + } + CALL [27] { + function: _+_ + args: { + IDENT [26] { + name: @it:0:0 + } + IDENT [28] { + name: @it:0:0 + } + } + } + } + } + } + } + } + } + } + result: { + IDENT [34] { + name: @ac:0:0 + } + } +} +Test case: PRESENCE_TEST +Source: has({'a': true}.a) && {'a':true}['a'] +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: "a" } + } + value: { + CONSTANT [6] { value: true } + } + } + } + } + } + CALL [7] { + function: _&&_ + args: { + SELECT [8] { + IDENT [9] { + name: @index0 + }.a~presence_test + } + CALL [10] { + function: _[_] + args: { + IDENT [11] { + name: @index0 + } + CONSTANT [12] { value: "a" } + } + } + } + } + } +} +Test case: PRESENCE_TEST_2 +Source: has({'a': true}.a) && has({'a': true}.a) +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + SELECT [3] { + MAP [4] { + MAP_ENTRY [5] { + key: { + CONSTANT [6] { value: "a" } + } + value: { + CONSTANT [7] { value: true } + } + } + }.a~presence_test + } + } + } + CALL [8] { + function: _&&_ + args: { + IDENT [9] { + name: @index0 + } + IDENT [10] { + name: @index0 + } + } + } + } +} +Test case: PRESENCE_TEST_WITH_TERNARY +Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : 0) == 10 +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + } + } + CALL [5] { + function: _==_ + args: { + CALL [6] { + function: _?_:_ + args: { + SELECT [7] { + IDENT [8] { + name: @index0 + }.payload~presence_test + } + SELECT [9] { + SELECT [10] { + IDENT [11] { + name: @index0 + }.payload + }.single_int64 + } + CONSTANT [12] { value: 0 } + } + } + CONSTANT [13] { value: 10 } + } + } + } +} +Test case: PRESENCE_TEST_WITH_TERNARY_2 +Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : msg.oneof_type.payload.single_int64 * 0) == 10 +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + SELECT [6] { + IDENT [7] { + name: @index0 + }.payload + }.single_int64 + } + } + } + CALL [8] { + function: _==_ + args: { + CALL [9] { + function: _?_:_ + args: { + SELECT [10] { + IDENT [11] { + name: @index0 + }.payload~presence_test + } + IDENT [12] { + name: @index1 + } + CALL [13] { + function: _*_ + args: { + IDENT [14] { + name: @index1 + } + CONSTANT [15] { value: 0 } + } + } + } + } + CONSTANT [16] { value: 10 } + } + } + } +} +Test case: PRESENCE_TEST_WITH_TERNARY_3 +Source: (has(msg.oneof_type.payload.single_int64) ? msg.oneof_type.payload.single_int64 : msg.oneof_type.payload.single_int64 * 0) == 10 +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + SELECT [3] { + SELECT [4] { + IDENT [5] { + name: msg + }.oneof_type + }.payload + } + SELECT [6] { + IDENT [7] { + name: @index0 + }.single_int64 + } + } + } + CALL [8] { + function: _==_ + args: { + CALL [9] { + function: _?_:_ + args: { + SELECT [10] { + IDENT [11] { + name: @index0 + }.single_int64~presence_test + } + IDENT [12] { + name: @index1 + } + CALL [13] { + function: _*_ + args: { + IDENT [14] { + name: @index1 + } + CONSTANT [15] { value: 0 } + } + } + } + } + CONSTANT [16] { value: 10 } + } + } + } +} +Test case: PRESENCE_TEST_WITH_TERNARY_NESTED +Source: (has(msg.oneof_type) && has(msg.oneof_type.payload) && has(msg.oneof_type.payload.single_int64)) ? ((has(msg.oneof_type.payload.map_string_string) && has(msg.oneof_type.payload.map_string_string.key)) ? msg.oneof_type.payload.map_string_string.key == 'A' : false) : false +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + SELECT [3] { + IDENT [4] { + name: msg + }.oneof_type + } + SELECT [5] { + IDENT [6] { + name: @index0 + }.payload + } + SELECT [7] { + IDENT [8] { + name: @index1 + }.map_string_string + } + } + } + CALL [9] { + function: _?_:_ + args: { + CALL [10] { + function: _&&_ + args: { + CALL [11] { + function: _&&_ + args: { + SELECT [12] { + IDENT [13] { + name: msg + }.oneof_type~presence_test + } + SELECT [14] { + IDENT [15] { + name: @index0 + }.payload~presence_test + } + } + } + SELECT [16] { + IDENT [17] { + name: @index1 + }.single_int64~presence_test + } + } + } + CALL [18] { + function: _?_:_ + args: { + CALL [19] { + function: _&&_ + args: { + SELECT [20] { + IDENT [21] { + name: @index1 + }.map_string_string~presence_test + } + SELECT [22] { + IDENT [23] { + name: @index2 + }.key~presence_test + } + } + } + CALL [24] { + function: _==_ + args: { + SELECT [25] { + IDENT [26] { + name: @index2 + }.key + } + CONSTANT [27] { value: "A" } + } + } + CONSTANT [28] { value: false } + } + } + CONSTANT [29] { value: false } + } + } + } +} +Test case: OPTIONAL_LIST +Source: [10, ?optional.none(), [?optional.none(), ?opt_x], [?optional.none(), ?opt_x]] == [10, [5], [5]] +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + CALL [3] { + function: optional.none + args: { + } + } + LIST [4] { + elements: { + IDENT [5] { + name: @index0 + } + IDENT [6] { + name: opt_x + } + } + optional_indices: [0, 1] + } + LIST [7] { + elements: { + CONSTANT [8] { value: 5 } + } + } + } + } + CALL [9] { + function: _==_ + args: { + LIST [10] { + elements: { + CONSTANT [11] { value: 10 } + IDENT [12] { + name: @index0 + } + IDENT [13] { + name: @index1 + } + IDENT [14] { + name: @index1 + } + } + optional_indices: [0] + } + LIST [15] { + elements: { + CONSTANT [16] { value: 10 } + IDENT [17] { + name: @index2 + } + IDENT [18] { + name: @index2 + } + } + } + } + } + } +} +Test case: OPTIONAL_MAP +Source: {?'hello': optional.of('hello')}['hello'] + {?'hello': optional.of('hello')}['hello'] == 'hellohello' +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + CALL [3] { + function: _[_] + args: { + MAP [4] { + MAP_ENTRY [5] { + key: { + CONSTANT [6] { value: "hello" } + } + optional_entry: true + value: { + CALL [7] { + function: optional.of + args: { + CONSTANT [8] { value: "hello" } + } + } + } + } + } + CONSTANT [9] { value: "hello" } + } + } + } + } + CALL [10] { + function: _==_ + args: { + CALL [11] { + function: _+_ + args: { + IDENT [12] { + name: @index0 + } + IDENT [13] { + name: @index0 + } + } + } + CONSTANT [14] { value: "hellohello" } + } + } + } +} +Test case: OPTIONAL_MAP_CHAINED +Source: {?'key': optional.of('test')}[?'bogus'].or({'key': 'test'}[?'bogus']).orValue({'key': 'test'}['key']) == 'test' +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + MAP [3] { + MAP_ENTRY [4] { + key: { + CONSTANT [5] { value: "key" } + } + value: { + CONSTANT [6] { value: "test" } + } + } + } + } + } + CALL [7] { + function: _==_ + args: { + CALL [8] { + function: orValue + target: { + CALL [9] { + function: or + target: { + CALL [10] { + function: _[?_] + args: { + MAP [11] { + MAP_ENTRY [12] { + key: { + CONSTANT [13] { value: "key" } + } + optional_entry: true + value: { + CALL [14] { + function: optional.of + args: { + CONSTANT [15] { value: "test" } + } + } + } + } + } + CONSTANT [16] { value: "bogus" } + } + } + } + args: { + CALL [17] { + function: _[?_] + args: { + IDENT [18] { + name: @index0 + } + CONSTANT [19] { value: "bogus" } + } + } + } + } + } + args: { + CALL [20] { + function: _[_] + args: { + IDENT [21] { + name: @index0 + } + CONSTANT [22] { value: "key" } + } + } + } + } + CONSTANT [23] { value: "test" } + } + } + } +} +Test case: OPTIONAL_MESSAGE +Source: TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}.single_int32 + TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}.single_int64 == 5 +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + STRUCT [3] { + name: TestAllTypes + entries: { + ENTRY [4] { + field_key: single_int64 + optional_entry: true + value: { + CALL [5] { + function: optional.ofNonZeroValue + args: { + CONSTANT [6] { value: 1 } + } + } + } + } + ENTRY [7] { + field_key: single_int32 + optional_entry: true + value: { + CALL [8] { + function: optional.of + args: { + CONSTANT [9] { value: 4 } + } + } + } + } + } + } + } + } + CALL [10] { + function: _==_ + args: { + CALL [11] { + function: _+_ + args: { + SELECT [12] { + IDENT [13] { + name: @index0 + }.single_int32 + } + SELECT [14] { + IDENT [15] { + name: @index0 + }.single_int64 + } + } + } + CONSTANT [16] { value: 5 } + } + } + } +} +Test case: CALL +Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('h' + 'e' + 'l' + 'l' + 'o') +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + CALL [3] { + function: _+_ + args: { + CALL [4] { + function: _+_ + args: { + CALL [5] { + function: _+_ + args: { + CALL [6] { + function: _+_ + args: { + CONSTANT [7] { value: "h" } + CONSTANT [8] { value: "e" } + } + } + CONSTANT [9] { value: "l" } + } + } + CONSTANT [10] { value: "l" } + } + } + CONSTANT [11] { value: "o" } + } + } + } + } + CALL [12] { + function: matches + target: { + CALL [13] { + function: _+_ + args: { + IDENT [14] { + name: @index0 + } + CONSTANT [15] { value: " world" } + } + } + } + args: { + IDENT [16] { + name: @index0 + } + } + } + } +} +Test case: CALL_ARGUMENT_NESTED_NO_COMMON_SUBEXPR +Source: 'hello world'.matches('h' + 'e' + 'l' + 'l' + 'o') +=====> +CALL [2] { + function: matches + target: { + CONSTANT [1] { value: "hello world" } + } + args: { + CALL [10] { + function: _+_ + args: { + CALL [8] { + function: _+_ + args: { + CALL [6] { + function: _+_ + args: { + CALL [4] { + function: _+_ + args: { + CONSTANT [3] { value: "h" } + CONSTANT [5] { value: "e" } + } + } + CONSTANT [7] { value: "l" } + } + } + CONSTANT [9] { value: "l" } + } + } + CONSTANT [11] { value: "o" } + } + } + } +} +Test case: CALL_TARGET_NESTED_NO_COMMON_SUBEXPR +Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('hello') +=====> +CALL [12] { + function: matches + target: { + CALL [10] { + function: _+_ + args: { + CALL [8] { + function: _+_ + args: { + CALL [6] { + function: _+_ + args: { + CALL [4] { + function: _+_ + args: { + CALL [2] { + function: _+_ + args: { + CONSTANT [1] { value: "h" } + CONSTANT [3] { value: "e" } + } + } + CONSTANT [5] { value: "l" } + } + } + CONSTANT [7] { value: "l" } + } + } + CONSTANT [9] { value: "o" } + } + } + CONSTANT [11] { value: " world" } + } + } + } + args: { + CONSTANT [13] { value: "hello" } + } +} +Test case: CALL_BOTH_ARGUMENT_TARGET_NESTED_NO_COMMON_SUBEXPR +Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('w' + 'o' + 'r' + 'l' + 'd') +=====> +CALL [12] { + function: matches + target: { + CALL [10] { + function: _+_ + args: { + CALL [8] { + function: _+_ + args: { + CALL [6] { + function: _+_ + args: { + CALL [4] { + function: _+_ + args: { + CALL [2] { + function: _+_ + args: { + CONSTANT [1] { value: "h" } + CONSTANT [3] { value: "e" } + } + } + CONSTANT [5] { value: "l" } + } + } + CONSTANT [7] { value: "l" } + } + } + CONSTANT [9] { value: "o" } + } + } + CONSTANT [11] { value: " world" } + } + } + } + args: { + CALL [20] { + function: _+_ + args: { + CALL [18] { + function: _+_ + args: { + CALL [16] { + function: _+_ + args: { + CALL [14] { + function: _+_ + args: { + CONSTANT [13] { value: "w" } + CONSTANT [15] { value: "o" } + } + } + CONSTANT [17] { value: "r" } + } + } + CONSTANT [19] { value: "l" } + } + } + CONSTANT [21] { value: "d" } + } + } + } +} +Test case: CUSTOM_FUNCTION_INELIMINABLE +Source: non_pure_custom_func(msg.oneof_type.payload.single_int64) + non_pure_custom_func(msg.oneof_type.payload.single_int32) + non_pure_custom_func(msg.oneof_type.payload.single_int64) + non_pure_custom_func(msg.single_int64) +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + SELECT [3] { + SELECT [4] { + IDENT [5] { + name: msg + }.oneof_type + }.payload + } + SELECT [6] { + IDENT [7] { + name: @index0 + }.single_int64 + } + } + } + CALL [8] { + function: _+_ + args: { + CALL [9] { + function: _+_ + args: { + CALL [10] { + function: _+_ + args: { + CALL [11] { + function: non_pure_custom_func + args: { + IDENT [12] { + name: @index1 + } + } + } + CALL [13] { + function: non_pure_custom_func + args: { + SELECT [14] { + IDENT [15] { + name: @index0 + }.single_int32 + } + } + } + } + } + CALL [16] { + function: non_pure_custom_func + args: { + IDENT [17] { + name: @index1 + } + } + } + } + } + CALL [18] { + function: non_pure_custom_func + args: { + SELECT [19] { + IDENT [20] { + name: msg + }.single_int64 + } + } + } + } + } + } +} +Test case: CUSTOM_FUNCTION_ELIMINABLE +Source: pure_custom_func(msg.oneof_type.payload.single_int64) + pure_custom_func(msg.oneof_type.payload.single_int32) + pure_custom_func(msg.oneof_type.payload.single_int64) + pure_custom_func(msg.single_int64) +=====> +CALL [1] { + function: cel.@block + args: { + LIST [2] { + elements: { + SELECT [3] { + SELECT [4] { + IDENT [5] { + name: msg + }.oneof_type + }.payload + } + CALL [6] { + function: pure_custom_func + args: { + SELECT [7] { + IDENT [8] { + name: @index0 + }.single_int64 + } + } + } + } + } + CALL [9] { + function: _+_ + args: { + CALL [10] { + function: _+_ + args: { + CALL [11] { + function: _+_ + args: { + IDENT [12] { + name: @index1 + } + CALL [13] { + function: pure_custom_func + args: { + SELECT [14] { + IDENT [15] { + name: @index0 + }.single_int32 + } + } + } + } + } + IDENT [16] { + name: @index1 + } + } + } + CALL [17] { + function: pure_custom_func + args: { + SELECT [18] { + IDENT [19] { + name: msg + }.single_int64 + } + } + } + } + } + } +} \ No newline at end of file diff --git a/optimizer/src/test/resources/subexpression_unparsed.baseline b/optimizer/src/test/resources/subexpression_unparsed.baseline index 781f59990..6b8606a48 100644 --- a/optimizer/src/test/resources/subexpression_unparsed.baseline +++ b/optimizer/src/test/resources/subexpression_unparsed.baseline @@ -4,6 +4,7 @@ Source: size([1,2]) + size([1,2]) + 1 == 5 Result: true [CASCADED_BINDS]: cel.bind(@r0, size([1, 2]), @r0 + @r0) + 1 == 5 [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([size([1, 2])], @index0 + @index0 + 1 == 5) +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: cel.@block([size([1, 2])], @index0 + @index0 + 1 == 5) [BLOCK_RECURSION_DEPTH_1]: cel.@block([[1, 2], size(@index0), @index1 + @index1, @index2 + 1], @index3 == 5) [BLOCK_RECURSION_DEPTH_2]: cel.@block([size([1, 2]), @index0 + @index0 + 1], @index1 == 5) [BLOCK_RECURSION_DEPTH_3]: cel.@block([size([1, 2])], @index0 + @index0 + 1 == 5) @@ -20,6 +21,7 @@ Source: 2 + size([1,2]) + size([1,2]) + 1 == 7 Result: true [CASCADED_BINDS]: cel.bind(@r0, size([1, 2]), 2 + @r0 + @r0) + 1 == 7 [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([size([1, 2])], 2 + @index0 + @index0 + 1 == 7) +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: cel.@block([size([1, 2])], 2 + @index0 + @index0 + 1 == 7) [BLOCK_RECURSION_DEPTH_1]: cel.@block([[1, 2], size(@index0), 2 + @index1, @index2 + @index1, @index3 + 1], @index4 == 7) [BLOCK_RECURSION_DEPTH_2]: cel.@block([size([1, 2]), 2 + @index0 + @index0], @index1 + 1 == 7) [BLOCK_RECURSION_DEPTH_3]: cel.@block([size([1, 2]), 2 + @index0 + @index0 + 1], @index1 == 7) @@ -36,6 +38,7 @@ Source: size([0]) + size([0]) + size([1,2]) + size([1,2]) == 6 Result: true [CASCADED_BINDS]: cel.bind(@r1, size([1, 2]), cel.bind(@r0, size([0]), @r0 + @r0) + @r1 + @r1) == 6 [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([size([0]), size([1, 2])], @index0 + @index0 + @index1 + @index1 == 6) +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: cel.@block([size([0]), size([1, 2])], @index0 + @index0 + @index1 + @index1 == 6) [BLOCK_RECURSION_DEPTH_1]: cel.@block([[0], size(@index0), [1, 2], size(@index2), @index1 + @index1, @index4 + @index3, @index5 + @index3], @index6 == 6) [BLOCK_RECURSION_DEPTH_2]: cel.@block([size([0]), size([1, 2]), @index0 + @index0 + @index1], @index2 + @index1 == 6) [BLOCK_RECURSION_DEPTH_3]: cel.@block([size([0]), size([1, 2]), @index0 + @index0 + @index1 + @index1], @index2 == 6) @@ -52,6 +55,7 @@ Source: 5 + size([0]) + size([0]) + size([1,2]) + size([1,2]) + size([1,2,3]) + Result: true [CASCADED_BINDS]: cel.bind(@r2, size([1, 2, 3]), cel.bind(@r1, size([1, 2]), cel.bind(@r0, size([0]), 5 + @r0 + @r0) + @r1 + @r1) + @r2 + @r2) == 17 [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([size([0]), size([1, 2]), size([1, 2, 3])], 5 + @index0 + @index0 + @index1 + @index1 + @index2 + @index2 == 17) +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: cel.@block([size([0]), size([1, 2]), size([1, 2, 3])], 5 + @index0 + @index0 + @index1 + @index1 + @index2 + @index2 == 17) [BLOCK_RECURSION_DEPTH_1]: cel.@block([[0], size(@index0), [1, 2], size(@index2), [1, 2, 3], size(@index4), 5 + @index1, @index6 + @index1, @index7 + @index3, @index8 + @index3, @index9 + @index5, @index10 + @index5], @index11 == 17) [BLOCK_RECURSION_DEPTH_2]: cel.@block([size([0]), size([1, 2]), size([1, 2, 3]), 5 + @index0 + @index0, @index3 + @index1 + @index1, @index4 + @index2 + @index2], @index5 == 17) [BLOCK_RECURSION_DEPTH_3]: cel.@block([size([0]), size([1, 2]), size([1, 2, 3]), 5 + @index0 + @index0 + @index1, @index3 + @index1 + @index2 + @index2], @index4 == 17) @@ -68,6 +72,7 @@ Source: timestamp(int(timestamp(1000000000))).getFullYear() + timestamp(int(time Result: true [CASCADED_BINDS]: cel.bind(@r0, timestamp(int(timestamp(1000000000))).getFullYear(), cel.bind(@r3, timestamp(int(timestamp(75))), cel.bind(@r2, timestamp(int(timestamp(200))).getFullYear(), cel.bind(@r1, timestamp(int(timestamp(50))), @r0 + @r3.getFullYear() + @r1.getFullYear() + @r0 + @r1.getSeconds()) + @r2 + @r2) + @r3.getMinutes()) + @r0) == 13934 [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([timestamp(int(timestamp(1000000000))).getFullYear(), timestamp(int(timestamp(50))), timestamp(int(timestamp(200))).getFullYear(), timestamp(int(timestamp(75)))], @index0 + @index3.getFullYear() + @index1.getFullYear() + @index0 + @index1.getSeconds() + @index2 + @index2 + @index3.getMinutes() + @index0 == 13934) +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: cel.@block([timestamp(int(timestamp(1000000000))).getFullYear(), timestamp(int(timestamp(50))), timestamp(int(timestamp(200))).getFullYear(), timestamp(int(timestamp(75)))], @index0 + @index3.getFullYear() + @index1.getFullYear() + @index0 + @index1.getSeconds() + @index2 + @index2 + @index3.getMinutes() + @index0 == 13934) [BLOCK_RECURSION_DEPTH_1]: cel.@block([timestamp(1000000000), int(@index0), timestamp(@index1), @index2.getFullYear(), timestamp(50), int(@index4), timestamp(@index5), timestamp(200), int(@index7), timestamp(@index8), @index9.getFullYear(), timestamp(75), int(@index11), timestamp(@index12), @index13.getFullYear(), @index3 + @index14, @index6.getFullYear(), @index15 + @index16, @index17 + @index3, @index6.getSeconds(), @index18 + @index19, @index20 + @index10, @index21 + @index10, @index13.getMinutes(), @index22 + @index23, @index24 + @index3], @index25 == 13934) [BLOCK_RECURSION_DEPTH_2]: cel.@block([int(timestamp(1000000000)), timestamp(@index0).getFullYear(), int(timestamp(50)), int(timestamp(200)), timestamp(@index3).getFullYear(), int(timestamp(75)), timestamp(@index2), timestamp(@index5), @index1 + @index7.getFullYear(), @index8 + @index6.getFullYear(), @index9 + @index1 + @index6.getSeconds(), @index10 + @index4 + @index4, @index11 + @index7.getMinutes()], @index12 + @index1 == 13934) [BLOCK_RECURSION_DEPTH_3]: cel.@block([timestamp(int(timestamp(1000000000))), timestamp(int(timestamp(50))), timestamp(int(timestamp(200))), timestamp(int(timestamp(75))), @index0.getFullYear(), @index2.getFullYear(), @index4 + @index3.getFullYear() + @index1.getFullYear(), @index6 + @index4 + @index1.getSeconds() + @index5, @index7 + @index5 + @index3.getMinutes() + @index4], @index8 == 13934) @@ -84,6 +89,7 @@ Source: {"a": 2}["a"] + {"a": 2}["a"] * {"a": 2}["a"] == 6 Result: true [CASCADED_BINDS]: cel.bind(@r0, {"a": 2}["a"], @r0 + @r0 * @r0) == 6 [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([{"a": 2}["a"]], @index0 + @index0 * @index0 == 6) +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: cel.@block([{"a": 2}["a"]], @index0 + @index0 * @index0 == 6) [BLOCK_RECURSION_DEPTH_1]: cel.@block([{"a": 2}, @index0["a"], @index1 * @index1, @index1 + @index2], @index3 == 6) [BLOCK_RECURSION_DEPTH_2]: cel.@block([{"a": 2}["a"], @index0 + @index0 * @index0], @index1 == 6) [BLOCK_RECURSION_DEPTH_3]: cel.@block([{"a": 2}["a"]], @index0 + @index0 * @index0 == 6) @@ -100,6 +106,7 @@ Source: {'a': {'b': 1}, 'c': {'b': 1}, 'd': {'e': {'b': 1}}, 'e': {'e': {'b': 1} Result: {a={b=1}, c={b=1}, d={e={b=1}}, e={e={b=1}}} [CASCADED_BINDS]: cel.bind(@r0, {"b": 1}, cel.bind(@r1, {"e": @r0}, {"a": @r0, "c": @r0, "d": @r1, "e": @r1})) [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([{"b": 1}, {"e": @index0}], {"a": @index0, "c": @index0, "d": @index1, "e": @index1}) +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: cel.@block([{"b": 1}, {"e": @index0}], {"a": @index0, "c": @index0, "d": @index1, "e": @index1}) [BLOCK_RECURSION_DEPTH_1]: cel.@block([{"b": 1}, {"e": @index0}], {"a": @index0, "c": @index0, "d": @index1, "e": @index1}) [BLOCK_RECURSION_DEPTH_2]: cel.@block([{"e": {"b": 1}}, {"b": 1}], {"a": @index1, "c": @index1, "d": @index0, "e": @index0}) [BLOCK_RECURSION_DEPTH_3]: cel.@block([{"e": {"b": 1}}, {"b": 1}], {"a": @index1, "c": @index1, "d": @index0, "e": @index0}) @@ -116,6 +123,7 @@ Source: [1, [1,2,3,4], 2, [1,2,3,4], 5, [1,2,3,4], 7, [[1,2], [1,2,3,4]], [1,2]] Result: [1, [1, 2, 3, 4], 2, [1, 2, 3, 4], 5, [1, 2, 3, 4], 7, [[1, 2], [1, 2, 3, 4]], [1, 2]] [CASCADED_BINDS]: cel.bind(@r0, [1, 2, 3, 4], cel.bind(@r1, [1, 2], [1, @r0, 2, @r0, 5, @r0, 7, [@r1, @r0], @r1])) [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([[1, 2, 3, 4], [1, 2]], [1, @index0, 2, @index0, 5, @index0, 7, [@index1, @index0], @index1]) +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: cel.@block([[1, 2, 3, 4], [1, 2]], [1, @index0, 2, @index0, 5, @index0, 7, [@index1, @index0], @index1]) [BLOCK_RECURSION_DEPTH_1]: cel.@block([[1, 2, 3, 4], [1, 2], [@index1, @index0]], [1, @index0, 2, @index0, 5, @index0, 7, @index2, @index1]) [BLOCK_RECURSION_DEPTH_2]: cel.@block([[1, 2, 3, 4], [1, 2]], [1, @index0, 2, @index0, 5, @index0, 7, [@index1, @index0], @index1]) [BLOCK_RECURSION_DEPTH_3]: cel.@block([[1, 2, 3, 4], [1, 2]], [1, @index0, 2, @index0, 5, @index0, 7, [@index1, @index0], @index1]) @@ -132,6 +140,7 @@ Source: msg.single_int64 + msg.single_int64 == 6 Result: true [CASCADED_BINDS]: cel.bind(@r0, msg.single_int64, @r0 + @r0) == 6 [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.single_int64], @index0 + @index0 == 6) +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: cel.@block([msg.single_int64], @index0 + @index0 == 6) [BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.single_int64, @index0 + @index0], @index1 == 6) [BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.single_int64], @index0 + @index0 == 6) [BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.single_int64], @index0 + @index0 == 6) @@ -148,6 +157,7 @@ Source: msg.oneof_type.payload.single_int64 + msg.oneof_type.payload.single_int3 Result: true [CASCADED_BINDS]: cel.bind(@r0, msg.oneof_type.payload, cel.bind(@r1, @r0.single_int64, @r1 + @r0.single_int32 + @r1) + msg.single_int64 + @r0.oneof_type.payload.single_int64) == 31 [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.oneof_type.payload, @index0.single_int64], @index1 + @index0.single_int32 + @index1 + msg.single_int64 + @index0.oneof_type.payload.single_int64 == 31) +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: cel.@block([msg.oneof_type.payload, @index0.single_int64], @index1 + @index0.single_int32 + @index1 + msg.single_int64 + @index0.oneof_type.payload.single_int64 == 31) [BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, @index1.single_int32, @index2 + @index3, @index4 + @index2, msg.single_int64, @index5 + @index6, @index1.oneof_type, @index8.payload, @index9.single_int64, @index7 + @index10], @index11 == 31) [BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type.payload, @index0.single_int64, @index1 + @index0.single_int32, @index2 + @index1 + msg.single_int64, @index0.oneof_type.payload, @index3 + @index4.single_int64], @index5 == 31) [BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type.payload.single_int64, msg.oneof_type.payload, @index0 + @index1.single_int32 + @index0, @index1.oneof_type.payload.single_int64, @index2 + msg.single_int64 + @index3], @index4 == 31) @@ -164,6 +174,7 @@ Source: true || msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.one Result: true [CASCADED_BINDS]: cel.bind(@r0, msg.oneof_type.payload.oneof_type.payload.oneof_type, true || @r0.payload.oneof_type.payload.single_bool || @r0.child.child.payload.single_bool) [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.oneof_type.payload.oneof_type.payload.oneof_type], true || @index0.payload.oneof_type.payload.single_bool || @index0.child.child.payload.single_bool) +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: cel.@block([msg.oneof_type.payload.oneof_type.payload.oneof_type], true || @index0.payload.oneof_type.payload.single_bool || @index0.child.child.payload.single_bool) [BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.oneof_type, @index2.payload, @index3.oneof_type, @index4.payload, @index5.oneof_type, @index6.payload, @index7.single_bool, true || @index8, @index4.child, @index10.child, @index11.payload, @index12.single_bool], @index9 || @index13) [BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type.payload, @index0.oneof_type.payload, @index1.oneof_type, @index2.payload.oneof_type, @index3.payload.single_bool, @index2.child.child, @index5.payload.single_bool], true || @index4 || @index6) [BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type.payload.oneof_type, @index0.payload.oneof_type, @index1.payload.oneof_type.payload, @index1.child.child.payload], true || @index2.single_bool || @index3.single_bool) @@ -180,6 +191,7 @@ Source: msg.oneof_type.payload.map_int32_int64[1] + msg.oneof_type.payload.map_i Result: true [CASCADED_BINDS]: cel.bind(@r0, msg.oneof_type.payload.map_int32_int64[1], @r0 + @r0 + @r0) == 15 [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.oneof_type.payload.map_int32_int64[1]], @index0 + @index0 + @index0 == 15) +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: cel.@block([msg.oneof_type.payload.map_int32_int64[1]], @index0 + @index0 + @index0 == 15) [BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_int32_int64, @index2[1], @index3 + @index3, @index4 + @index3], @index5 == 15) [BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type.payload, @index0.map_int32_int64[1], @index1 + @index1 + @index1], @index2 == 15) [BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type.payload.map_int32_int64, @index0[1]], @index1 + @index1 + @index1 == 15) @@ -196,6 +208,7 @@ Source: msg.oneof_type.payload.map_int32_int64[0] + msg.oneof_type.payload.map_i Result: true [CASCADED_BINDS]: cel.bind(@r0, msg.oneof_type.payload.map_int32_int64, @r0[0] + @r0[1] + @r0[2]) == 8 [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.oneof_type.payload.map_int32_int64], @index0[0] + @index0[1] + @index0[2] == 8) +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: cel.@block([msg.oneof_type.payload.map_int32_int64], @index0[0] + @index0[1] + @index0[2] == 8) [BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_int32_int64, @index2[0], @index2[1], @index3 + @index4, @index2[2], @index5 + @index6], @index7 == 8) [BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type.payload, @index0.map_int32_int64, @index1[0] + @index1[1], @index2 + @index1[2]], @index3 == 8) [BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type.payload.map_int32_int64, @index0[0] + @index0[1] + @index0[2]], @index1 == 8) @@ -212,6 +225,7 @@ Source: msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type. Result: 0 [CASCADED_BINDS]: msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload.single_int64 [BLOCK_COMMON_SUBEXPR_ONLY]: msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload.single_int64 +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: msg.oneof_type.payload.oneof_type.payload.oneof_type.payload.oneof_type.payload.single_int64 [BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.oneof_type, @index2.payload, @index3.oneof_type, @index4.payload, @index5.oneof_type, @index6.payload], @index7.single_int64) [BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type.payload, @index0.oneof_type.payload, @index1.oneof_type.payload, @index2.oneof_type.payload], @index3.single_int64) [BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type.payload.oneof_type, @index0.payload.oneof_type.payload], @index1.oneof_type.payload.single_int64) @@ -228,6 +242,7 @@ Source: (msg.single_int64 > 0 ? msg.single_int64 : 0) == 3 Result: true [CASCADED_BINDS]: cel.bind(@r0, msg.single_int64, (@r0 > 0) ? @r0 : 0) == 3 [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.single_int64], ((@index0 > 0) ? @index0 : 0) == 3) +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: cel.@block([msg.single_int64], ((@index0 > 0) ? @index0 : 0) == 3) [BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.single_int64, @index0 > 0, @index1 ? @index0 : 0], @index2 == 3) [BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.single_int64, (@index0 > 0) ? @index0 : 0], @index1 == 3) [BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.single_int64], ((@index0 > 0) ? @index0 : 0) == 3) @@ -244,6 +259,7 @@ Source: false ? false : (msg.single_int64) + ((msg.single_int64 + 1) * 2) == 11 Result: true [CASCADED_BINDS]: false ? false : (cel.bind(@r0, msg.single_int64, @r0 + (@r0 + 1) * 2) == 11) [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.single_int64], false ? false : (@index0 + (@index0 + 1) * 2 == 11)) +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: cel.@block([msg.single_int64], false ? false : (@index0 + (@index0 + 1) * 2 == 11)) [BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.single_int64, @index0 + 1, @index1 * 2, @index0 + @index2, @index3 == 11], false ? false : @index4) [BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.single_int64, (@index0 + 1) * 2, @index0 + @index1 == 11], false ? false : @index2) [BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.single_int64, @index0 + (@index0 + 1) * 2], false ? false : (@index1 == 11)) @@ -260,6 +276,7 @@ Source: (msg.single_int64 > 0 ? (msg.single_int32 > 0 ? msg.single_int64 + msg.s Result: true [CASCADED_BINDS]: cel.bind(@r0, msg.single_int64, (@r0 > 0) ? cel.bind(@r1, msg.single_int32, (@r1 > 0) ? (@r0 + @r1) : 0) : 0) == 8 [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.single_int64, msg.single_int32], ((@index0 > 0) ? ((@index1 > 0) ? (@index0 + @index1) : 0) : 0) == 8) +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: cel.@block([msg.single_int64, msg.single_int32], ((@index0 > 0) ? ((@index1 > 0) ? (@index0 + @index1) : 0) : 0) == 8) [BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.single_int64, msg.single_int32, @index0 > 0, @index1 > 0, @index0 + @index1, @index3 ? @index4 : 0, @index2 ? @index5 : 0], @index6 == 8) [BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.single_int64, msg.single_int32, (@index1 > 0) ? (@index0 + @index1) : 0, (@index0 > 0) ? @index2 : 0], @index3 == 8) [BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.single_int64, msg.single_int32, (@index0 > 0) ? ((@index1 > 0) ? (@index0 + @index1) : 0) : 0], @index2 == 8) @@ -276,6 +293,7 @@ Source: size([[1].exists(i, i > 0)]) + size([[1].exists(j, j > 0)]) + size([[2]. Result: true [CASCADED_BINDS]: cel.bind(@r1, [2], cel.bind(@r0, [1], size([@r0.exists(@it:0, @it:0 > 0)]) + size([@r0.exists(@it:1, @it:1 > 0)])) + size([@r1.exists(@it:2, @it:2 > 1)]) + size([@r1.exists(@it:3, @it:3 > 1)])) == 4 [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([size([[1].exists(@it:0:0, @it:0:0 > 0)]), size([[2].exists(@it:0:0, @it:0:0 > 1)])], @index0 + @index0 + @index1 + @index1 == 4) +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: cel.@block([[1].exists(@it:0:0, @it:0:0 > 0), size([@index0]), [2].exists(@it:0:0, @it:0:0 > 1), size([@index2])], @index1 + @index1 + @index3 + @index3 == 4) [BLOCK_RECURSION_DEPTH_1]: cel.@block([[1], @it:0:0 > 0, @ac:0:0 || @index1, [2], @it:0:0 > 1, @ac:0:0 || @index4], size([@index0.exists(@it:0:0, @index1)]) + size([@index0.exists(@it:0:0, @index1)]) + size([@index3.exists(@it:0:0, @index4)]) + size([@index3.exists(@it:0:0, @index4)]) == 4) [BLOCK_RECURSION_DEPTH_2]: cel.@block([@ac:0:0 || @it:0:0 > 0, @ac:0:0 || @it:0:0 > 1, [1], [2]], size([@index2.exists(@it:0:0, @it:0:0 > 0)]) + size([@index2.exists(@it:0:0, @it:0:0 > 0)]) + size([@index3.exists(@it:0:0, @it:0:0 > 1)]) + size([@index3.exists(@it:0:0, @it:0:0 > 1)]) == 4) [BLOCK_RECURSION_DEPTH_3]: cel.@block([[1].exists(@it:0:0, @it:0:0 > 0), [2].exists(@it:0:0, @it:0:0 > 1), size([@index0]), size([@index1]), @index2 + @index2 + @index3 + @index3], @index4 == 4) @@ -292,6 +310,7 @@ Source: [[1].exists(i, i > 0)] + [[1].exists(j, j > 0)] + [['a'].exists(k, k == Result: true [CASCADED_BINDS]: cel.bind(@r1, ["a"], cel.bind(@r0, [1], [@r0.exists(@it:0, @it:0 > 0)] + [@r0.exists(@it:1, @it:1 > 0)]) + [@r1.exists(@it:2, @it:2 == "a")] + [@r1.exists(@it:3, @it:3 == "a")]) == [true, true, true, true] [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([[[1].exists(@it:0:0, @it:0:0 > 0)], [["a"].exists(@it:0:1, @it:0:1 == "a")]], @index0 + @index0 + @index1 + @index1 == [true, true, true, true]) +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: cel.@block([[1].exists(@it:0:0, @it:0:0 > 0), [@index0], ["a"].exists(@it:0:1, @it:0:1 == "a"), [@index2]], @index1 + @index1 + @index3 + @index3 == [true, true, true, true]) [BLOCK_RECURSION_DEPTH_1]: cel.@block([[1], @it:0:0 > 0, @ac:0:0 || @index1, ["a"], @it:0:1 == "a", @ac:0:1 || @index4, [true, true, true, true]], [@index0.exists(@it:0:0, @index1)] + [@index0.exists(@it:0:0, @index1)] + [@index3.exists(@it:0:1, @index4)] + [@index3.exists(@it:0:1, @index4)] == @index6) [BLOCK_RECURSION_DEPTH_2]: cel.@block([@ac:0:0 || @it:0:0 > 0, @ac:0:1 || @it:0:1 == "a", [1], ["a"], [true, true, true, true]], [@index2.exists(@it:0:0, @it:0:0 > 0)] + [@index2.exists(@it:0:0, @it:0:0 > 0)] + [@index3.exists(@it:0:1, @it:0:1 == "a")] + [@index3.exists(@it:0:1, @it:0:1 == "a")] == @index4) [BLOCK_RECURSION_DEPTH_3]: cel.@block([[1].exists(@it:0:0, @it:0:0 > 0), ["a"].exists(@it:0:1, @it:0:1 == "a"), [@index0], [@index1], @index2 + @index2 + @index3 + @index3], @index4 == [true, true, true, true]) @@ -308,6 +327,7 @@ Source: [1].exists(i, i > 0) && [1].exists(j, j > 0) && [1].exists(k, k > 1) && Result: false [CASCADED_BINDS]: cel.bind(@r0, [1], @r0.exists(@it:0, @it:0 > 0) && @r0.exists(@it:1, @it:1 > 0) && @r0.exists(@it:2, @it:2 > 1) && [2].exists(@it:3, @it:3 > 1)) [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([[1].exists(@it:0:0, @it:0:0 > 0), @ac:0:0 || @it:0:0 > 1], @index0 && @index0 && [1].exists(@it:0:0, @it:0:0 > 1) && [2].exists(@it:0:0, @it:0:0 > 1)) +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: cel.@block([[1].exists(@it:0:0, @it:0:0 > 0)], @index0 && @index0 && [1].exists(@it:0:0, @it:0:0 > 1) && [2].exists(@it:0:0, @it:0:0 > 1)) [BLOCK_RECURSION_DEPTH_1]: cel.@block([[1], @it:0:0 > 0, @ac:0:0 || @index1, @it:0:0 > 1, @ac:0:0 || @index3, [2]], @index0.exists(@it:0:0, @index1) && @index0.exists(@it:0:0, @index1) && @index0.exists(@it:0:0, @index3) && @index5.exists(@it:0:0, @index3)) [BLOCK_RECURSION_DEPTH_2]: cel.@block([@ac:0:0 || @it:0:0 > 0, @ac:0:0 || @it:0:0 > 1, [1], [2]], @index2.exists(@it:0:0, @it:0:0 > 0) && @index2.exists(@it:0:0, @it:0:0 > 0) && @index2.exists(@it:0:0, @it:0:0 > 1) && @index3.exists(@it:0:0, @it:0:0 > 1)) [BLOCK_RECURSION_DEPTH_3]: cel.@block([[1].exists(@it:0:0, @it:0:0 > 0), @ac:0:0 || @it:0:0 > 1, [1].exists(@it:0:0, @it:0:0 > 1), [2].exists(@it:0:0, @it:0:0 > 1)], @index0 && @index0 && @index2 && @index3) @@ -324,6 +344,7 @@ Source: [1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [[2, 3, 4], [2, 3, 4], [2, 3, Result: true [CASCADED_BINDS]: cel.bind(@r0, [1, 2, 3], @r0.map(@it:1, @r0.map(@it:0, @it:0 + 1))) == cel.bind(@r1, [2, 3, 4], [@r1, @r1, @r1]) [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([[1, 2, 3], [2, 3, 4]], @index0.map(@it:0:0, @index0.map(@it:1:0, @it:1:0 + 1)) == [@index1, @index1, @index1]) +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: cel.@block([[1, 2, 3], [2, 3, 4]], @index0.map(@it:0:0, @index0.map(@it:1:0, @it:1:0 + 1)) == [@index1, @index1, @index1]) [BLOCK_RECURSION_DEPTH_1]: cel.@block([[1, 2, 3], [2, 3, 4], @it:1:0 + 1, [@index2], @ac:1:0 + @index3, [@index1, @index1, @index1]], @index0.map(@it:0:0, @index0.map(@it:1:0, @index2)) == @index5) [BLOCK_RECURSION_DEPTH_2]: cel.@block([[1, 2, 3], [2, 3, 4], [@it:1:0 + 1], @index0.map(@it:1:0, @it:1:0 + 1), @ac:0:0 + [@index3], @index0.map(@it:0:0, @index3)], @index5 == [@index1, @index1, @index1]) [BLOCK_RECURSION_DEPTH_3]: cel.@block([[1, 2, 3], [2, 3, 4], @ac:1:0 + [@it:1:0 + 1], [@index0.map(@it:1:0, @it:1:0 + 1)]], @index0.map(@it:0:0) == [@index1, @index1, @index1]) @@ -340,6 +361,7 @@ Source: [1, 2].map(y, [1, 2, 3].filter(x, x == y)) == [[1], [2]] Result: true [CASCADED_BINDS]: [1, 2].map(@it:1, [1, 2, 3].filter(@it:0, @it:0 == @it:1)) == [[1], [2]] [BLOCK_COMMON_SUBEXPR_ONLY]: [1, 2].map(@it:0:0, [1, 2, 3].filter(@it:1:0, @it:1:0 == @it:0:0)) == [[1], [2]] +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: [1, 2].map(@it:0:0, [1, 2, 3].filter(@it:1:0, @it:1:0 == @it:0:0)) == [[1], [2]] [BLOCK_RECURSION_DEPTH_1]: cel.@block([[1, 2], [1, 2, 3], @it:1:0 == @it:0:0, [@it:1:0], @ac:1:0 + @index3, @index2 ? @index4 : @ac:1:0, [1], [2], [@index6, @index7]], @index0.map(@it:0:0, @index1.filter(@it:1:0, @index2)) == @index8) [BLOCK_RECURSION_DEPTH_2]: cel.@block([@ac:1:0 + [@it:1:0], (@it:1:0 == @it:0:0) ? @index0 : @ac:1:0, [1, 2, 3].filter(@it:1:0, @it:1:0 == @it:0:0), @ac:0:0 + [@index2], [1, 2].map(@it:0:0, @index2), [[1], [2]]], @index4 == @index5) [BLOCK_RECURSION_DEPTH_3]: cel.@block([(@it:1:0 == @it:0:0) ? (@ac:1:0 + [@it:1:0]) : @ac:1:0, [[1, 2, 3].filter(@it:1:0, @it:1:0 == @it:0:0)]], [1, 2].map(@it:0:0) == [[1], [2]]) @@ -356,6 +378,7 @@ Source: [1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [1,2,3].map(j, [1, 2, 3].map( Result: true [CASCADED_BINDS]: cel.bind(@r0, [1, 2, 3], @r0.map(@it:1, @r0.map(@it:0, @it:0 + 1)) == @r0.map(@it:3, @r0.map(@it:2, @it:2 + 1))) [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([[1, 2, 3], @index0.map(@it:0:0, @index0.map(@it:1:0, @it:1:0 + 1))], @index1 == @index1) +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: cel.@block([[1, 2, 3], @index0.map(@it:0:0, @index0.map(@it:1:0, @it:1:0 + 1))], @index1 == @index1) [BLOCK_RECURSION_DEPTH_1]: cel.@block([[1, 2, 3], @it:1:0 + 1, [@index1], @ac:1:0 + @index2], @index0.map(@it:0:0, @index0.map(@it:1:0, @index1)) == @index0.map(@it:0:0, @index0.map(@it:1:0, @index1))) [BLOCK_RECURSION_DEPTH_2]: cel.@block([[@it:1:0 + 1], [1, 2, 3].map(@it:1:0, @it:1:0 + 1), @ac:0:0 + [@index1], [1, 2, 3].map(@it:0:0, @index1)], @index3 == @index3) [BLOCK_RECURSION_DEPTH_3]: cel.@block([@ac:1:0 + [@it:1:0 + 1], [[1, 2, 3].map(@it:1:0, @it:1:0 + 1)], [1, 2, 3].map(@it:0:0)], @index2 == @index2) @@ -372,6 +395,7 @@ Source: 1 in [1,2,3] && 2 in [1,2,3] && 3 in [3, [1,2,3]] && 1 in [1,2,3] Result: true [CASCADED_BINDS]: cel.bind(@r0, [1, 2, 3], cel.bind(@r1, 1 in @r0, @r1 && 2 in @r0 && 3 in [3, @r0] && @r1)) [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([[1, 2, 3], 1 in @index0], @index1 && 2 in @index0 && 3 in [3, @index0] && @index1) +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: cel.@block([[1, 2, 3], 1 in @index0], @index1 && 2 in @index0 && 3 in [3, @index0] && @index1) [BLOCK_RECURSION_DEPTH_1]: cel.@block([[1, 2, 3], 1 in @index0, 2 in @index0, @index1 && @index2, [3, @index0], 3 in @index4, @index5 && @index1], @index3 && @index6) [BLOCK_RECURSION_DEPTH_2]: cel.@block([1 in [1, 2, 3], [1, 2, 3], @index0 && 2 in @index1, 3 in [3, @index1]], @index2 && @index3 && @index0) [BLOCK_RECURSION_DEPTH_3]: cel.@block([1 in [1, 2, 3], [1, 2, 3], 3 in [3, @index1] && @index0], @index0 && 2 in @index1 && @index2) @@ -388,6 +412,7 @@ Source: 2 in {'a': 1, 2: {true: false}, 3: {true: false}} Result: true [CASCADED_BINDS]: 2 in cel.bind(@r0, {true: false}, {"a": 1, 2: @r0, 3: @r0}) [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([{true: false}], 2 in {"a": 1, 2: @index0, 3: @index0}) +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: cel.@block([{true: false}], 2 in {"a": 1, 2: @index0, 3: @index0}) [BLOCK_RECURSION_DEPTH_1]: cel.@block([{true: false}, {"a": 1, 2: @index0, 3: @index0}], 2 in @index1) [BLOCK_RECURSION_DEPTH_2]: cel.@block([{true: false}], 2 in {"a": 1, 2: @index0, 3: @index0}) [BLOCK_RECURSION_DEPTH_3]: cel.@block([{true: false}], 2 in {"a": 1, 2: @index0, 3: @index0}) @@ -404,6 +429,7 @@ Source: [1,2].map(i, [1, 2].map(i, [3,4])) == [[[3, 4], [3, 4]], [[3, 4], [3, 4] Result: true [CASCADED_BINDS]: cel.bind(@r1, [3, 4], cel.bind(@r0, [1, 2], @r0.map(@it:1, @r0.map(@it:0, @r1))) == cel.bind(@r2, [@r1, @r1], [@r2, @r2])) [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([[1, 2], [3, 4], [@index1, @index1]], @index0.map(@it:0:0, @index0.map(@it:1:0, @index1)) == [@index2, @index2]) +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: cel.@block([[1, 2], [3, 4], [@index1, @index1]], @index0.map(@it:0:0, @index0.map(@it:1:0, @index1)) == [@index2, @index2]) [BLOCK_RECURSION_DEPTH_1]: cel.@block([[1, 2], [3, 4], [@index1, @index1], [@index1], @ac:1:0 + @index3, [@index2, @index2]], @index0.map(@it:0:0, @index0.map(@it:1:0, @index1)) == @index5) [BLOCK_RECURSION_DEPTH_2]: cel.@block([[[3, 4], [3, 4]], [1, 2], [[3, 4]], @index1.map(@it:1:0, [3, 4]), @ac:0:0 + [@index3], @index1.map(@it:0:0, @index3)], @index5 == [@index0, @index0]) [BLOCK_RECURSION_DEPTH_3]: cel.@block([[[3, 4], [3, 4]], [1, 2], @ac:1:0 + [[3, 4]], [@index1.map(@it:1:0, [3, 4])]], @index1.map(@it:0:0) == [@index0, @index0]) @@ -420,6 +446,7 @@ Source: [x - 1 > 3 ? x - 1 : 5].exists(x, x - 1 > 3) || x - 1 > 3 Result: true [CASCADED_BINDS]: cel.bind(@r0, x - 1, cel.bind(@r1, @r0 > 3, [@r1 ? @r0 : 5].exists(@it:0, @it:0 - 1 > 3) || @r1)) [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([x - 1, @index0 > 3], [@index1 ? @index0 : 5].exists(@it:0:0, @it:0:0 - 1 > 3) || @index1) +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: cel.@block([x - 1, @index0 > 3], [@index1 ? @index0 : 5].exists(@it:0:0, @it:0:0 - 1 > 3) || @index1) [BLOCK_RECURSION_DEPTH_1]: cel.@block([x - 1, @index0 > 3, @index1 ? @index0 : 5, [@index2], @it:0:0 - 1, @index4 > 3, @ac:0:0 || @index5], @index3.exists(@it:0:0, @index5) || @index1) [BLOCK_RECURSION_DEPTH_2]: cel.@block([x - 1 > 3, @index0 ? (x - 1) : 5, @it:0:0 - 1 > 3, [@index1], @ac:0:0 || @index2], @index3.exists(@it:0:0, @index2) || @index0) [BLOCK_RECURSION_DEPTH_3]: cel.@block([x - 1 > 3, [@index0 ? (x - 1) : 5], @ac:0:0 || @it:0:0 - 1 > 3, @index1.exists(@it:0:0, @it:0:0 - 1 > 3)], @index3 || @index0) @@ -436,6 +463,7 @@ Source: ["foo", "bar"].map(x, [x + x, x + x]).map(x, [x + x, x + x]) Result: [[[foofoo, foofoo, foofoo, foofoo], [foofoo, foofoo, foofoo, foofoo]], [[barbar, barbar, barbar, barbar], [barbar, barbar, barbar, barbar]]] [CASCADED_BINDS]: ["foo", "bar"].map(@it:0, cel.bind(@r0, @it:0 + @it:0, [@r0, @r0])).map(@it:1, cel.bind(@r1, @it:1 + @it:1, [@r1, @r1])) [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([@it:1:0 + @it:1:0, @it:0:0 + @it:0:0], ["foo", "bar"].map(@it:1:0, [@index0, @index0]).map(@it:0:0, [@index1, @index1])) +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: ["foo", "bar"].map(@it:1:0, [@it:1:0 + @it:1:0, @it:1:0 + @it:1:0]).map(@it:0:0, [@it:0:0 + @it:0:0, @it:0:0 + @it:0:0]) [BLOCK_RECURSION_DEPTH_1]: cel.@block([@it:1:0 + @it:1:0, @it:0:0 + @it:0:0, ["foo", "bar"], [@index0, @index0], [@index3], @ac:1:0 + @index4, [@index1, @index1], [@index6], @ac:0:0 + @index7], @index2.map(@it:1:0, @index3).map(@it:0:0, @index6)) [BLOCK_RECURSION_DEPTH_2]: cel.@block([@it:1:0 + @it:1:0, @it:0:0 + @it:0:0, [[@index0, @index0]], ["foo", "bar"].map(@it:1:0, [@index0, @index0]), [[@index1, @index1]]], @index3.map(@it:0:0, [@index1, @index1])) [BLOCK_RECURSION_DEPTH_3]: cel.@block([@it:1:0 + @it:1:0, @it:0:0 + @it:0:0, @ac:1:0 + [[@index0, @index0]], @ac:0:0 + [[@index1, @index1]]], ["foo", "bar"].map(@it:1:0, [@index0, @index0]).map(@it:0:0, [@index1, @index1])) @@ -452,6 +480,7 @@ Source: has({'a': true}.a) && {'a':true}['a'] Result: true [CASCADED_BINDS]: cel.bind(@r0, {"a": true}, has(@r0.a) && @r0["a"]) [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([{"a": true}], has(@index0.a) && @index0["a"]) +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: cel.@block([{"a": true}], has(@index0.a) && @index0["a"]) [BLOCK_RECURSION_DEPTH_1]: cel.@block([{"a": true}, has(@index0.a), @index0["a"]], @index1 && @index2) [BLOCK_RECURSION_DEPTH_2]: cel.@block([{"a": true}], has(@index0.a) && @index0["a"]) [BLOCK_RECURSION_DEPTH_3]: cel.@block([{"a": true}], has(@index0.a) && @index0["a"]) @@ -468,6 +497,7 @@ Source: has({'a': true}.a) && has({'a': true}.a) Result: true [CASCADED_BINDS]: cel.bind(@r0, has({"a": true}.a), @r0 && @r0) [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([has({"a": true}.a)], @index0 && @index0) +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: cel.@block([has({"a": true}.a)], @index0 && @index0) [BLOCK_RECURSION_DEPTH_1]: cel.@block([{"a": true}, has(@index0.a)], @index1 && @index1) [BLOCK_RECURSION_DEPTH_2]: cel.@block([has({"a": true}.a)], @index0 && @index0) [BLOCK_RECURSION_DEPTH_3]: cel.@block([has({"a": true}.a)], @index0 && @index0) @@ -484,6 +514,7 @@ Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : 0) Result: true [CASCADED_BINDS]: cel.bind(@r0, msg.oneof_type, has(@r0.payload) ? @r0.payload.single_int64 : 0) == 10 [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.oneof_type], (has(@index0.payload) ? @index0.payload.single_int64 : 0) == 10) +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: cel.@block([msg.oneof_type], (has(@index0.payload) ? @index0.payload.single_int64 : 0) == 10) [BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, has(@index0.payload), @index0.payload, @index2.single_int64, @index1 ? @index3 : 0], @index4 == 10) [BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type, @index0.payload.single_int64, has(@index0.payload) ? @index1 : 0], @index2 == 10) [BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type, has(@index0.payload) ? @index0.payload.single_int64 : 0], @index1 == 10) @@ -500,6 +531,7 @@ Source: (has(msg.oneof_type.payload) ? msg.oneof_type.payload.single_int64 : msg Result: true [CASCADED_BINDS]: cel.bind(@r0, msg.oneof_type, cel.bind(@r1, @r0.payload.single_int64, has(@r0.payload) ? @r1 : (@r1 * 0))) == 10 [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.oneof_type, @index0.payload.single_int64], (has(@index0.payload) ? @index1 : (@index1 * 0)) == 10) +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: cel.@block([msg.oneof_type, @index0.payload.single_int64], (has(@index0.payload) ? @index1 : (@index1 * 0)) == 10) [BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, has(@index0.payload), @index2 * 0, @index3 ? @index2 : @index4], @index5 == 10) [BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type.payload, @index0.single_int64, has(msg.oneof_type.payload), @index2 ? @index1 : (@index1 * 0)], @index3 == 10) [BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type.payload.single_int64, has(msg.oneof_type.payload) ? @index0 : (@index0 * 0)], @index1 == 10) @@ -516,6 +548,7 @@ Source: (has(msg.oneof_type.payload.single_int64) ? msg.oneof_type.payload.singl Result: true [CASCADED_BINDS]: cel.bind(@r0, msg.oneof_type.payload, cel.bind(@r1, @r0.single_int64, has(@r0.single_int64) ? @r1 : (@r1 * 0))) == 10 [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.oneof_type.payload, @index0.single_int64], (has(@index0.single_int64) ? @index1 : (@index1 * 0)) == 10) +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: cel.@block([msg.oneof_type.payload, @index0.single_int64], (has(@index0.single_int64) ? @index1 : (@index1 * 0)) == 10) [BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, has(@index1.single_int64), @index2 * 0, @index3 ? @index2 : @index4], @index5 == 10) [BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type.payload, @index0.single_int64, has(@index0.single_int64) ? @index1 : (@index1 * 0)], @index2 == 10) [BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type.payload.single_int64, has(msg.oneof_type.payload.single_int64)], (@index1 ? @index0 : (@index0 * 0)) == 10) @@ -532,6 +565,7 @@ Source: (has(msg.oneof_type) && has(msg.oneof_type.payload) && has(msg.oneof_typ Result: true [CASCADED_BINDS]: cel.bind(@r0, msg.oneof_type, cel.bind(@r1, @r0.payload, (has(msg.oneof_type) && has(@r0.payload) && has(@r1.single_int64)) ? cel.bind(@r2, @r1.map_string_string, (has(@r1.map_string_string) && has(@r2.key)) ? (@r2.key == "A") : false) : false)) [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_string_string], (has(msg.oneof_type) && has(@index0.payload) && has(@index1.single_int64)) ? ((has(@index1.map_string_string) && has(@index2.key)) ? (@index2.key == "A") : false) : false) +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_string_string], (has(msg.oneof_type) && has(@index0.payload) && has(@index1.single_int64)) ? ((has(@index1.map_string_string) && has(@index2.key)) ? (@index2.key == "A") : false) : false) [BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.map_string_string, has(msg.oneof_type), has(@index0.payload), @index3 && @index4, has(@index1.single_int64), @index5 && @index6, has(@index1.map_string_string), has(@index2.key), @index8 && @index9, @index2.key, @index11 == "A", @index10 ? @index12 : false], @index7 ? @index13 : false) [BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type.payload, @index0.map_string_string, has(msg.oneof_type.payload), has(msg.oneof_type) && @index2, @index3 && has(@index0.single_int64), has(@index0.map_string_string) && has(@index1.key), @index1.key == "A"], @index4 ? (@index5 ? @index6 : false) : false) [BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type.payload.map_string_string, msg.oneof_type.payload, has(msg.oneof_type) && has(msg.oneof_type.payload), (has(@index1.map_string_string) && has(@index0.key)) ? (@index0.key == "A") : false], (@index2 && has(@index1.single_int64)) ? @index3 : false) @@ -548,6 +582,7 @@ Source: [10, ?optional.none(), [?optional.none(), ?opt_x], [?optional.none(), ?o Result: true [CASCADED_BINDS]: cel.bind(@r0, optional.none(), cel.bind(@r1, [?@r0, ?opt_x], [10, ?@r0, @r1, @r1])) == cel.bind(@r2, [5], [10, @r2, @r2]) [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([optional.none(), [?@index0, ?opt_x], [5]], [10, ?@index0, @index1, @index1] == [10, @index2, @index2]) +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: cel.@block([optional.none(), [?@index0, ?opt_x], [5]], [10, ?@index0, @index1, @index1] == [10, @index2, @index2]) [BLOCK_RECURSION_DEPTH_1]: cel.@block([optional.none(), [?@index0, ?opt_x], [5], [10, ?@index0, @index1, @index1], [10, @index2, @index2]], @index3 == @index4) [BLOCK_RECURSION_DEPTH_2]: cel.@block([[?optional.none(), ?opt_x], [5], [10, ?optional.none(), @index0, @index0]], @index2 == [10, @index1, @index1]) [BLOCK_RECURSION_DEPTH_3]: cel.@block([[?optional.none(), ?opt_x], [5]], [10, ?optional.none(), @index0, @index0] == [10, @index1, @index1]) @@ -564,6 +599,7 @@ Source: {?'hello': optional.of('hello')}['hello'] + {?'hello': optional.of('hell Result: true [CASCADED_BINDS]: cel.bind(@r0, {?"hello": optional.of("hello")}["hello"], @r0 + @r0) == "hellohello" [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([{?"hello": optional.of("hello")}["hello"]], @index0 + @index0 == "hellohello") +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: cel.@block([{?"hello": optional.of("hello")}["hello"]], @index0 + @index0 == "hellohello") [BLOCK_RECURSION_DEPTH_1]: cel.@block([optional.of("hello"), {?"hello": @index0}, @index1["hello"], @index2 + @index2], @index3 == "hellohello") [BLOCK_RECURSION_DEPTH_2]: cel.@block([{?"hello": optional.of("hello")}, @index0["hello"]], @index1 + @index1 == "hellohello") [BLOCK_RECURSION_DEPTH_3]: cel.@block([{?"hello": optional.of("hello")}["hello"]], @index0 + @index0 == "hellohello") @@ -580,6 +616,7 @@ Source: {?'key': optional.of('test')}[?'bogus'].or({'key': 'test'}[?'bogus']).or Result: true [CASCADED_BINDS]: cel.bind(@r0, {"key": "test"}, {?"key": optional.of("test")}[?"bogus"].or(@r0[?"bogus"]).orValue(@r0["key"])) == "test" [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([{"key": "test"}], {?"key": optional.of("test")}[?"bogus"].or(@index0[?"bogus"]).orValue(@index0["key"]) == "test") +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: cel.@block([{"key": "test"}], {?"key": optional.of("test")}[?"bogus"].or(@index0[?"bogus"]).orValue(@index0["key"]) == "test") [BLOCK_RECURSION_DEPTH_1]: cel.@block([{"key": "test"}, optional.of("test"), {?"key": @index1}, @index2[?"bogus"], @index0[?"bogus"], @index3.or(@index4), @index0["key"], @index5.orValue(@index6)], @index7 == "test") [BLOCK_RECURSION_DEPTH_2]: cel.@block([{"key": "test"}, {?"key": optional.of("test")}, @index1[?"bogus"].or(@index0[?"bogus"]), @index2.orValue(@index0["key"])], @index3 == "test") [BLOCK_RECURSION_DEPTH_3]: cel.@block([{"key": "test"}, {?"key": optional.of("test")}[?"bogus"], @index1.or(@index0[?"bogus"]).orValue(@index0["key"])], @index2 == "test") @@ -596,6 +633,7 @@ Source: TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: o Result: true [CASCADED_BINDS]: cel.bind(@r0, TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}, @r0.single_int32 + @r0.single_int64) == 5 [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}], @index0.single_int32 + @index0.single_int64 == 5) +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: cel.@block([TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}], @index0.single_int32 + @index0.single_int64 == 5) [BLOCK_RECURSION_DEPTH_1]: cel.@block([optional.ofNonZeroValue(1), optional.of(4), TestAllTypes{?single_int64: @index0, ?single_int32: @index1}, @index2.single_int32, @index2.single_int64, @index3 + @index4], @index5 == 5) [BLOCK_RECURSION_DEPTH_2]: cel.@block([TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}, @index0.single_int32 + @index0.single_int64], @index1 == 5) [BLOCK_RECURSION_DEPTH_3]: cel.@block([TestAllTypes{?single_int64: optional.ofNonZeroValue(1), ?single_int32: optional.of(4)}], @index0.single_int32 + @index0.single_int64 == 5) @@ -612,6 +650,7 @@ Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('h' + 'e' + 'l' + 'l' + Result: true [CASCADED_BINDS]: cel.bind(@r0, "h" + "e" + "l" + "l" + "o", (@r0 + " world").matches(@r0)) [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block(["h" + "e" + "l" + "l" + "o"], (@index0 + " world").matches(@index0)) +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: cel.@block(["h" + "e" + "l" + "l" + "o"], (@index0 + " world").matches(@index0)) [BLOCK_RECURSION_DEPTH_1]: cel.@block(["h" + "e", @index0 + "l", @index1 + "l", @index2 + "o", @index3 + " world"], @index4.matches(@index3)) [BLOCK_RECURSION_DEPTH_2]: cel.@block(["h" + "e" + "l", @index0 + "l" + "o"], (@index1 + " world").matches(@index1)) [BLOCK_RECURSION_DEPTH_3]: cel.@block(["h" + "e" + "l" + "l", @index0 + "o"], (@index1 + " world").matches(@index1)) @@ -628,6 +667,7 @@ Source: 'hello world'.matches('h' + 'e' + 'l' + 'l' + 'o') Result: true [CASCADED_BINDS]: "hello world".matches("h" + "e" + "l" + "l" + "o") [BLOCK_COMMON_SUBEXPR_ONLY]: "hello world".matches("h" + "e" + "l" + "l" + "o") +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: "hello world".matches("h" + "e" + "l" + "l" + "o") [BLOCK_RECURSION_DEPTH_1]: cel.@block(["h" + "e", @index0 + "l", @index1 + "l", @index2 + "o"], "hello world".matches(@index3)) [BLOCK_RECURSION_DEPTH_2]: cel.@block(["h" + "e" + "l", @index0 + "l" + "o"], "hello world".matches(@index1)) [BLOCK_RECURSION_DEPTH_3]: cel.@block(["h" + "e" + "l" + "l"], "hello world".matches(@index0 + "o")) @@ -644,6 +684,7 @@ Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('hello') Result: true [CASCADED_BINDS]: ("h" + "e" + "l" + "l" + "o" + " world").matches("hello") [BLOCK_COMMON_SUBEXPR_ONLY]: ("h" + "e" + "l" + "l" + "o" + " world").matches("hello") +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: ("h" + "e" + "l" + "l" + "o" + " world").matches("hello") [BLOCK_RECURSION_DEPTH_1]: cel.@block(["h" + "e", @index0 + "l", @index1 + "l", @index2 + "o", @index3 + " world"], @index4.matches("hello")) [BLOCK_RECURSION_DEPTH_2]: cel.@block(["h" + "e" + "l", @index0 + "l" + "o"], (@index1 + " world").matches("hello")) [BLOCK_RECURSION_DEPTH_3]: cel.@block(["h" + "e" + "l" + "l"], (@index0 + "o" + " world").matches("hello")) @@ -660,6 +701,7 @@ Source: ('h' + 'e' + 'l' + 'l' + 'o' + ' world').matches('w' + 'o' + 'r' + 'l' + Result: true [CASCADED_BINDS]: ("h" + "e" + "l" + "l" + "o" + " world").matches("w" + "o" + "r" + "l" + "d") [BLOCK_COMMON_SUBEXPR_ONLY]: ("h" + "e" + "l" + "l" + "o" + " world").matches("w" + "o" + "r" + "l" + "d") +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: ("h" + "e" + "l" + "l" + "o" + " world").matches("w" + "o" + "r" + "l" + "d") [BLOCK_RECURSION_DEPTH_1]: cel.@block(["h" + "e", @index0 + "l", @index1 + "l", @index2 + "o", @index3 + " world", "w" + "o", @index5 + "r", @index6 + "l", @index7 + "d"], @index4.matches(@index8)) [BLOCK_RECURSION_DEPTH_2]: cel.@block(["h" + "e" + "l", @index0 + "l" + "o", "w" + "o" + "r", @index2 + "l" + "d"], (@index1 + " world").matches(@index3)) [BLOCK_RECURSION_DEPTH_3]: cel.@block(["h" + "e" + "l" + "l", "w" + "o" + "r" + "l"], (@index0 + "o" + " world").matches(@index1 + "d")) @@ -676,6 +718,7 @@ Source: non_pure_custom_func(msg.oneof_type.payload.single_int64) + non_pure_cus Result: 31 [CASCADED_BINDS]: cel.bind(@r0, msg.oneof_type.payload, cel.bind(@r1, @r0.single_int64, non_pure_custom_func(@r1) + non_pure_custom_func(@r0.single_int32) + non_pure_custom_func(@r1))) + non_pure_custom_func(msg.single_int64) [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.oneof_type.payload, @index0.single_int64], non_pure_custom_func(@index1) + non_pure_custom_func(@index0.single_int32) + non_pure_custom_func(@index1) + non_pure_custom_func(msg.single_int64)) +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: cel.@block([msg.oneof_type.payload, @index0.single_int64], non_pure_custom_func(@index1) + non_pure_custom_func(@index0.single_int32) + non_pure_custom_func(@index1) + non_pure_custom_func(msg.single_int64)) [BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64], non_pure_custom_func(@index2) + non_pure_custom_func(@index1.single_int32) + non_pure_custom_func(@index2) + non_pure_custom_func(msg.single_int64)) [BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type.payload, @index0.single_int64], non_pure_custom_func(@index1) + non_pure_custom_func(@index0.single_int32) + non_pure_custom_func(@index1) + non_pure_custom_func(msg.single_int64)) [BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type.payload.single_int64], non_pure_custom_func(@index0) + non_pure_custom_func(msg.oneof_type.payload.single_int32) + non_pure_custom_func(@index0) + non_pure_custom_func(msg.single_int64)) @@ -692,6 +735,7 @@ Source: pure_custom_func(msg.oneof_type.payload.single_int64) + pure_custom_func Result: 31 [CASCADED_BINDS]: cel.bind(@r0, msg.oneof_type.payload, cel.bind(@r1, pure_custom_func(@r0.single_int64), @r1 + pure_custom_func(@r0.single_int32) + @r1)) + pure_custom_func(msg.single_int64) [BLOCK_COMMON_SUBEXPR_ONLY]: cel.@block([msg.oneof_type.payload, pure_custom_func(@index0.single_int64)], @index1 + pure_custom_func(@index0.single_int32) + @index1 + pure_custom_func(msg.single_int64)) +[BLOCK_COMMON_SUBEXPR_COMPREHENSION_STRUCTURE_RETAINED]: cel.@block([msg.oneof_type.payload, pure_custom_func(@index0.single_int64)], @index1 + pure_custom_func(@index0.single_int32) + @index1 + pure_custom_func(msg.single_int64)) [BLOCK_RECURSION_DEPTH_1]: cel.@block([msg.oneof_type, @index0.payload, @index1.single_int64, pure_custom_func(@index2), @index1.single_int32, pure_custom_func(@index4), @index3 + @index5, @index6 + @index3, msg.single_int64, pure_custom_func(@index8)], @index7 + @index9) [BLOCK_RECURSION_DEPTH_2]: cel.@block([msg.oneof_type.payload, pure_custom_func(@index0.single_int64), pure_custom_func(@index0.single_int32), @index1 + @index2 + @index1, pure_custom_func(msg.single_int64)], @index3 + @index4) [BLOCK_RECURSION_DEPTH_3]: cel.@block([msg.oneof_type.payload.single_int64, pure_custom_func(@index0), msg.oneof_type.payload.single_int32, @index1 + pure_custom_func(@index2) + @index1], @index3 + pure_custom_func(msg.single_int64)) From 502830e4535c45195470121c0eb94db4844a0697 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Wed, 21 Aug 2024 13:05:26 -0700 Subject: [PATCH 185/486] Migrate test_all_types proto over to the cel-spec variant No functional changes. This is just a test-cleanup to remove the divergent test_all_types proto. PiperOrigin-RevId: 665999916 --- WORKSPACE | 6 +- .../src/test/java/dev/cel/bundle/BUILD.bazel | 6 +- .../test/java/dev/cel/bundle/CelImplTest.java | 16 +- .../src/test/java/dev/cel/checker/BUILD.bazel | 6 +- .../cel/checker/CelCheckerLegacyImplTest.java | 6 +- .../cel/checker/CelProtoExprVisitorTest.java | 2 +- .../checker/DescriptorTypeProviderTest.java | 35 ++--- .../java/dev/cel/checker/ExprCheckerTest.java | 86 +++++------ .../checker/TypeProviderLegacyImplTest.java | 34 ++--- .../test/resources/aggregateMessage.baseline | 2 +- .../src/test/resources/anyMessage.baseline | 6 +- .../src/test/resources/dynOperators.baseline | 6 +- .../resources/dynOperatorsAtRuntime.baseline | 6 +- .../src/test/resources/enumValues.baseline | 2 +- .../src/test/resources/equalsWrapper.baseline | 14 +- .../test/resources/globalEnumValues.baseline | 2 +- .../resources/jsonStructTypeError.baseline | 2 +- .../test/resources/listElemTypeError.baseline | 4 +- .../resources/listIndexTypeError.baseline | 4 +- .../src/test/resources/listOperators.baseline | 18 +-- .../resources/listRepeatedOperators.baseline | 6 +- checker/src/test/resources/mapEmpty.baseline | 4 +- checker/src/test/resources/mapExpr.baseline | 8 +- .../src/test/resources/mapFilterExpr.baseline | 8 +- .../test/resources/mapIndexTypeError.baseline | 4 +- .../src/test/resources/mapOperators.baseline | 12 +- .../resources/messageFieldSelect.baseline | 12 +- .../messageFieldSelectError.baseline | 2 +- .../resources/namespacedVariables.baseline | 6 +- .../src/test/resources/nestedEnums.baseline | 16 +- .../test/resources/nullableMessage.baseline | 10 +- .../resources/nullablePrimitiveError.baseline | 2 +- .../test/resources/nullableWrapper.baseline | 4 +- .../resources/operatorsConditional.baseline | 4 +- checker/src/test/resources/optionals.baseline | 2 +- .../resources/proto2PrimitiveField.baseline | 10 +- .../src/test/resources/quantifiers.baseline | 8 +- .../test/resources/quantifiersErrors.baseline | 4 +- .../resources/referenceTypeAbsolute.baseline | 4 +- .../resources/referenceTypeRelative.baseline | 2 +- .../test/resources/referenceValue.baseline | 4 +- .../userFunctionAddsOverload.baseline | 6 +- checker/src/test/resources/wrapper.baseline | 4 +- common/resources/testdata/proto2/BUILD.bazel | 20 --- common/resources/testdata/proto3/BUILD.bazel | 5 - .../resources/testdata/proto2/BUILD.bazel | 59 -------- .../proto2/messages_extensions_proto2.proto | 49 ------- .../testdata/proto2/messages_proto2.proto | 44 ------ .../testdata/proto2/test_all_types.proto | 134 ----------------- .../resources/testdata/proto3/BUILD.bazel | 21 --- .../testdata/proto3/test_all_types.proto | 138 ------------------ .../test/java/dev/cel/common/ast/BUILD.bazel | 2 +- .../cel/common/ast/CelExprFormatterTest.java | 6 +- .../cel/common/ast/CelExprVisitorTest.java | 2 +- .../java/dev/cel/common/internal/BUILD.bazel | 6 +- .../internal/CombinedDescriptorPoolTest.java | 13 +- .../DefaultInstanceMessageFactoryTest.java | 2 +- .../internal/DefaultMessageFactoryTest.java | 4 +- .../common/internal/ProtoEqualityTest.java | 6 +- .../dev/cel/common/navigation/BUILD.bazel | 2 +- .../CelNavigableExprVisitorTest.java | 12 +- .../java/dev/cel/common/types/BUILD.bazel | 5 +- .../types/ProtoMessageTypeProviderTest.java | 93 ++++++------ .../java/dev/cel/common/values/BUILD.bazel | 4 +- .../values/ProtoMessageValueProviderTest.java | 16 +- .../common/values/ProtoMessageValueTest.java | 29 ++-- .../test/java/dev/cel/extensions/BUILD.bazel | 6 +- .../extensions/CelBindingsExtensionsTest.java | 2 +- .../extensions/CelOptionalLibraryTest.java | 6 +- .../extensions/CelProtoExtensionsTest.java | 124 ++++++++-------- .../cel/extensions/CelSetsExtensionsTest.java | 4 +- .../dev/cel/optimizer/AstMutatorTest.java | 4 +- .../test/java/dev/cel/optimizer/BUILD.bazel | 2 +- .../dev/cel/optimizer/optimizers/BUILD.bazel | 2 +- .../ConstantFoldingOptimizerTest.java | 4 +- .../SubexpressionOptimizerBaselineTest.java | 6 +- .../SubexpressionOptimizerTest.java | 2 +- .../src/test/java/dev/cel/policy/BUILD.bazel | 2 +- .../cel/policy/CelPolicyCompilerImplTest.java | 2 +- policy/src/test/resources/pb/config.yaml | 4 +- .../java/dev/cel/runtime/ActivationTest.java | 6 +- .../src/test/java/dev/cel/runtime/BUILD.bazel | 5 +- .../cel/runtime/CelRuntimeLegacyImplTest.java | 4 +- .../java/dev/cel/runtime/CelRuntimeTest.java | 6 +- .../DescriptorMessageProviderTest.java | 23 +-- .../dev/cel/runtime/MessageFactoryTest.java | 2 +- .../java/dev/cel/runtime/async/BUILD.bazel | 2 +- .../async/CelAsyncRuntimeImplTest.java | 2 +- .../resources/dynamicMessage_adapted.baseline | 92 ++++++------ .../dynamicMessage_dynamicDescriptor.baseline | 28 ++-- .../resources/extensionManipulation.baseline | 44 +++--- .../test/resources/fieldManipulation.baseline | 60 ++++---- runtime/src/test/resources/has.baseline | 4 +- .../test/resources/jsonValueTypes.baseline | 18 +-- runtime/src/test/resources/lists.baseline | 18 +-- runtime/src/test/resources/maps.baseline | 22 +-- runtime/src/test/resources/messages.baseline | 10 +- .../resources/namespacedVariables.baseline | 2 +- .../src/test/resources/nestedEnums.baseline | 6 +- .../src/test/resources/packUnpackAny.baseline | 28 ++-- .../test/resources/typeComparisons.baseline | 2 +- .../src/test/resources/unknownField.baseline | 14 +- .../test/resources/unknownResultSet.baseline | 82 +++++------ runtime/src/test/resources/wrappers.baseline | 6 +- .../src/main/java/dev/cel/testing/BUILD.bazel | 2 +- .../dev/cel/testing/BaseInterpreterTest.java | 24 +-- 106 files changed, 627 insertions(+), 1132 deletions(-) delete mode 100644 common/resources/testdata/proto2/BUILD.bazel delete mode 100644 common/src/main/resources/testdata/proto2/BUILD.bazel delete mode 100644 common/src/main/resources/testdata/proto2/messages_extensions_proto2.proto delete mode 100644 common/src/main/resources/testdata/proto2/messages_proto2.proto delete mode 100644 common/src/main/resources/testdata/proto2/test_all_types.proto delete mode 100644 common/src/main/resources/testdata/proto3/test_all_types.proto diff --git a/WORKSPACE b/WORKSPACE index 9ba1c3f0c..37c7cd2de 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -149,10 +149,10 @@ http_archive( # cel-spec api/expr canonical protos http_archive( name = "cel_spec", - sha256 = "b4efed0586004c538fe2be4f0472a1e2483790895493502fcab58f56060f6d37", - strip_prefix = "cel-spec-0.16.0", + sha256 = "7136e18be8881153e05229fc040f8790b634af833d28efb102da00bad640b3ea", + strip_prefix = "cel-spec-e363cad95c4da033336f1350de063b16a3e36cd2", urls = [ - "https://github.com/google/cel-spec/archive/refs/tags/v0.16.0.tar.gz", + "https://github.com/google/cel-spec/archive/e363cad95c4da033336f1350de063b16a3e36cd2.tar.gz", ], ) diff --git a/bundle/src/test/java/dev/cel/bundle/BUILD.bazel b/bundle/src/test/java/dev/cel/bundle/BUILD.bazel index f19406eec..3ca1dd570 100644 --- a/bundle/src/test/java/dev/cel/bundle/BUILD.bazel +++ b/bundle/src/test/java/dev/cel/bundle/BUILD.bazel @@ -20,11 +20,7 @@ java_library( "//common:options", "//common:proto_ast", "//common/ast", - "//common/resources/testdata/proto2:messages_extensions_proto2_java_proto", - "//common/resources/testdata/proto2:messages_proto2_java_proto", - "//common/resources/testdata/proto2:test_all_types_java_proto", "//common/resources/testdata/proto3:standalone_global_enum_java_proto", - "//common/resources/testdata/proto3:test_all_types_java_proto", "//common/testing", "//common/types", "//common/types:cel_types", @@ -38,6 +34,8 @@ java_library( "//runtime:unknown_attributes", "@@protobuf~//java/core", "@cel_spec//proto/cel/expr:expr_java_proto", + "@cel_spec//proto/test/v1/proto2:test_all_types_java_proto", + "@cel_spec//proto/test/v1/proto3:test_all_types_java_proto", "@com_google_googleapis//google/rpc/context:attribute_context_java_proto", "@com_google_googleapis//google/type:type_java_proto", "@maven//:com_google_guava_guava", diff --git a/bundle/src/test/java/dev/cel/bundle/CelImplTest.java b/bundle/src/test/java/dev/cel/bundle/CelImplTest.java index ecbac380e..db8f311e9 100644 --- a/bundle/src/test/java/dev/cel/bundle/CelImplTest.java +++ b/bundle/src/test/java/dev/cel/bundle/CelImplTest.java @@ -35,6 +35,8 @@ import dev.cel.expr.Reference; import dev.cel.expr.Type; import dev.cel.expr.Type.PrimitiveType; +import com.google.api.expr.test.v1.proto2.Proto2ExtensionScopedMessage; +import com.google.api.expr.test.v1.proto3.TestAllTypesProto.TestAllTypes; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; @@ -98,7 +100,6 @@ import dev.cel.runtime.CelVariableResolver; import dev.cel.runtime.UnknownContext; import dev.cel.testing.testdata.proto3.StandaloneGlobalEnum; -import dev.cel.testing.testdata.proto3.TestAllTypesProto.TestAllTypes; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -1021,7 +1022,7 @@ public void program_enumTypeTransitiveResolution() throws Exception { Cel cel = standardCelBuilderWithMacros() .setOptions(CelOptions.current().resolveTypeDependencies(true).build()) - .addMessageTypes(TestAllTypes.getDescriptor()) + .addMessageTypes(Proto2ExtensionScopedMessage.getDescriptor()) .setResultType(StructTypeReference.create("google.protobuf.NullValue")) .setContainer("google.protobuf") .build(); @@ -1030,7 +1031,6 @@ public void program_enumTypeTransitiveResolution() throws Exception { // enum within this 'Value' struct. // As deep type dependency is enabled, the following evaluation should work by as the // 'NullValue' enum type is transitively discovered - CelRuntime.Program program = cel.createProgram(cel.compile("Value{null_value: NullValue.NULL_VALUE}").getAst()); assertThat(program.eval()).isEqualTo(NullValue.NULL_VALUE); @@ -1055,7 +1055,7 @@ public void compile_enumTypeTransitiveResolutionFailure() { Cel cel = standardCelBuilderWithMacros() .setOptions(CelOptions.current().resolveTypeDependencies(false).build()) - .addMessageTypes(TestAllTypes.getDescriptor()) + .addMessageTypes(Proto2ExtensionScopedMessage.getDescriptor()) .setResultType(StructTypeReference.create("google.protobuf.NullValue")) .setContainer("google.protobuf") .build(); @@ -1817,13 +1817,13 @@ public void programAdvanceEvaluation_partialUnknownMessageFieldPropagates() thro .addMessageTypes(TestAllTypes.getDescriptor()) .addVar( "partialMessage1", - StructTypeReference.create("dev.cel.testing.testdata.proto3.TestAllTypes")) + StructTypeReference.create("google.api.expr.test.v1.proto3.TestAllTypes")) .addVar( "partialMessage2", - StructTypeReference.create("dev.cel.testing.testdata.proto3.TestAllTypes")) + StructTypeReference.create("google.api.expr.test.v1.proto3.TestAllTypes")) .setResultType( - StructTypeReference.create("dev.cel.testing.testdata.proto3.NestedTestAllTypes")) - .setContainer("dev.cel.testing.testdata.proto3") + StructTypeReference.create("google.api.expr.test.v1.proto3.NestedTestAllTypes")) + .setContainer("google.api.expr.test.v1.proto3") .addFunctionBindings() .build(); Program program = diff --git a/checker/src/test/java/dev/cel/checker/BUILD.bazel b/checker/src/test/java/dev/cel/checker/BUILD.bazel index 52a39a8ae..ff4b87a34 100644 --- a/checker/src/test/java/dev/cel/checker/BUILD.bazel +++ b/checker/src/test/java/dev/cel/checker/BUILD.bazel @@ -27,11 +27,7 @@ java_library( "//common/ast", "//common/internal:env_visitor", "//common/internal:errors", - "//common/resources/testdata/proto2:messages_extensions_proto2_java_proto", - "//common/resources/testdata/proto2:messages_proto2_java_proto", - "//common/resources/testdata/proto2:test_all_types_java_proto", "//common/resources/testdata/proto3:standalone_global_enum_java_proto", - "//common/resources/testdata/proto3:test_all_types_java_proto", "//common/types", "//common/types:cel_types", "//common/types:json", @@ -49,6 +45,8 @@ java_library( "//:java_truth", "@maven//:com_google_truth_extensions_truth_proto_extension", "@cel_spec//proto/cel/expr:expr_java_proto", + "@cel_spec//proto/test/v1/proto2:test_all_types_java_proto", + "@cel_spec//proto/test/v1/proto3:test_all_types_java_proto", "@com_google_googleapis//google/rpc/context:attribute_context_java_proto", "@maven//:com_google_guava_guava", ], diff --git a/checker/src/test/java/dev/cel/checker/CelCheckerLegacyImplTest.java b/checker/src/test/java/dev/cel/checker/CelCheckerLegacyImplTest.java index 1f96367f3..4e0c15576 100644 --- a/checker/src/test/java/dev/cel/checker/CelCheckerLegacyImplTest.java +++ b/checker/src/test/java/dev/cel/checker/CelCheckerLegacyImplTest.java @@ -16,12 +16,12 @@ import static com.google.common.truth.Truth.assertThat; +import com.google.api.expr.test.v1.proto3.TestAllTypesProto.TestAllTypes; import dev.cel.common.CelFunctionDecl; import dev.cel.common.CelOverloadDecl; import dev.cel.common.CelVarDecl; import dev.cel.common.types.SimpleType; import dev.cel.compiler.CelCompilerFactory; -import dev.cel.testing.testdata.proto2.TestAllTypesProto.TestAllTypes; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -63,7 +63,7 @@ public void toCheckerBuilder_collectionProperties_copied() { .addMessageTypes(TestAllTypes.getDescriptor()) .addFileTypes(TestAllTypes.getDescriptor().getFile()) .addProtoTypeMasks( - ProtoTypeMask.ofAllFields("dev.cel.testing.testdata.proto2.TestAllTypes")) + ProtoTypeMask.ofAllFields("google.api.expr.test.v1.proto3.TestAllTypes")) .addLibraries(new CelCheckerLibrary() {}); CelCheckerLegacyImpl celChecker = (CelCheckerLegacyImpl) celCheckerBuilder.build(); @@ -93,7 +93,7 @@ public void toCheckerBuilder_collectionProperties_areImmutable() { celCheckerBuilder.addMessageTypes(TestAllTypes.getDescriptor()); celCheckerBuilder.addFileTypes(TestAllTypes.getDescriptor().getFile()); celCheckerBuilder.addProtoTypeMasks( - ProtoTypeMask.ofAllFields("dev.cel.testing.testdata.proto2.TestAllTypes")); + ProtoTypeMask.ofAllFields("google.api.expr.test.v1.proto3.TestAllTypes")); celCheckerBuilder.addLibraries(new CelCheckerLibrary() {}); assertThat(newCheckerBuilder.getFunctionDecls().build()).isEmpty(); diff --git a/checker/src/test/java/dev/cel/checker/CelProtoExprVisitorTest.java b/checker/src/test/java/dev/cel/checker/CelProtoExprVisitorTest.java index 54972b931..3b598d4c7 100644 --- a/checker/src/test/java/dev/cel/checker/CelProtoExprVisitorTest.java +++ b/checker/src/test/java/dev/cel/checker/CelProtoExprVisitorTest.java @@ -19,6 +19,7 @@ import dev.cel.expr.Constant; import dev.cel.expr.Expr; +import com.google.api.expr.test.v1.proto3.TestAllTypesProto.TestAllTypes; import com.google.auto.value.AutoValue; import dev.cel.common.CelAbstractSyntaxTree; import dev.cel.common.types.SimpleType; @@ -26,7 +27,6 @@ import dev.cel.compiler.CelCompilerFactory; import dev.cel.parser.CelStandardMacro; import dev.cel.parser.Operator; -import dev.cel.testing.testdata.proto3.TestAllTypesProto.TestAllTypes; import java.util.Optional; import org.junit.Before; import org.junit.Test; diff --git a/checker/src/test/java/dev/cel/checker/DescriptorTypeProviderTest.java b/checker/src/test/java/dev/cel/checker/DescriptorTypeProviderTest.java index d7fc84202..46e3a419d 100644 --- a/checker/src/test/java/dev/cel/checker/DescriptorTypeProviderTest.java +++ b/checker/src/test/java/dev/cel/checker/DescriptorTypeProviderTest.java @@ -17,13 +17,13 @@ import static com.google.common.truth.Truth.assertThat; import dev.cel.expr.Type; +import com.google.api.expr.test.v1.proto2.TestAllTypesExtensions; +import com.google.api.expr.test.v1.proto2.TestAllTypesProto.TestAllTypes; import com.google.common.collect.ImmutableList; import com.google.rpc.context.AttributeContext; import dev.cel.checker.TypeProvider.CombinedTypeProvider; import dev.cel.checker.TypeProvider.ExtensionFieldType; import dev.cel.common.types.CelTypes; -import dev.cel.testing.testdata.proto2.MessagesProto2Extensions; -import dev.cel.testing.testdata.proto2.Proto2Message; import java.util.Arrays; import org.junit.Assert; import org.junit.Test; @@ -50,23 +50,14 @@ public void lookupFieldNames_undeclaredMessageType() { @Test public void lookupFieldNames_groupTypeField() throws Exception { - Type proto2MessageType = - CelTypes.createMessage("dev.cel.testing.testdata.proto2.Proto2Message"); + Type proto2MessageType = CelTypes.createMessage("google.api.expr.test.v1.proto2.TestAllTypes"); TypeProvider typeProvider = new DescriptorTypeProvider( ImmutableList.of( - Proto2Message.getDescriptor().getFile(), MessagesProto2Extensions.getDescriptor())); - assertThat(typeProvider.lookupFieldNames(proto2MessageType)) - .containsExactly( - "single_nested_test_all_types", - "single_enum", - "nestedgroup", - "single_int32", - "single_fixed32", - "single_fixed64"); + TestAllTypes.getDescriptor().getFile(), TestAllTypesExtensions.getDescriptor())); assertThat(typeProvider.lookupFieldType(proto2MessageType, "nestedgroup").type()) .isEqualTo( - CelTypes.createMessage("dev.cel.testing.testdata.proto2.Proto2Message.NestedGroup")); + CelTypes.createMessage("google.api.expr.test.v1.proto2.TestAllTypes.NestedGroup")); } @Test @@ -103,43 +94,41 @@ public void lookupExtensionType_combinedProvider() { final TypeProvider configuredProvider = new DescriptorTypeProvider( ImmutableList.of( - Proto2Message.getDescriptor().getFile(), MessagesProto2Extensions.getDescriptor())); + TestAllTypes.getDescriptor().getFile(), TestAllTypesExtensions.getDescriptor())); final TypeProvider partialProvider = // The partial provider has no extension lookup. makePartialTypeProvider(configuredProvider); final TypeProvider typeProvider = new CombinedTypeProvider(ImmutableList.of(partialProvider, configuredProvider)); - final Type messageType = - CelTypes.createMessage("dev.cel.testing.testdata.proto2.Proto2Message"); + final Type messageType = CelTypes.createMessage("google.api.expr.test.v1.proto2.TestAllTypes"); assertThat(typeProvider.lookupExtensionType("non.existent")).isNull(); ExtensionFieldType nestedExt = - typeProvider.lookupExtensionType("dev.cel.testing.testdata.proto2.nested_ext"); + typeProvider.lookupExtensionType("google.api.expr.test.v1.proto2.nested_ext"); assertThat(nestedExt).isNotNull(); assertThat(nestedExt.fieldType().type()).isEqualTo(messageType); assertThat(nestedExt.messageType()).isEqualTo(messageType); ExtensionFieldType int32Ext = - typeProvider.lookupExtensionType("dev.cel.testing.testdata.proto2.int32_ext"); + typeProvider.lookupExtensionType("google.api.expr.test.v1.proto2.int32_ext"); assertThat(int32Ext).isNotNull(); assertThat(int32Ext.fieldType().type()).isEqualTo(CelTypes.INT64); assertThat(int32Ext.messageType()).isEqualTo(messageType); ExtensionFieldType repeatedExt = - typeProvider.lookupExtensionType( - "dev.cel.testing.testdata.proto2.repeated_string_holder_ext"); + typeProvider.lookupExtensionType("google.api.expr.test.v1.proto2.repeated_test_all_types"); assertThat(repeatedExt).isNotNull(); assertThat(repeatedExt.fieldType().type()) .isEqualTo( CelTypes.createList( - CelTypes.createMessage("dev.cel.testing.testdata.proto2.StringHolder"))); + CelTypes.createMessage("google.api.expr.test.v1.proto2.TestAllTypes"))); assertThat(repeatedExt.messageType()).isEqualTo(messageType); // With leading dot '.'. assertThat( typeProvider.lookupExtensionType( - ".dev.cel.testing.testdata.proto2.repeated_string_holder_ext")) + ".google.api.expr.test.v1.proto2.repeated_test_all_types")) .isNotNull(); } diff --git a/checker/src/test/java/dev/cel/checker/ExprCheckerTest.java b/checker/src/test/java/dev/cel/checker/ExprCheckerTest.java index 9217942c1..c232441fc 100644 --- a/checker/src/test/java/dev/cel/checker/ExprCheckerTest.java +++ b/checker/src/test/java/dev/cel/checker/ExprCheckerTest.java @@ -31,6 +31,8 @@ import dev.cel.expr.Type; import dev.cel.expr.Type.AbstractType; import dev.cel.expr.Type.PrimitiveType; +import com.google.api.expr.test.v1.proto2.TestAllTypesProto; +import com.google.api.expr.test.v1.proto3.TestAllTypesProto.TestAllTypes; import com.google.common.base.Joiner; import com.google.common.base.Optional; import com.google.common.collect.ImmutableList; @@ -48,9 +50,7 @@ import dev.cel.testing.CelAdorner; import dev.cel.testing.CelBaselineTestCase; import dev.cel.testing.CelDebug; -import dev.cel.testing.testdata.proto2.Proto2Message; import dev.cel.testing.testdata.proto3.StandaloneGlobalEnum; -import dev.cel.testing.testdata.proto3.TestAllTypesProto.TestAllTypes; import java.util.Arrays; import org.junit.Test; import org.junit.runner.RunWith; @@ -74,7 +74,9 @@ public ExprCheckerTest(TestCase testCase) { /** Helper to run a test for configured instance variables. */ private void runTest() throws Exception { CelAbstractSyntaxTree ast = - prepareTest(Arrays.asList(TestAllTypes.getDescriptor(), Proto2Message.getDescriptor())); + prepareTest( + Arrays.asList( + TestAllTypes.getDescriptor(), TestAllTypesProto.TestAllTypes.getDescriptor())); if (ast != null) { testOutput() .println( @@ -150,7 +152,7 @@ public void operatorsBytes() throws Exception { @Test public void operatorsConditional() throws Exception { - declareVariable("x", createMessage("dev.cel.testing.testdata.proto3.TestAllTypes")); + declareVariable("x", createMessage("google.api.expr.test.v1.proto3.TestAllTypes")); source = "false ? x.single_timestamp : null"; runTest(); } @@ -161,19 +163,19 @@ public void operatorsConditional() throws Exception { @Test public void referenceTypeRelative() throws Exception { source = "proto3.TestAllTypes"; - container = "dev.cel.testing.testdata"; + container = "google.api.expr.test.v1.TestAllTypes"; runTest(); } @Test public void referenceTypeAbsolute() throws Exception { - source = ".dev.cel.testing.testdata.proto3.TestAllTypes"; + source = ".google.api.expr.test.v1.proto3.TestAllTypes"; runTest(); } @Test public void referenceValue() throws Exception { - declareVariable("container.x", createMessage("dev.cel.testing.testdata.proto3.TestAllTypes")); + declareVariable("container.x", createMessage("google.api.expr.test.v1.proto3.TestAllTypes")); source = "x"; container = "container"; runTest(); @@ -194,15 +196,15 @@ public void anyMessage() throws Exception { declareVariable("y", createWrapper(PrimitiveType.INT64)); source = "x == google.protobuf.Any{" - + "type_url:'types.googleapis.com/dev.cel.testing.testdata.proto3.TestAllTypes'}" + + "type_url:'types.googleapis.com/google.api.expr.test.v1.proto3.TestAllTypes'}" + " && x.single_nested_message.bb == 43 || x ==" - + " dev.cel.testing.testdata.proto3.TestAllTypes{} || y < x|| x >= x"; + + " google.api.expr.test.v1.proto3.TestAllTypes{} || y < x|| x >= x"; runTest(); } @Test public void messageFieldSelect() throws Exception { - declareVariable("x", createMessage("dev.cel.testing.testdata.proto3.TestAllTypes")); + declareVariable("x", createMessage("google.api.expr.test.v1.proto3.TestAllTypes")); source = "x.single_nested_message.bb == 43 && has(x.single_nested_message) && has(x.single_int32)" + " && has(x.repeated_int32) && has(x.map_int64_nested_type)"; @@ -211,7 +213,7 @@ public void messageFieldSelect() throws Exception { @Test public void messageFieldSelectError() throws Exception { - declareVariable("x", createMessage("dev.cel.testing.testdata.proto3.TestAllTypes")); + declareVariable("x", createMessage("google.api.expr.test.v1.proto3.TestAllTypes")); source = "x.single_nested_message.undefined == x.undefined"; runTest(); } @@ -221,7 +223,7 @@ public void messageFieldSelectError() throws Exception { @Test public void listOperators() throws Exception { - declareVariable("x", createList(createMessage("dev.cel.testing.testdata.proto3.TestAllTypes"))); + declareVariable("x", createList(createMessage("google.api.expr.test.v1.proto3.TestAllTypes"))); source = "(x + x)[1].single_int32 == size(x)"; runTest(); @@ -231,14 +233,14 @@ public void listOperators() throws Exception { @Test public void listRepeatedOperators() throws Exception { - declareVariable("x", createMessage("dev.cel.testing.testdata.proto3.TestAllTypes")); + declareVariable("x", createMessage("google.api.expr.test.v1.proto3.TestAllTypes")); source = "x.repeated_int64[x.single_int32] == 23"; runTest(); } @Test public void listIndexTypeError() throws Exception { - declareVariable("x", createList(createMessage("dev.cel.testing.testdata.proto3.TestAllTypes"))); + declareVariable("x", createList(createMessage("google.api.expr.test.v1.proto3.TestAllTypes"))); source = "x[1u]"; runTest(); } @@ -251,7 +253,7 @@ public void identError() throws Exception { @Test public void listElemTypeError() throws Exception { - declareVariable("x", createList(createMessage("dev.cel.testing.testdata.proto3.TestAllTypes"))); + declareVariable("x", createList(createMessage("google.api.expr.test.v1.proto3.TestAllTypes"))); declareVariable("y", createList(CelTypes.INT64)); source = "x + y"; runTest(); @@ -264,7 +266,7 @@ public void listElemTypeError() throws Exception { public void mapOperators() throws Exception { declareVariable( "x", - createMap(CelTypes.STRING, createMessage("dev.cel.testing.testdata.proto3.TestAllTypes"))); + createMap(CelTypes.STRING, createMessage("google.api.expr.test.v1.proto3.TestAllTypes"))); source = "x[\"a\"].single_int32 == 23"; runTest(); @@ -276,14 +278,14 @@ public void mapOperators() throws Exception { public void mapIndexTypeError() throws Exception { declareVariable( "x", - createMap(CelTypes.STRING, createMessage("dev.cel.testing.testdata.proto3.TestAllTypes"))); + createMap(CelTypes.STRING, createMessage("google.api.expr.test.v1.proto3.TestAllTypes"))); source = "x[2].single_int32 == 23"; runTest(); } @Test public void mapEmpty() throws Exception { - declareVariable("x", createMessage("dev.cel.testing.testdata.proto3.TestAllTypes")); + declareVariable("x", createMessage("google.api.expr.test.v1.proto3.TestAllTypes")); source = "size(x.map_int64_nested_type) == 0"; runTest(); } @@ -293,14 +295,14 @@ public void mapEmpty() throws Exception { @Test public void wrapper() throws Exception { - declareVariable("x", createMessage("dev.cel.testing.testdata.proto3.TestAllTypes")); + declareVariable("x", createMessage("google.api.expr.test.v1.proto3.TestAllTypes")); source = "x.single_int64_wrapper + 1 != 23"; runTest(); } @Test public void equalsWrapper() throws Exception { - declareVariable("x", createMessage("dev.cel.testing.testdata.proto3.TestAllTypes")); + declareVariable("x", createMessage("google.api.expr.test.v1.proto3.TestAllTypes")); source = "x.single_int64_wrapper == 1 && " + "x.single_int32_wrapper != 2 && " @@ -316,18 +318,18 @@ public void equalsWrapper() throws Exception { @Test public void nullableWrapper() throws Exception { - declareVariable("x", createMessage("dev.cel.testing.testdata.proto3.TestAllTypes")); + declareVariable("x", createMessage("google.api.expr.test.v1.proto3.TestAllTypes")); source = "x.single_int64_wrapper == null"; runTest(); } @Test public void nullableMessage() throws Exception { - declareVariable("x", createMessage("dev.cel.testing.testdata.proto3.TestAllTypes")); + declareVariable("x", createMessage("google.api.expr.test.v1.proto3.TestAllTypes")); source = "x.single_nested_message != null"; runTest(); - container = "dev.cel.testing.testdata.proto3.TestAllTypesProto"; + container = "google.api.expr.test.v1.proto3.TestAllTypesProto"; source = "null == TestAllTypes{} || TestAllTypes{} == null"; runTest(); } @@ -340,7 +342,7 @@ public void nullNull() throws Exception { @Test public void nullablePrimitiveError() throws Exception { - declareVariable("x", createMessage("dev.cel.testing.testdata.proto3.TestAllTypes")); + declareVariable("x", createMessage("google.api.expr.test.v1.proto3.TestAllTypes")); source = "x.single_int64 != null"; runTest(); } @@ -350,14 +352,14 @@ public void nullablePrimitiveError() throws Exception { @Test public void dynOperators() throws Exception { - declareVariable("x", createMessage("dev.cel.testing.testdata.proto3.TestAllTypes")); + declareVariable("x", createMessage("google.api.expr.test.v1.proto3.TestAllTypes")); source = "x.single_value + 1 / x.single_struct.y == 23"; runTest(); } @Test public void dynOperatorsAtRuntime() throws Exception { - declareVariable("x", createMessage("dev.cel.testing.testdata.proto3.TestAllTypes")); + declareVariable("x", createMessage("google.api.expr.test.v1.proto3.TestAllTypes")); source = "x.single_value[23] + x.single_struct['y']"; runTest(); } @@ -492,9 +494,9 @@ public void namespacedVariables() throws Exception { source = "x"; runTest(); - container = "dev.cel.testing.testdata.proto3"; - Type messageType = createMessage("dev.cel.testing.testdata.proto3.TestAllTypes"); - declareVariable("dev.cel.testing.testdata.proto3.msgVar", messageType); + container = "google.api.expr.test.v1.proto3"; + Type messageType = createMessage("google.api.expr.test.v1.proto3.TestAllTypes"); + declareVariable("google.api.expr.test.v1.proto3.msgVar", messageType); source = "msgVar.single_int32"; runTest(); } @@ -531,7 +533,7 @@ public void userFunctionOverlaps() throws Exception { @Test public void userFunctionAddsOverload() throws Exception { - Type messageType = createMessage("dev.cel.testing.testdata.proto3.TestAllTypes"); + Type messageType = createMessage("google.api.expr.test.v1.proto3.TestAllTypes"); declareVariable("x", messageType); declareFunction( "size", globalOverload("size_message", ImmutableList.of(messageType), CelTypes.INT64)); @@ -551,7 +553,7 @@ public void userFunctionAddsMacroError() throws Exception { @Test public void proto2PrimitiveField() throws Exception { - declareVariable("x", createMessage("dev.cel.testing.testdata.proto2.Proto2Message")); + declareVariable("x", createMessage("google.api.expr.test.v1.proto2.TestAllTypes")); source = "x.single_fixed32 != 0u && x.single_fixed64 > 1u && x.single_int32 != null"; runTest(); source = "x.nestedgroup.single_name == ''"; @@ -563,21 +565,21 @@ public void proto2PrimitiveField() throws Exception { @Test public void aggregateMessage() throws Exception { - container = "dev.cel.testing.testdata.proto3.TestAllTypesProto"; + container = "google.api.expr.test.v1.proto3.TestAllTypesProto"; source = "TestAllTypes{single_int32: 1, single_int64: 2}"; runTest(); } @Test public void aggregateMessageFieldUndefinedError() throws Exception { - container = "dev.cel.testing.testdata.proto3.TestAllTypesProto"; + container = "google.api.expr.test.v1.proto3.TestAllTypesProto"; source = "TestAllTypes{single_int32: 1, undefined: 2}"; runTest(); } @Test public void aggregateMessageFieldTypeError() throws Exception { - container = "dev.cel.testing.testdata.proto3.TestAllTypesProto"; + container = "google.api.expr.test.v1.proto3.TestAllTypesProto"; source = "TestAllTypes{single_int32: 1u}"; runTest(); } @@ -661,7 +663,7 @@ public void types() throws Exception { @Test public void enumValues() throws Exception { - container = "dev.cel.testing.testdata.proto3.TestAllTypesProto"; + container = "google.api.expr.test.v1.proto3.TestAllTypesProto"; source = "TestAllTypes.NestedEnum.BAR != 99"; runTest(); } @@ -684,7 +686,7 @@ public void nestedEnums() throws Exception { @Test public void globalEnumValues() throws Exception { - container = "dev.cel.testing.testdata.proto3.TestAllTypesProto"; + container = "google.api.expr.test.v1.proto3.TestAllTypesProto"; source = "GlobalEnum.GAZ == 2"; runTest(); } @@ -724,7 +726,7 @@ public void conversions() throws Exception { @Test public void quantifiers() throws Exception { - Type messageType = createMessage("dev.cel.testing.testdata.proto3.TestAllTypes"); + Type messageType = createMessage("google.api.expr.test.v1.proto3.TestAllTypes"); declareVariable("x", messageType); source = "x.repeated_int64.all(e, e > 0) " @@ -735,7 +737,7 @@ public void quantifiers() throws Exception { @Test public void quantifiersErrors() throws Exception { - Type messageType = createMessage("dev.cel.testing.testdata.proto3.TestAllTypes"); + Type messageType = createMessage("google.api.expr.test.v1.proto3.TestAllTypes"); declareVariable("x", messageType); source = "x.all(e, 0)"; runTest(); @@ -743,7 +745,7 @@ public void quantifiersErrors() throws Exception { @Test public void mapExpr() throws Exception { - Type messageType = createMessage("dev.cel.testing.testdata.proto3.TestAllTypes"); + Type messageType = createMessage("google.api.expr.test.v1.proto3.TestAllTypes"); declareVariable("x", messageType); source = "x.repeated_int64.map(x, double(x))"; runTest(); @@ -757,7 +759,7 @@ public void mapExpr() throws Exception { @Test public void mapFilterExpr() throws Exception { - Type messageType = createMessage("dev.cel.testing.testdata.proto3.TestAllTypes"); + Type messageType = createMessage("google.api.expr.test.v1.proto3.TestAllTypes"); declareVariable("x", messageType); source = "x.repeated_int64.map(x, x > 0, double(x))"; runTest(); @@ -924,7 +926,7 @@ public void optionals() throws Exception { source = "{?'key': {'a': 'b'}.?value}.key"; runTest(); - container = "dev.cel.testing.testdata.proto3.TestAllTypesProto"; + container = "google.api.expr.test.v1.proto3.TestAllTypesProto"; source = "TestAllTypes{?single_int32: {}.?i}"; runTest(); @@ -949,7 +951,7 @@ public void optionalErrors() throws Exception { source = "[?'value']"; runTest(); - container = "dev.cel.testing.testdata.proto3.TestAllTypesProto"; + container = "google.api.expr.test.v1.proto3.TestAllTypesProto"; source = "TestAllTypes{?single_int32: 1}"; runTest(); diff --git a/checker/src/test/java/dev/cel/checker/TypeProviderLegacyImplTest.java b/checker/src/test/java/dev/cel/checker/TypeProviderLegacyImplTest.java index bd6635666..9195bb3d5 100644 --- a/checker/src/test/java/dev/cel/checker/TypeProviderLegacyImplTest.java +++ b/checker/src/test/java/dev/cel/checker/TypeProviderLegacyImplTest.java @@ -18,14 +18,13 @@ import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; import dev.cel.expr.Type; +import com.google.api.expr.test.v1.proto2.Proto2ExtensionScopedMessage; +import com.google.api.expr.test.v1.proto2.TestAllTypesProto.TestAllTypes; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.protobuf.Descriptors.Descriptor; import dev.cel.common.types.CelTypes; import dev.cel.common.types.ProtoMessageTypeProvider; -import dev.cel.testing.testdata.proto2.Proto2ExtensionScopedMessage; -import dev.cel.testing.testdata.proto2.Proto2Message; -import dev.cel.testing.testdata.proto2.TestAllTypesProto.TestAllTypes; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -34,10 +33,7 @@ public final class TypeProviderLegacyImplTest { private static final ImmutableList DESCRIPTORS = - ImmutableList.of( - TestAllTypes.getDescriptor(), - Proto2Message.getDescriptor(), - Proto2ExtensionScopedMessage.getDescriptor()); + ImmutableList.of(TestAllTypes.getDescriptor(), Proto2ExtensionScopedMessage.getDescriptor()); private final ProtoMessageTypeProvider proto2Provider = new ProtoMessageTypeProvider(DESCRIPTORS); @@ -60,7 +56,7 @@ public void lookupType() { public void lookupFieldNames() { Type nestedTestAllTypes = compatTypeProvider - .lookupType("dev.cel.testing.testdata.proto2.NestedTestAllTypes") + .lookupType("google.api.expr.test.v1.proto2.NestedTestAllTypes") .getType(); ImmutableSet fieldNames = compatTypeProvider.lookupFieldNames(nestedTestAllTypes); assertThat(fieldNames) @@ -72,7 +68,7 @@ public void lookupFieldNames() { public void lookupFieldType() { Type nestedTestAllTypes = compatTypeProvider - .lookupType("dev.cel.testing.testdata.proto2.NestedTestAllTypes") + .lookupType("google.api.expr.test.v1.proto2.NestedTestAllTypes") .getType(); assertThat(compatTypeProvider.lookupFieldType(nestedTestAllTypes, "payload")) .isEqualTo(descriptorTypeProvider.lookupFieldType(nestedTestAllTypes, "payload")); @@ -83,7 +79,7 @@ public void lookupFieldType() { @Test public void lookupFieldType_inputNotMessage() { Type globalEnumType = - compatTypeProvider.lookupType("dev.cel.testing.testdata.proto2.GlobalEnum").getType(); + compatTypeProvider.lookupType("google.api.expr.test.v1.proto2.GlobalEnum").getType(); assertThat(compatTypeProvider.lookupFieldType(globalEnumType, "payload")).isNull(); assertThat(compatTypeProvider.lookupFieldType(globalEnumType, "payload")) .isEqualTo(descriptorTypeProvider.lookupFieldType(globalEnumType, "payload")); @@ -92,47 +88,47 @@ public void lookupFieldType_inputNotMessage() { @Test public void lookupExtension() { TypeProvider.ExtensionFieldType extensionType = - compatTypeProvider.lookupExtensionType("dev.cel.testing.testdata.proto2.nested_enum_ext"); + compatTypeProvider.lookupExtensionType("google.api.expr.test.v1.proto2.nested_enum_ext"); assertThat(extensionType.messageType()) - .isEqualTo(CelTypes.createMessage("dev.cel.testing.testdata.proto2.Proto2Message")); + .isEqualTo(CelTypes.createMessage("google.api.expr.test.v1.proto2.TestAllTypes")); assertThat(extensionType.fieldType().type()).isEqualTo(CelTypes.INT64); assertThat(extensionType) .isEqualTo( descriptorTypeProvider.lookupExtensionType( - "dev.cel.testing.testdata.proto2.nested_enum_ext")); + "google.api.expr.test.v1.proto2.nested_enum_ext")); } @Test public void lookupEnumValue() { Integer enumValue = - compatTypeProvider.lookupEnumValue("dev.cel.testing.testdata.proto2.GlobalEnum.GAR"); + compatTypeProvider.lookupEnumValue("google.api.expr.test.v1.proto2.GlobalEnum.GAR"); assertThat(enumValue).isEqualTo(1); assertThat(enumValue) .isEqualTo( descriptorTypeProvider.lookupEnumValue( - "dev.cel.testing.testdata.proto2.GlobalEnum.GAR")); + "google.api.expr.test.v1.proto2.GlobalEnum.GAR")); } @Test public void lookupEnumValue_notFoundValue() { Integer enumValue = - compatTypeProvider.lookupEnumValue("dev.cel.testing.testdata.proto2.GlobalEnum.BAR"); + compatTypeProvider.lookupEnumValue("google.api.expr.test.v1.proto2.GlobalEnum.BAR"); assertThat(enumValue).isNull(); assertThat(enumValue) .isEqualTo( descriptorTypeProvider.lookupEnumValue( - "dev.cel.testing.testdata.proto2.GlobalEnum.BAR")); + "google.api.expr.test.v1.proto2.GlobalEnum.BAR")); } @Test public void lookupEnumValue_notFoundEnumType() { Integer enumValue = - compatTypeProvider.lookupEnumValue("dev.cel.testing.testdata.proto2.InvalidEnum.TEST"); + compatTypeProvider.lookupEnumValue("google.api.expr.test.v1.proto2.InvalidEnum.TEST"); assertThat(enumValue).isNull(); assertThat(enumValue) .isEqualTo( descriptorTypeProvider.lookupEnumValue( - "dev.cel.testing.testdata.proto2.InvalidEnum.TEST")); + "google.api.expr.test.v1.proto2.InvalidEnum.TEST")); } @Test diff --git a/checker/src/test/resources/aggregateMessage.baseline b/checker/src/test/resources/aggregateMessage.baseline index 646c6e15b..506b5deb6 100644 --- a/checker/src/test/resources/aggregateMessage.baseline +++ b/checker/src/test/resources/aggregateMessage.baseline @@ -3,5 +3,5 @@ Source: TestAllTypes{single_int32: 1, single_int64: 2} TestAllTypes{ single_int32:1~int, single_int64:2~int -}~dev.cel.testing.testdata.proto3.TestAllTypes^dev.cel.testing.testdata.proto3.TestAllTypes +}~google.api.expr.test.v1.proto3.TestAllTypes^google.api.expr.test.v1.proto3.TestAllTypes diff --git a/checker/src/test/resources/anyMessage.baseline b/checker/src/test/resources/anyMessage.baseline index 55aedb13f..83b50bac3 100644 --- a/checker/src/test/resources/anyMessage.baseline +++ b/checker/src/test/resources/anyMessage.baseline @@ -1,4 +1,4 @@ -Source: x == google.protobuf.Any{type_url:'types.googleapis.com/dev.cel.testing.testdata.proto3.TestAllTypes'} && x.single_nested_message.bb == 43 || x == dev.cel.testing.testdata.proto3.TestAllTypes{} || y < x|| x >= x +Source: x == google.protobuf.Any{type_url:'types.googleapis.com/google.api.expr.test.v1.proto3.TestAllTypes'} && x.single_nested_message.bb == 43 || x == google.api.expr.test.v1.proto3.TestAllTypes{} || y < x|| x >= x declare x { value any } @@ -12,7 +12,7 @@ _||_( _==_( x~any^x, google.protobuf.Any{ - type_url:"types.googleapis.com/dev.cel.testing.testdata.proto3.TestAllTypes"~string + type_url:"types.googleapis.com/google.api.expr.test.v1.proto3.TestAllTypes"~string }~any^google.protobuf.Any )~bool^equals, _==_( @@ -22,7 +22,7 @@ _||_( )~bool^logical_and, _==_( x~any^x, - dev.cel.testing.testdata.proto3.TestAllTypes{}~dev.cel.testing.testdata.proto3.TestAllTypes^dev.cel.testing.testdata.proto3.TestAllTypes + google.api.expr.test.v1.proto3.TestAllTypes{}~google.api.expr.test.v1.proto3.TestAllTypes^google.api.expr.test.v1.proto3.TestAllTypes )~bool^equals )~bool^logical_or, _||_( diff --git a/checker/src/test/resources/dynOperators.baseline b/checker/src/test/resources/dynOperators.baseline index e95cbbb86..ae4ea2c41 100644 --- a/checker/src/test/resources/dynOperators.baseline +++ b/checker/src/test/resources/dynOperators.baseline @@ -1,14 +1,14 @@ Source: x.single_value + 1 / x.single_struct.y == 23 declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> _==_( _+_( - x~dev.cel.testing.testdata.proto3.TestAllTypes^x.single_value~dyn, + x~google.api.expr.test.v1.proto3.TestAllTypes^x.single_value~dyn, _/_( 1~int, - x~dev.cel.testing.testdata.proto3.TestAllTypes^x.single_struct~map(string, dyn).y~dyn + x~google.api.expr.test.v1.proto3.TestAllTypes^x.single_struct~map(string, dyn).y~dyn )~int^divide_int64 )~int^add_int64, 23~int diff --git a/checker/src/test/resources/dynOperatorsAtRuntime.baseline b/checker/src/test/resources/dynOperatorsAtRuntime.baseline index 2a347d6ee..8730c3c35 100644 --- a/checker/src/test/resources/dynOperatorsAtRuntime.baseline +++ b/checker/src/test/resources/dynOperatorsAtRuntime.baseline @@ -1,15 +1,15 @@ Source: x.single_value[23] + x.single_struct['y'] declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> _+_( _[_]( - x~dev.cel.testing.testdata.proto3.TestAllTypes^x.single_value~dyn, + x~google.api.expr.test.v1.proto3.TestAllTypes^x.single_value~dyn, 23~int )~dyn^index_list|index_map, _[_]( - x~dev.cel.testing.testdata.proto3.TestAllTypes^x.single_struct~map(string, dyn), + x~google.api.expr.test.v1.proto3.TestAllTypes^x.single_struct~map(string, dyn), "y"~string )~dyn^index_map )~dyn^add_int64|add_uint64|add_double|add_string|add_bytes|add_list|add_timestamp_duration|add_duration_timestamp|add_duration_duration diff --git a/checker/src/test/resources/enumValues.baseline b/checker/src/test/resources/enumValues.baseline index 2bad4ad99..b861e12d7 100644 --- a/checker/src/test/resources/enumValues.baseline +++ b/checker/src/test/resources/enumValues.baseline @@ -1,6 +1,6 @@ Source: TestAllTypes.NestedEnum.BAR != 99 =====> _!=_( - dev.cel.testing.testdata.proto3.TestAllTypes.NestedEnum.BAR~int^dev.cel.testing.testdata.proto3.TestAllTypes.NestedEnum.BAR, + google.api.expr.test.v1.proto3.TestAllTypes.NestedEnum.BAR~int^google.api.expr.test.v1.proto3.TestAllTypes.NestedEnum.BAR, 99~int )~bool^not_equals diff --git a/checker/src/test/resources/equalsWrapper.baseline b/checker/src/test/resources/equalsWrapper.baseline index c069c9625..0f7fdbe4e 100644 --- a/checker/src/test/resources/equalsWrapper.baseline +++ b/checker/src/test/resources/equalsWrapper.baseline @@ -1,38 +1,38 @@ Source: x.single_int64_wrapper == 1 && x.single_int32_wrapper != 2 && x.single_double_wrapper != 2.0 && x.single_float_wrapper == 1.0 && x.single_uint32_wrapper == 1u && x.single_uint64_wrapper != 42u declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> _&&_( _&&_( _&&_( _==_( - x~dev.cel.testing.testdata.proto3.TestAllTypes^x.single_int64_wrapper~wrapper(int), + x~google.api.expr.test.v1.proto3.TestAllTypes^x.single_int64_wrapper~wrapper(int), 1~int )~bool^equals, _!=_( - x~dev.cel.testing.testdata.proto3.TestAllTypes^x.single_int32_wrapper~wrapper(int), + x~google.api.expr.test.v1.proto3.TestAllTypes^x.single_int32_wrapper~wrapper(int), 2~int )~bool^not_equals )~bool^logical_and, _!=_( - x~dev.cel.testing.testdata.proto3.TestAllTypes^x.single_double_wrapper~wrapper(double), + x~google.api.expr.test.v1.proto3.TestAllTypes^x.single_double_wrapper~wrapper(double), 2.0~double )~bool^not_equals )~bool^logical_and, _&&_( _&&_( _==_( - x~dev.cel.testing.testdata.proto3.TestAllTypes^x.single_float_wrapper~wrapper(double), + x~google.api.expr.test.v1.proto3.TestAllTypes^x.single_float_wrapper~wrapper(double), 1.0~double )~bool^equals, _==_( - x~dev.cel.testing.testdata.proto3.TestAllTypes^x.single_uint32_wrapper~wrapper(uint), + x~google.api.expr.test.v1.proto3.TestAllTypes^x.single_uint32_wrapper~wrapper(uint), 1u~uint )~bool^equals )~bool^logical_and, _!=_( - x~dev.cel.testing.testdata.proto3.TestAllTypes^x.single_uint64_wrapper~wrapper(uint), + x~google.api.expr.test.v1.proto3.TestAllTypes^x.single_uint64_wrapper~wrapper(uint), 42u~uint )~bool^not_equals )~bool^logical_and diff --git a/checker/src/test/resources/globalEnumValues.baseline b/checker/src/test/resources/globalEnumValues.baseline index 87f242428..b2f7ac7dc 100644 --- a/checker/src/test/resources/globalEnumValues.baseline +++ b/checker/src/test/resources/globalEnumValues.baseline @@ -1,6 +1,6 @@ Source: GlobalEnum.GAZ == 2 =====> _==_( - dev.cel.testing.testdata.proto3.GlobalEnum.GAZ~int^dev.cel.testing.testdata.proto3.GlobalEnum.GAZ, + google.api.expr.test.v1.proto3.GlobalEnum.GAZ~int^google.api.expr.test.v1.proto3.GlobalEnum.GAZ, 2~int )~bool^equals diff --git a/checker/src/test/resources/jsonStructTypeError.baseline b/checker/src/test/resources/jsonStructTypeError.baseline index a345af322..83d6bd717 100644 --- a/checker/src/test/resources/jsonStructTypeError.baseline +++ b/checker/src/test/resources/jsonStructTypeError.baseline @@ -3,6 +3,6 @@ declare x { value google.protobuf.Struct } =====> -ERROR: test_location:1:10: found no matching overload for '_!=_' applied to '(google.protobuf.Value, dev.cel.testing.testdata.proto3.TestAllTypes)' (candidates: (%A3, %A3)) +ERROR: test_location:1:10: found no matching overload for '_!=_' applied to '(google.protobuf.Value, google.api.expr.test.v1.proto3.TestAllTypes)' (candidates: (%A3, %A3)) | x["iss"] != TestAllTypes{single_int32: 1} | .........^ diff --git a/checker/src/test/resources/listElemTypeError.baseline b/checker/src/test/resources/listElemTypeError.baseline index 666025b59..469e5b0e6 100644 --- a/checker/src/test/resources/listElemTypeError.baseline +++ b/checker/src/test/resources/listElemTypeError.baseline @@ -1,11 +1,11 @@ Source: x + y declare x { - value list(dev.cel.testing.testdata.proto3.TestAllTypes) + value list(google.api.expr.test.v1.proto3.TestAllTypes) } declare y { value list(int) } =====> -ERROR: test_location:1:3: found no matching overload for '_+_' applied to '(list(dev.cel.testing.testdata.proto3.TestAllTypes), list(int))' (candidates: (int, int),(uint, uint),(double, double),(string, string),(bytes, bytes),(list(%A0), list(%A0)),(google.protobuf.Timestamp, google.protobuf.Duration),(google.protobuf.Duration, google.protobuf.Timestamp),(google.protobuf.Duration, google.protobuf.Duration)) +ERROR: test_location:1:3: found no matching overload for '_+_' applied to '(list(google.api.expr.test.v1.proto3.TestAllTypes), list(int))' (candidates: (int, int),(uint, uint),(double, double),(string, string),(bytes, bytes),(list(%A0), list(%A0)),(google.protobuf.Timestamp, google.protobuf.Duration),(google.protobuf.Duration, google.protobuf.Timestamp),(google.protobuf.Duration, google.protobuf.Duration)) | x + y | ..^ \ No newline at end of file diff --git a/checker/src/test/resources/listIndexTypeError.baseline b/checker/src/test/resources/listIndexTypeError.baseline index 3bab400ef..898590535 100644 --- a/checker/src/test/resources/listIndexTypeError.baseline +++ b/checker/src/test/resources/listIndexTypeError.baseline @@ -1,8 +1,8 @@ Source: x[1u] declare x { - value list(dev.cel.testing.testdata.proto3.TestAllTypes) + value list(google.api.expr.test.v1.proto3.TestAllTypes) } =====> -ERROR: test_location:1:2: found no matching overload for '_[_]' applied to '(list(dev.cel.testing.testdata.proto3.TestAllTypes), uint)' (candidates: (list(%A0), int),(map(%A1, %B2), %A1)) +ERROR: test_location:1:2: found no matching overload for '_[_]' applied to '(list(google.api.expr.test.v1.proto3.TestAllTypes), uint)' (candidates: (list(%A0), int),(map(%A1, %B2), %A1)) | x[1u] | .^ diff --git a/checker/src/test/resources/listOperators.baseline b/checker/src/test/resources/listOperators.baseline index 7b3a3c154..dba29ba4c 100644 --- a/checker/src/test/resources/listOperators.baseline +++ b/checker/src/test/resources/listOperators.baseline @@ -1,30 +1,30 @@ Source: (x + x)[1].single_int32 == size(x) declare x { - value list(dev.cel.testing.testdata.proto3.TestAllTypes) + value list(google.api.expr.test.v1.proto3.TestAllTypes) } =====> _==_( _[_]( _+_( - x~list(dev.cel.testing.testdata.proto3.TestAllTypes)^x, - x~list(dev.cel.testing.testdata.proto3.TestAllTypes)^x - )~list(dev.cel.testing.testdata.proto3.TestAllTypes)^add_list, + x~list(google.api.expr.test.v1.proto3.TestAllTypes)^x, + x~list(google.api.expr.test.v1.proto3.TestAllTypes)^x + )~list(google.api.expr.test.v1.proto3.TestAllTypes)^add_list, 1~int - )~dev.cel.testing.testdata.proto3.TestAllTypes^index_list.single_int32~int, + )~google.api.expr.test.v1.proto3.TestAllTypes^index_list.single_int32~int, size( - x~list(dev.cel.testing.testdata.proto3.TestAllTypes)^x + x~list(google.api.expr.test.v1.proto3.TestAllTypes)^x )~int^size_list )~bool^equals Source: x.size() == size(x) declare x { - value list(dev.cel.testing.testdata.proto3.TestAllTypes) + value list(google.api.expr.test.v1.proto3.TestAllTypes) } =====> _==_( - x~list(dev.cel.testing.testdata.proto3.TestAllTypes)^x.size()~int^list_size, + x~list(google.api.expr.test.v1.proto3.TestAllTypes)^x.size()~int^list_size, size( - x~list(dev.cel.testing.testdata.proto3.TestAllTypes)^x + x~list(google.api.expr.test.v1.proto3.TestAllTypes)^x )~int^size_list )~bool^equals diff --git a/checker/src/test/resources/listRepeatedOperators.baseline b/checker/src/test/resources/listRepeatedOperators.baseline index 6f5fa76c8..4fd1fe5d5 100644 --- a/checker/src/test/resources/listRepeatedOperators.baseline +++ b/checker/src/test/resources/listRepeatedOperators.baseline @@ -1,12 +1,12 @@ Source: x.repeated_int64[x.single_int32] == 23 declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> _==_( _[_]( - x~dev.cel.testing.testdata.proto3.TestAllTypes^x.repeated_int64~list(int), - x~dev.cel.testing.testdata.proto3.TestAllTypes^x.single_int32~int + x~google.api.expr.test.v1.proto3.TestAllTypes^x.repeated_int64~list(int), + x~google.api.expr.test.v1.proto3.TestAllTypes^x.single_int32~int )~int^index_list, 23~int )~bool^equals diff --git a/checker/src/test/resources/mapEmpty.baseline b/checker/src/test/resources/mapEmpty.baseline index db6d5b65b..a7dc95415 100644 --- a/checker/src/test/resources/mapEmpty.baseline +++ b/checker/src/test/resources/mapEmpty.baseline @@ -1,11 +1,11 @@ Source: size(x.map_int64_nested_type) == 0 declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> _==_( size( - x~dev.cel.testing.testdata.proto3.TestAllTypes^x.map_int64_nested_type~map(int, dev.cel.testing.testdata.proto3.NestedTestAllTypes) + x~google.api.expr.test.v1.proto3.TestAllTypes^x.map_int64_nested_type~map(int, google.api.expr.test.v1.proto3.NestedTestAllTypes) )~int^size_map, 0~int )~bool^equals diff --git a/checker/src/test/resources/mapExpr.baseline b/checker/src/test/resources/mapExpr.baseline index eb3739e61..4fabfed85 100644 --- a/checker/src/test/resources/mapExpr.baseline +++ b/checker/src/test/resources/mapExpr.baseline @@ -1,13 +1,13 @@ Source: x.repeated_int64.map(x, double(x)) declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> __comprehension__( // Variable x, // Target - x~dev.cel.testing.testdata.proto3.TestAllTypes^x.repeated_int64~list(int), + x~google.api.expr.test.v1.proto3.TestAllTypes^x.repeated_int64~list(int), // Accumulator __result__, // Init @@ -28,7 +28,7 @@ __comprehension__( Source: [].map(x, [].map(y, x in y && y in x)) declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> ERROR: test_location:1:33: found no matching overload for '@in' applied to '(list(%elem0), %elem0)' (candidates: (%A7, list(%A7)),(%A8, map(%A8, %B9))) @@ -37,7 +37,7 @@ ERROR: test_location:1:33: found no matching overload for '@in' applied to '(lis Source: [{}.map(c,c,c)]+[{}.map(c,c,c)] declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> _+_( diff --git a/checker/src/test/resources/mapFilterExpr.baseline b/checker/src/test/resources/mapFilterExpr.baseline index b7b56ee88..7e7c0175a 100644 --- a/checker/src/test/resources/mapFilterExpr.baseline +++ b/checker/src/test/resources/mapFilterExpr.baseline @@ -1,13 +1,13 @@ Source: x.repeated_int64.map(x, x > 0, double(x)) declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> __comprehension__( // Variable x, // Target - x~dev.cel.testing.testdata.proto3.TestAllTypes^x.repeated_int64~list(int), + x~google.api.expr.test.v1.proto3.TestAllTypes^x.repeated_int64~list(int), // Accumulator __result__, // Init @@ -35,7 +35,7 @@ __comprehension__( Source: lists.filter(x, x > 1.5) declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare lists { value dyn @@ -71,7 +71,7 @@ __comprehension__( Source: args.user["myextension"].customAttributes.filter(x, x.name == "hobbies") declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare lists { value dyn diff --git a/checker/src/test/resources/mapIndexTypeError.baseline b/checker/src/test/resources/mapIndexTypeError.baseline index b681e067d..ad31488db 100644 --- a/checker/src/test/resources/mapIndexTypeError.baseline +++ b/checker/src/test/resources/mapIndexTypeError.baseline @@ -1,8 +1,8 @@ Source: x[2].single_int32 == 23 declare x { - value map(string, dev.cel.testing.testdata.proto3.TestAllTypes) + value map(string, google.api.expr.test.v1.proto3.TestAllTypes) } =====> -ERROR: test_location:1:2: found no matching overload for '_[_]' applied to '(map(string, dev.cel.testing.testdata.proto3.TestAllTypes), int)' (candidates: (list(%A0), int),(map(%A1, %B2), %A1)) +ERROR: test_location:1:2: found no matching overload for '_[_]' applied to '(map(string, google.api.expr.test.v1.proto3.TestAllTypes), int)' (candidates: (list(%A0), int),(map(%A1, %B2), %A1)) | x[2].single_int32 == 23 | .^ diff --git a/checker/src/test/resources/mapOperators.baseline b/checker/src/test/resources/mapOperators.baseline index 703b78898..454d7f024 100644 --- a/checker/src/test/resources/mapOperators.baseline +++ b/checker/src/test/resources/mapOperators.baseline @@ -1,25 +1,25 @@ Source: x["a"].single_int32 == 23 declare x { - value map(string, dev.cel.testing.testdata.proto3.TestAllTypes) + value map(string, google.api.expr.test.v1.proto3.TestAllTypes) } =====> _==_( _[_]( - x~map(string, dev.cel.testing.testdata.proto3.TestAllTypes)^x, + x~map(string, google.api.expr.test.v1.proto3.TestAllTypes)^x, "a"~string - )~dev.cel.testing.testdata.proto3.TestAllTypes^index_map.single_int32~int, + )~google.api.expr.test.v1.proto3.TestAllTypes^index_map.single_int32~int, 23~int )~bool^equals Source: x.size() == size(x) declare x { - value map(string, dev.cel.testing.testdata.proto3.TestAllTypes) + value map(string, google.api.expr.test.v1.proto3.TestAllTypes) } =====> _==_( - x~map(string, dev.cel.testing.testdata.proto3.TestAllTypes)^x.size()~int^map_size, + x~map(string, google.api.expr.test.v1.proto3.TestAllTypes)^x.size()~int^map_size, size( - x~map(string, dev.cel.testing.testdata.proto3.TestAllTypes)^x + x~map(string, google.api.expr.test.v1.proto3.TestAllTypes)^x )~int^size_map )~bool^equals diff --git a/checker/src/test/resources/messageFieldSelect.baseline b/checker/src/test/resources/messageFieldSelect.baseline index dd4cf8723..8a219faaf 100644 --- a/checker/src/test/resources/messageFieldSelect.baseline +++ b/checker/src/test/resources/messageFieldSelect.baseline @@ -1,22 +1,22 @@ Source: x.single_nested_message.bb == 43 && has(x.single_nested_message) && has(x.single_int32) && has(x.repeated_int32) && has(x.map_int64_nested_type) declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> _&&_( _&&_( _&&_( _==_( - x~dev.cel.testing.testdata.proto3.TestAllTypes^x.single_nested_message~dev.cel.testing.testdata.proto3.TestAllTypes.NestedMessage.bb~int, + x~google.api.expr.test.v1.proto3.TestAllTypes^x.single_nested_message~google.api.expr.test.v1.proto3.TestAllTypes.NestedMessage.bb~int, 43~int )~bool^equals, - x~dev.cel.testing.testdata.proto3.TestAllTypes^x.single_nested_message~test-only~~bool + x~google.api.expr.test.v1.proto3.TestAllTypes^x.single_nested_message~test-only~~bool )~bool^logical_and, - x~dev.cel.testing.testdata.proto3.TestAllTypes^x.single_int32~test-only~~bool + x~google.api.expr.test.v1.proto3.TestAllTypes^x.single_int32~test-only~~bool )~bool^logical_and, _&&_( - x~dev.cel.testing.testdata.proto3.TestAllTypes^x.repeated_int32~test-only~~bool, - x~dev.cel.testing.testdata.proto3.TestAllTypes^x.map_int64_nested_type~test-only~~bool + x~google.api.expr.test.v1.proto3.TestAllTypes^x.repeated_int32~test-only~~bool, + x~google.api.expr.test.v1.proto3.TestAllTypes^x.map_int64_nested_type~test-only~~bool )~bool^logical_and )~bool^logical_and diff --git a/checker/src/test/resources/messageFieldSelectError.baseline b/checker/src/test/resources/messageFieldSelectError.baseline index 3bb8538ad..8c1808f1d 100644 --- a/checker/src/test/resources/messageFieldSelectError.baseline +++ b/checker/src/test/resources/messageFieldSelectError.baseline @@ -1,6 +1,6 @@ Source: x.single_nested_message.undefined == x.undefined declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> ERROR: test_location:1:24: undefined field 'undefined' diff --git a/checker/src/test/resources/namespacedVariables.baseline b/checker/src/test/resources/namespacedVariables.baseline index 9e0ccfe85..ecb3cfc30 100644 --- a/checker/src/test/resources/namespacedVariables.baseline +++ b/checker/src/test/resources/namespacedVariables.baseline @@ -9,8 +9,8 @@ Source: msgVar.single_int32 declare ns.x { value int } -declare dev.cel.testing.testdata.proto3.msgVar { - value dev.cel.testing.testdata.proto3.TestAllTypes +declare google.api.expr.test.v1.proto3.msgVar { + value google.api.expr.test.v1.proto3.TestAllTypes } =====> -dev.cel.testing.testdata.proto3.msgVar~dev.cel.testing.testdata.proto3.TestAllTypes^dev.cel.testing.testdata.proto3.msgVar.single_int32~int +google.api.expr.test.v1.proto3.msgVar~google.api.expr.test.v1.proto3.TestAllTypes^google.api.expr.test.v1.proto3.msgVar.single_int32~int diff --git a/checker/src/test/resources/nestedEnums.baseline b/checker/src/test/resources/nestedEnums.baseline index 3a2869a75..98b5477c7 100644 --- a/checker/src/test/resources/nestedEnums.baseline +++ b/checker/src/test/resources/nestedEnums.baseline @@ -1,16 +1,16 @@ Source: x.single_nested_enum == TestAllTypes.NestedEnum.BAR declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> _==_( - x~dev.cel.testing.testdata.proto3.TestAllTypes^x.single_nested_enum~int, - dev.cel.testing.testdata.proto3.TestAllTypes.NestedEnum.BAR~int^dev.cel.testing.testdata.proto3.TestAllTypes.NestedEnum.BAR + x~google.api.expr.test.v1.proto3.TestAllTypes^x.single_nested_enum~int, + google.api.expr.test.v1.proto3.TestAllTypes.NestedEnum.BAR~int^google.api.expr.test.v1.proto3.TestAllTypes.NestedEnum.BAR )~bool^equals Source: single_nested_enum == TestAllTypes.NestedEnum.BAR declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare single_nested_enum { value int @@ -18,12 +18,12 @@ declare single_nested_enum { =====> _==_( single_nested_enum~int^single_nested_enum, - dev.cel.testing.testdata.proto3.TestAllTypes.NestedEnum.BAR~int^dev.cel.testing.testdata.proto3.TestAllTypes.NestedEnum.BAR + google.api.expr.test.v1.proto3.TestAllTypes.NestedEnum.BAR~int^google.api.expr.test.v1.proto3.TestAllTypes.NestedEnum.BAR )~bool^equals Source: TestAllTypes{single_nested_enum : TestAllTypes.NestedEnum.BAR}.single_nested_enum == 1 declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare single_nested_enum { value int @@ -31,7 +31,7 @@ declare single_nested_enum { =====> _==_( TestAllTypes{ - single_nested_enum:dev.cel.testing.testdata.proto3.TestAllTypes.NestedEnum.BAR~int^dev.cel.testing.testdata.proto3.TestAllTypes.NestedEnum.BAR - }~dev.cel.testing.testdata.proto3.TestAllTypes^dev.cel.testing.testdata.proto3.TestAllTypes.single_nested_enum~int, + single_nested_enum:google.api.expr.test.v1.proto3.TestAllTypes.NestedEnum.BAR~int^google.api.expr.test.v1.proto3.TestAllTypes.NestedEnum.BAR + }~google.api.expr.test.v1.proto3.TestAllTypes^google.api.expr.test.v1.proto3.TestAllTypes.single_nested_enum~int, 1~int )~bool^equals diff --git a/checker/src/test/resources/nullableMessage.baseline b/checker/src/test/resources/nullableMessage.baseline index e2db74762..d6920cede 100644 --- a/checker/src/test/resources/nullableMessage.baseline +++ b/checker/src/test/resources/nullableMessage.baseline @@ -1,25 +1,25 @@ Source: x.single_nested_message != null declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> _!=_( - x~dev.cel.testing.testdata.proto3.TestAllTypes^x.single_nested_message~dev.cel.testing.testdata.proto3.TestAllTypes.NestedMessage, + x~google.api.expr.test.v1.proto3.TestAllTypes^x.single_nested_message~google.api.expr.test.v1.proto3.TestAllTypes.NestedMessage, null~null )~bool^not_equals Source: null == TestAllTypes{} || TestAllTypes{} == null declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> _||_( _==_( null~null, - TestAllTypes{}~dev.cel.testing.testdata.proto3.TestAllTypes^dev.cel.testing.testdata.proto3.TestAllTypes + TestAllTypes{}~google.api.expr.test.v1.proto3.TestAllTypes^google.api.expr.test.v1.proto3.TestAllTypes )~bool^equals, _==_( - TestAllTypes{}~dev.cel.testing.testdata.proto3.TestAllTypes^dev.cel.testing.testdata.proto3.TestAllTypes, + TestAllTypes{}~google.api.expr.test.v1.proto3.TestAllTypes^google.api.expr.test.v1.proto3.TestAllTypes, null~null )~bool^equals )~bool^logical_or diff --git a/checker/src/test/resources/nullablePrimitiveError.baseline b/checker/src/test/resources/nullablePrimitiveError.baseline index 43a50447f..b6e4a7dc7 100644 --- a/checker/src/test/resources/nullablePrimitiveError.baseline +++ b/checker/src/test/resources/nullablePrimitiveError.baseline @@ -1,6 +1,6 @@ Source: x.single_int64 != null declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> ERROR: test_location:1:16: found no matching overload for '_!=_' applied to '(int, null)' (candidates: (%A0, %A0)) diff --git a/checker/src/test/resources/nullableWrapper.baseline b/checker/src/test/resources/nullableWrapper.baseline index 4e6deb477..f2e0165b0 100644 --- a/checker/src/test/resources/nullableWrapper.baseline +++ b/checker/src/test/resources/nullableWrapper.baseline @@ -1,10 +1,10 @@ Source: x.single_int64_wrapper == null declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> _==_( - x~dev.cel.testing.testdata.proto3.TestAllTypes^x.single_int64_wrapper~wrapper(int), + x~google.api.expr.test.v1.proto3.TestAllTypes^x.single_int64_wrapper~wrapper(int), null~null )~bool^equals diff --git a/checker/src/test/resources/operatorsConditional.baseline b/checker/src/test/resources/operatorsConditional.baseline index 96c64bbf6..72123b2ee 100644 --- a/checker/src/test/resources/operatorsConditional.baseline +++ b/checker/src/test/resources/operatorsConditional.baseline @@ -1,10 +1,10 @@ Source: false ? x.single_timestamp : null declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> _?_:_( false~bool, - x~dev.cel.testing.testdata.proto3.TestAllTypes^x.single_timestamp~google.protobuf.Timestamp, + x~google.api.expr.test.v1.proto3.TestAllTypes^x.single_timestamp~google.protobuf.Timestamp, null~null )~google.protobuf.Timestamp^conditional diff --git a/checker/src/test/resources/optionals.baseline b/checker/src/test/resources/optionals.baseline index cc534f514..c78f5cc5a 100644 --- a/checker/src/test/resources/optionals.baseline +++ b/checker/src/test/resources/optionals.baseline @@ -77,7 +77,7 @@ TestAllTypes{ {}~map(dyn, int), "i" )~optional_type(int)^select_optional_field -}~dev.cel.testing.testdata.proto3.TestAllTypes^dev.cel.testing.testdata.proto3.TestAllTypes +}~google.api.expr.test.v1.proto3.TestAllTypes^google.api.expr.test.v1.proto3.TestAllTypes Source: [?a, ?b, 'world'] declare a { diff --git a/checker/src/test/resources/proto2PrimitiveField.baseline b/checker/src/test/resources/proto2PrimitiveField.baseline index 1842b1c5e..6d5351988 100644 --- a/checker/src/test/resources/proto2PrimitiveField.baseline +++ b/checker/src/test/resources/proto2PrimitiveField.baseline @@ -1,18 +1,18 @@ Source: x.single_fixed32 != 0u && x.single_fixed64 > 1u && x.single_int32 != null declare x { - value dev.cel.testing.testdata.proto2.Proto2Message + value google.api.expr.test.v1.proto2.TestAllTypes } =====> ERROR: test_location:1:67: found no matching overload for '_!=_' applied to '(int, null)' (candidates: (%A1, %A1)) - | x.single_fixed32 != 0u && x.single_fixed64 > 1u && x.single_int32 != null - | ..................................................................^ + | x.single_fixed32 != 0u && x.single_fixed64 > 1u && x.single_int32 != null + | ..................................................................^ Source: x.nestedgroup.single_name == '' declare x { - value dev.cel.testing.testdata.proto2.Proto2Message + value google.api.expr.test.v1.proto2.TestAllTypes } =====> _==_( - x~dev.cel.testing.testdata.proto2.Proto2Message^x.nestedgroup~dev.cel.testing.testdata.proto2.Proto2Message.NestedGroup.single_name~string, + x~google.api.expr.test.v1.proto2.TestAllTypes^x.nestedgroup~google.api.expr.test.v1.proto2.TestAllTypes.NestedGroup.single_name~string, ""~string )~bool^equals diff --git a/checker/src/test/resources/quantifiers.baseline b/checker/src/test/resources/quantifiers.baseline index 3f4d99bb5..b2d651c8c 100644 --- a/checker/src/test/resources/quantifiers.baseline +++ b/checker/src/test/resources/quantifiers.baseline @@ -1,6 +1,6 @@ Source: x.repeated_int64.all(e, e > 0) && x.repeated_int64.exists(e, e < 0) && x.repeated_int64.exists_one(e, e == 0) declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> _&&_( @@ -9,7 +9,7 @@ _&&_( // Variable e, // Target - x~dev.cel.testing.testdata.proto3.TestAllTypes^x.repeated_int64~list(int), + x~google.api.expr.test.v1.proto3.TestAllTypes^x.repeated_int64~list(int), // Accumulator __result__, // Init @@ -32,7 +32,7 @@ _&&_( // Variable e, // Target - x~dev.cel.testing.testdata.proto3.TestAllTypes^x.repeated_int64~list(int), + x~google.api.expr.test.v1.proto3.TestAllTypes^x.repeated_int64~list(int), // Accumulator __result__, // Init @@ -58,7 +58,7 @@ _&&_( // Variable e, // Target - x~dev.cel.testing.testdata.proto3.TestAllTypes^x.repeated_int64~list(int), + x~google.api.expr.test.v1.proto3.TestAllTypes^x.repeated_int64~list(int), // Accumulator __result__, // Init diff --git a/checker/src/test/resources/quantifiersErrors.baseline b/checker/src/test/resources/quantifiersErrors.baseline index 052d9a38c..2f6d1eac6 100644 --- a/checker/src/test/resources/quantifiersErrors.baseline +++ b/checker/src/test/resources/quantifiersErrors.baseline @@ -1,9 +1,9 @@ Source: x.all(e, 0) declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> -ERROR: test_location:1:1: expression of type 'dev.cel.testing.testdata.proto3.TestAllTypes' cannot be range of a comprehension (must be list, map, or dynamic) +ERROR: test_location:1:1: expression of type 'google.api.expr.test.v1.proto3.TestAllTypes' cannot be range of a comprehension (must be list, map, or dynamic) | x.all(e, 0) | ^ ERROR: test_location:1:6: found no matching overload for '_&&_' applied to '(bool, int)' (candidates: (bool, bool)) diff --git a/checker/src/test/resources/referenceTypeAbsolute.baseline b/checker/src/test/resources/referenceTypeAbsolute.baseline index 12057f1ce..7bd4487e5 100644 --- a/checker/src/test/resources/referenceTypeAbsolute.baseline +++ b/checker/src/test/resources/referenceTypeAbsolute.baseline @@ -1,3 +1,3 @@ -Source: .dev.cel.testing.testdata.proto3.TestAllTypes +Source: .google.api.expr.test.v1.proto3.TestAllTypes =====> -dev.cel.testing.testdata.proto3.TestAllTypes~type(dev.cel.testing.testdata.proto3.TestAllTypes)^dev.cel.testing.testdata.proto3.TestAllTypes +google.api.expr.test.v1.proto3.TestAllTypes~type(google.api.expr.test.v1.proto3.TestAllTypes)^google.api.expr.test.v1.proto3.TestAllTypes diff --git a/checker/src/test/resources/referenceTypeRelative.baseline b/checker/src/test/resources/referenceTypeRelative.baseline index 80e386607..abe4260d5 100644 --- a/checker/src/test/resources/referenceTypeRelative.baseline +++ b/checker/src/test/resources/referenceTypeRelative.baseline @@ -1,3 +1,3 @@ Source: proto3.TestAllTypes =====> -dev.cel.testing.testdata.proto3.TestAllTypes~type(dev.cel.testing.testdata.proto3.TestAllTypes)^dev.cel.testing.testdata.proto3.TestAllTypes +google.api.expr.test.v1.proto3.TestAllTypes~type(google.api.expr.test.v1.proto3.TestAllTypes)^google.api.expr.test.v1.proto3.TestAllTypes diff --git a/checker/src/test/resources/referenceValue.baseline b/checker/src/test/resources/referenceValue.baseline index b6ed9f23b..a6ded5464 100644 --- a/checker/src/test/resources/referenceValue.baseline +++ b/checker/src/test/resources/referenceValue.baseline @@ -1,6 +1,6 @@ Source: x declare container.x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> -container.x~dev.cel.testing.testdata.proto3.TestAllTypes^container.x +container.x~google.api.expr.test.v1.proto3.TestAllTypes^container.x diff --git a/checker/src/test/resources/userFunctionAddsOverload.baseline b/checker/src/test/resources/userFunctionAddsOverload.baseline index 775194ce7..3a8cb44ad 100644 --- a/checker/src/test/resources/userFunctionAddsOverload.baseline +++ b/checker/src/test/resources/userFunctionAddsOverload.baseline @@ -1,14 +1,14 @@ Source: size(x) > 4 declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare size { - function size_message (dev.cel.testing.testdata.proto3.TestAllTypes) -> int + function size_message (google.api.expr.test.v1.proto3.TestAllTypes) -> int } =====> _>_( size( - x~dev.cel.testing.testdata.proto3.TestAllTypes^x + x~google.api.expr.test.v1.proto3.TestAllTypes^x )~int^size_message, 4~int )~bool^greater_int64 diff --git a/checker/src/test/resources/wrapper.baseline b/checker/src/test/resources/wrapper.baseline index f5370bcd7..2180c4a5f 100644 --- a/checker/src/test/resources/wrapper.baseline +++ b/checker/src/test/resources/wrapper.baseline @@ -1,11 +1,11 @@ Source: x.single_int64_wrapper + 1 != 23 declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> _!=_( _+_( - x~dev.cel.testing.testdata.proto3.TestAllTypes^x.single_int64_wrapper~wrapper(int), + x~google.api.expr.test.v1.proto3.TestAllTypes^x.single_int64_wrapper~wrapper(int), 1~int )~int^add_int64, 23~int diff --git a/common/resources/testdata/proto2/BUILD.bazel b/common/resources/testdata/proto2/BUILD.bazel deleted file mode 100644 index a4afac550..000000000 --- a/common/resources/testdata/proto2/BUILD.bazel +++ /dev/null @@ -1,20 +0,0 @@ -package( - default_applicable_licenses = ["//:license"], - default_testonly = True, - default_visibility = ["//visibility:public"], -) - -alias( - name = "test_all_types_java_proto", - actual = "//common/src/main/resources/testdata/proto2:test_all_types_java_proto", -) - -alias( - name = "messages_proto2_java_proto", - actual = "//common/src/main/resources/testdata/proto2:messages_proto2_java_proto", -) - -alias( - name = "messages_extensions_proto2_java_proto", - actual = "//common/src/main/resources/testdata/proto2:messages_extensions_proto2_java_proto", -) diff --git a/common/resources/testdata/proto3/BUILD.bazel b/common/resources/testdata/proto3/BUILD.bazel index 38b92096c..77d5160ac 100644 --- a/common/resources/testdata/proto3/BUILD.bazel +++ b/common/resources/testdata/proto3/BUILD.bazel @@ -9,11 +9,6 @@ alias( actual = "//common/src/main/resources/testdata/proto3:test_all_types_file_descriptor_set", ) -alias( - name = "test_all_types_java_proto", - actual = "//common/src/main/resources/testdata/proto3:test_all_types_java_proto", -) - alias( name = "standalone_global_enum_java_proto", actual = "//common/src/main/resources/testdata/proto3:standalone_global_enum_java_proto", diff --git a/common/src/main/resources/testdata/proto2/BUILD.bazel b/common/src/main/resources/testdata/proto2/BUILD.bazel deleted file mode 100644 index 6d374ad01..000000000 --- a/common/src/main/resources/testdata/proto2/BUILD.bazel +++ /dev/null @@ -1,59 +0,0 @@ -package( - default_applicable_licenses = [ - "//:license", - ], - default_testonly = True, - default_visibility = [ - "//common/resources/testdata/proto2:__pkg__", - ], -) - -proto_library( - name = "messages_proto2_proto", - srcs = [ - "messages_proto2.proto", - ], - deps = [ - ":test_all_types_proto", - ], -) - -java_proto_library( - name = "messages_proto2_java_proto", - deps = [":messages_proto2_proto"], -) - -proto_library( - name = "messages_extensions_proto2_proto", - srcs = [ - "messages_extensions_proto2.proto", - ], - deps = [ - ":messages_proto2_proto", - ":test_all_types_proto", - ], -) - -java_proto_library( - name = "messages_extensions_proto2_java_proto", - deps = [":messages_extensions_proto2_proto"], -) - -proto_library( - name = "test_all_types_proto", - srcs = [ - "test_all_types.proto", - ], - deps = [ - "@com_google_protobuf//:any_proto", - "@com_google_protobuf//:duration_proto", - "@com_google_protobuf//:struct_proto", - "@com_google_protobuf//:timestamp_proto", - "@com_google_protobuf//:wrappers_proto", - ], -) - -java_proto_library( - name = "test_all_types_java_proto", - deps = [":test_all_types_proto"], -) diff --git a/common/src/main/resources/testdata/proto2/messages_extensions_proto2.proto b/common/src/main/resources/testdata/proto2/messages_extensions_proto2.proto deleted file mode 100644 index d1c6ee06d..000000000 --- a/common/src/main/resources/testdata/proto2/messages_extensions_proto2.proto +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2022 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. - -syntax = "proto2"; - -import "common/src/main/resources/testdata/proto2/messages_proto2.proto"; -import "common/src/main/resources/testdata/proto2/test_all_types.proto"; - -package dev.cel.testing.testdata.proto2; - -option java_outer_classname = "MessagesProto2Extensions"; -option java_package = "dev.cel.testing.testdata.proto2"; -option java_multiple_files = true; - -// Package scoped extensions -extend Proto2Message { - optional Proto2Message nested_ext = 100; - optional int32 int32_ext = 101; - optional dev.cel.testing.testdata.proto2.TestAllTypes test_all_types_ext = - 102; - optional dev.cel.testing.testdata.proto2.TestAllTypes.NestedEnum - nested_enum_ext = 103; - repeated StringHolder repeated_string_holder_ext = 104; -} - -// Message scoped extensions -message Proto2ExtensionScopedMessage { - extend Proto2Message { - optional Proto2Message message_scoped_nested_ext = 105; - optional NestedMessageInsideExtensions nested_message_inside_ext = 106; - optional int64 int64_ext = 107; - optional string string_ext = 108; - } -} - -message NestedMessageInsideExtensions { - optional string field = 1; -} diff --git a/common/src/main/resources/testdata/proto2/messages_proto2.proto b/common/src/main/resources/testdata/proto2/messages_proto2.proto deleted file mode 100644 index 6f8f082e6..000000000 --- a/common/src/main/resources/testdata/proto2/messages_proto2.proto +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2022 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. - -// LINT: ALLOW_GROUPS -syntax = "proto2"; - -package dev.cel.testing.testdata.proto2; - -import "common/src/main/resources/testdata/proto2/test_all_types.proto"; - -option java_outer_classname = "MessagesProto2"; -option java_package = "dev.cel.testing.testdata.proto2"; -option java_multiple_files = true; - -message Proto2Message { - optional int32 single_int32 = 1; - optional fixed32 single_fixed32 = 2; - optional fixed64 single_fixed64 = 3; - optional dev.cel.testing.testdata.proto2.GlobalEnum single_enum = 4; - optional dev.cel.testing.testdata.proto2.NestedTestAllTypes - single_nested_test_all_types = 5; - - optional group NestedGroup = 6 { - optional int32 single_id = 7; - optional string single_name = 8; - } - - extensions 100 to max; -} - -message StringHolder { - optional string s = 1; -} diff --git a/common/src/main/resources/testdata/proto2/test_all_types.proto b/common/src/main/resources/testdata/proto2/test_all_types.proto deleted file mode 100644 index 7307b2970..000000000 --- a/common/src/main/resources/testdata/proto2/test_all_types.proto +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright 2022 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. - -// Keep this file synced with: -// https://github.com/google/cel-spec/blob/master/proto/test/v1/proto2/test_all_types.proto - -syntax = "proto2"; - -package dev.cel.testing.testdata.proto2; - -import "google/protobuf/any.proto"; -import "google/protobuf/duration.proto"; -import "google/protobuf/struct.proto"; -import "google/protobuf/timestamp.proto"; -import "google/protobuf/wrappers.proto"; - -option java_outer_classname = "TestAllTypesProto"; -option java_package = "dev.cel.testing.testdata.proto2"; - -// This proto includes every type of field in both singular and repeated -// forms. -message TestAllTypes { - message NestedMessage { - // The field name "b" fails to compile in proto1 because it conflicts with - // a local variable named "b" in one of the generated methods. - // This file needs to compile in proto1 to test backwards-compatibility. - optional int32 bb = 1; - } - - enum NestedEnum { - FOO = 0; - BAR = 1; - BAZ = 2; - } - - // Singular - optional int32 single_int32 = 1 [default = -32]; - optional int64 single_int64 = 2 [default = -64]; - optional uint32 single_uint32 = 3 [default = 32]; - optional uint64 single_uint64 = 4 [default = 64]; - optional sint32 single_sint32 = 5; - optional sint64 single_sint64 = 6; - optional fixed32 single_fixed32 = 7; - optional fixed64 single_fixed64 = 8; - optional sfixed32 single_sfixed32 = 9; - optional sfixed64 single_sfixed64 = 10; - optional float single_float = 11 [default = 3.0]; - optional double single_double = 12 [default = 6.4]; - optional bool single_bool = 13 [default = true]; - optional string single_string = 14 [default = "empty"]; - optional bytes single_bytes = 15 [default = "none"]; - - // Wellknown. - optional google.protobuf.Any single_any = 100; - optional google.protobuf.Duration single_duration = 101; - optional google.protobuf.Timestamp single_timestamp = 102; - optional google.protobuf.Struct single_struct = 103; - optional google.protobuf.Value single_value = 104; - optional google.protobuf.Int64Value single_int64_wrapper = 105; - optional google.protobuf.Int32Value single_int32_wrapper = 106; - optional google.protobuf.DoubleValue single_double_wrapper = 107; - optional google.protobuf.FloatValue single_float_wrapper = 108; - optional google.protobuf.UInt64Value single_uint64_wrapper = 109; - optional google.protobuf.UInt32Value single_uint32_wrapper = 110; - optional google.protobuf.StringValue single_string_wrapper = 111; - optional google.protobuf.BoolValue single_bool_wrapper = 112; - optional google.protobuf.BytesValue single_bytes_wrapper = 113; - optional google.protobuf.ListValue list_value = 114; - - // Nested messages - oneof nested_type { - NestedMessage single_nested_message = 21; - NestedEnum single_nested_enum = 22 [default = BAR]; - } - optional NestedMessage standalone_message = 23; - optional NestedEnum standalone_enum = 24; - - // Repeated - repeated int32 repeated_int32 = 31; - repeated int64 repeated_int64 = 32; - repeated uint32 repeated_uint32 = 33; - repeated uint64 repeated_uint64 = 34; - repeated sint32 repeated_sint32 = 35; - repeated sint64 repeated_sint64 = 36; - repeated fixed32 repeated_fixed32 = 37; - repeated fixed64 repeated_fixed64 = 38; - repeated sfixed32 repeated_sfixed32 = 39; - repeated sfixed64 repeated_sfixed64 = 40; - repeated float repeated_float = 41; - repeated double repeated_double = 42; - repeated bool repeated_bool = 43; - repeated string repeated_string = 44; - repeated bytes repeated_bytes = 45; - - // Repeated and nested - repeated NestedMessage repeated_nested_message = 51; - repeated NestedEnum repeated_nested_enum = 52; - repeated string repeated_string_piece = 53 [ctype = STRING_PIECE]; - repeated string repeated_cord = 54 [ctype = CORD]; - repeated NestedMessage repeated_lazy_message = 55; - - // Map - map map_string_string = 61; - map map_int64_nested_type = 62; -} - -// This proto includes a recursively nested message. -message NestedTestAllTypes { - optional NestedTestAllTypes child = 1; - optional TestAllTypes payload = 2; -} - -// This proto has a required field. -message TestRequired { - required int32 required_int32 = 1; -} - -// This proto tests that global enums are resolved correctly. -enum GlobalEnum { - GOO = 0; - GAR = 1; - GAZ = 2; -} diff --git a/common/src/main/resources/testdata/proto3/BUILD.bazel b/common/src/main/resources/testdata/proto3/BUILD.bazel index 2230ee37a..865c21d84 100644 --- a/common/src/main/resources/testdata/proto3/BUILD.bazel +++ b/common/src/main/resources/testdata/proto3/BUILD.bazel @@ -13,27 +13,6 @@ filegroup( srcs = ["test_all_types.fds"], ) -proto_library( - name = "test_all_types_proto", - srcs = [ - "test_all_types.proto", - ], - deps = [ - "@com_google_protobuf//:any_proto", - "@com_google_protobuf//:duration_proto", - "@com_google_protobuf//:struct_proto", - "@com_google_protobuf//:timestamp_proto", - "@com_google_protobuf//:wrappers_proto", - ], -) - -java_proto_library( - name = "test_all_types_java_proto", - tags = [ - ], - deps = [":test_all_types_proto"], -) - proto_library( name = "standalone_global_enum_proto", srcs = ["standalone_global_enum.proto"], diff --git a/common/src/main/resources/testdata/proto3/test_all_types.proto b/common/src/main/resources/testdata/proto3/test_all_types.proto deleted file mode 100644 index 2ed2d9900..000000000 --- a/common/src/main/resources/testdata/proto3/test_all_types.proto +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright 2022 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. - -// Keep this file synced with: -// https://raw.githubusercontent.com/google/cel-spec/master/proto/test/v1/proto3/test_all_types.proto - -syntax = "proto3"; - -package dev.cel.testing.testdata.proto3; - -import "google/protobuf/any.proto"; -import "google/protobuf/duration.proto"; -import "google/protobuf/struct.proto"; -import "google/protobuf/timestamp.proto"; -import "google/protobuf/wrappers.proto"; - -option java_outer_classname = "TestAllTypesProto"; -option java_package = "dev.cel.testing.testdata.proto3"; - -// This proto includes every type of field in both singular and repeated -// forms. -message TestAllTypes { - message NestedMessage { - // The field name "b" fails to compile in proto1 because it conflicts with - // a local variable named "b" in one of the generated methods. - // This file needs to compile in proto1 to test backwards-compatibility. - int32 bb = 1; - } - - enum NestedEnum { - FOO = 0; - BAR = 1; - BAZ = 2; - } - - // Singular - int32 single_int32 = 1; - int64 single_int64 = 2; - uint32 single_uint32 = 3; - uint64 single_uint64 = 4; - sint32 single_sint32 = 5; - sint64 single_sint64 = 6; - fixed32 single_fixed32 = 7; - fixed64 single_fixed64 = 8; - sfixed32 single_sfixed32 = 9; - sfixed64 single_sfixed64 = 10; - float single_float = 11; - double single_double = 12; - bool single_bool = 13; - string single_string = 14; - bytes single_bytes = 15; - optional bool optional_bool = 16; - optional bool optional_string = 17; - - // Wellknown. - google.protobuf.Any single_any = 100; - google.protobuf.Duration single_duration = 101; - google.protobuf.Timestamp single_timestamp = 102; - google.protobuf.Struct single_struct = 103; - google.protobuf.Value single_value = 104; - google.protobuf.Int64Value single_int64_wrapper = 105; - google.protobuf.Int32Value single_int32_wrapper = 106; - google.protobuf.DoubleValue single_double_wrapper = 107; - google.protobuf.FloatValue single_float_wrapper = 108; - google.protobuf.UInt64Value single_uint64_wrapper = 109; - google.protobuf.UInt32Value single_uint32_wrapper = 110; - google.protobuf.StringValue single_string_wrapper = 111; - google.protobuf.BoolValue single_bool_wrapper = 112; - google.protobuf.BytesValue single_bytes_wrapper = 113; - google.protobuf.ListValue single_list_value = 114; - - // Nested messages - oneof nested_type { - NestedMessage single_nested_message = 21; - NestedEnum single_nested_enum = 22; - } - NestedMessage standalone_message = 23; - NestedEnum standalone_enum = 24; - - // Repeated - repeated int32 repeated_int32 = 31; - repeated int64 repeated_int64 = 32; - repeated uint32 repeated_uint32 = 33; - repeated uint64 repeated_uint64 = 34; - repeated sint32 repeated_sint32 = 35; - repeated sint64 repeated_sint64 = 36; - repeated fixed32 repeated_fixed32 = 37; - repeated fixed64 repeated_fixed64 = 38; - repeated sfixed32 repeated_sfixed32 = 39; - repeated sfixed64 repeated_sfixed64 = 40; - repeated float repeated_float = 41; - repeated double repeated_double = 42; - repeated bool repeated_bool = 43; - repeated string repeated_string = 44; - repeated bytes repeated_bytes = 45; - - // Repeated and nested - repeated NestedMessage repeated_nested_message = 51; - repeated NestedEnum repeated_nested_enum = 52; - repeated string repeated_string_piece = 53 [ctype = STRING_PIECE]; - repeated string repeated_cord = 54 [ctype = CORD]; - repeated NestedMessage repeated_lazy_message = 55; - - // Map - map map_int32_int64 = 56; - map map_string_string = 61; - map map_int64_nested_type = 62; - - oneof kind { - NestedTestAllTypes oneof_type = 63; - NestedMessage oneof_msg = 64; - bool oneof_bool = 65; - } -} - -// This proto includes a recursively nested message. -message NestedTestAllTypes { - NestedTestAllTypes child = 1; - TestAllTypes payload = 2; -} - -// This proto tests that global enums are resolved correctly. -enum GlobalEnum { - GOO = 0; - GAR = 1; - GAZ = 2; -} diff --git a/common/src/test/java/dev/cel/common/ast/BUILD.bazel b/common/src/test/java/dev/cel/common/ast/BUILD.bazel index 3f1868156..2097a25f7 100644 --- a/common/src/test/java/dev/cel/common/ast/BUILD.bazel +++ b/common/src/test/java/dev/cel/common/ast/BUILD.bazel @@ -22,7 +22,6 @@ java_library( "//common/ast:expr_factory", "//common/ast:expr_v1alpha1_converter", "//common/ast:mutable_expr", - "//common/resources/testdata/proto3:test_all_types_java_proto", "//common/types", "//compiler", "//compiler:compiler_builder", @@ -31,6 +30,7 @@ java_library( "//parser:operator", "@@protobuf~//java/core", "@cel_spec//proto/cel/expr:expr_java_proto", + "@cel_spec//proto/test/v1/proto3:test_all_types_java_proto", "@com_google_googleapis//google/api/expr/v1alpha1:expr_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_guava_guava_testlib", diff --git a/common/src/test/java/dev/cel/common/ast/CelExprFormatterTest.java b/common/src/test/java/dev/cel/common/ast/CelExprFormatterTest.java index be0652982..fee0ef6fd 100644 --- a/common/src/test/java/dev/cel/common/ast/CelExprFormatterTest.java +++ b/common/src/test/java/dev/cel/common/ast/CelExprFormatterTest.java @@ -16,6 +16,7 @@ import static com.google.common.truth.Truth.assertThat; +import com.google.api.expr.test.v1.proto3.TestAllTypesProto.TestAllTypes; import com.google.testing.junit.testparameterinjector.TestParameter; import com.google.testing.junit.testparameterinjector.TestParameterInjector; import dev.cel.common.CelAbstractSyntaxTree; @@ -27,7 +28,6 @@ import dev.cel.compiler.CelCompilerFactory; import dev.cel.extensions.CelOptionalLibrary; import dev.cel.parser.CelStandardMacro; -import dev.cel.testing.testdata.proto3.TestAllTypesProto.TestAllTypes; import org.junit.Test; import org.junit.runner.RunWith; @@ -173,7 +173,7 @@ public void list() throws Exception { public void struct() throws Exception { CelCompiler celCompiler = CelCompilerFactory.standardCelCompilerBuilder() - .setContainer("dev.cel.testing.testdata.proto3") + .setContainer("google.api.expr.test.v1.proto3") .addMessageTypes(TestAllTypes.getDescriptor()) .addLibraries(CelOptionalLibrary.INSTANCE) .build(); @@ -223,7 +223,7 @@ public void struct() throws Exception { public void map() throws Exception { CelCompiler celCompiler = CelCompilerFactory.standardCelCompilerBuilder() - .setContainer("dev.cel.testing.testdata.proto3") + .setContainer("google.api.expr.test.v1.proto3") .addMessageTypes(TestAllTypes.getDescriptor()) .addLibraries(CelOptionalLibrary.INSTANCE) .build(); diff --git a/common/src/test/java/dev/cel/common/ast/CelExprVisitorTest.java b/common/src/test/java/dev/cel/common/ast/CelExprVisitorTest.java index cdb3de525..f27c8a347 100644 --- a/common/src/test/java/dev/cel/common/ast/CelExprVisitorTest.java +++ b/common/src/test/java/dev/cel/common/ast/CelExprVisitorTest.java @@ -17,6 +17,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertThrows; +import com.google.api.expr.test.v1.proto3.TestAllTypesProto.TestAllTypes; import com.google.auto.value.AutoValue; import com.google.common.collect.ImmutableList; import dev.cel.common.CelAbstractSyntaxTree; @@ -33,7 +34,6 @@ import dev.cel.compiler.CelCompilerFactory; import dev.cel.parser.CelStandardMacro; import dev.cel.parser.Operator; -import dev.cel.testing.testdata.proto3.TestAllTypesProto.TestAllTypes; import java.util.Optional; import org.junit.Before; import org.junit.Test; diff --git a/common/src/test/java/dev/cel/common/internal/BUILD.bazel b/common/src/test/java/dev/cel/common/internal/BUILD.bazel index 5109b23ac..fa46ced6d 100644 --- a/common/src/test/java/dev/cel/common/internal/BUILD.bazel +++ b/common/src/test/java/dev/cel/common/internal/BUILD.bazel @@ -25,16 +25,14 @@ java_library( "//common/internal:errors", "//common/internal:proto_equality", "//common/internal:proto_message_factory", - "//common/resources/testdata/proto2:messages_extensions_proto2_java_proto", - "//common/resources/testdata/proto2:messages_proto2_java_proto", - "//common/resources/testdata/proto2:test_all_types_java_proto", - "//common/resources/testdata/proto3:test_all_types_java_proto", "//common/src/test/resources:default_instance_message_test_protos_java_proto", "//common/src/test/resources:multi_file_java_proto", "//common/src/test/resources:service_conflicting_name_java_proto", "//common/src/test/resources:single_file_java_proto", "//common/testing", "@@protobuf~//java/core", + "@cel_spec//proto/test/v1/proto2:test_all_types_java_proto", + "@cel_spec//proto/test/v1/proto3:test_all_types_java_proto", "@com_google_googleapis//google/type:type_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_testparameterinjector_test_parameter_injector", diff --git a/common/src/test/java/dev/cel/common/internal/CombinedDescriptorPoolTest.java b/common/src/test/java/dev/cel/common/internal/CombinedDescriptorPoolTest.java index a56bb2ed5..518c039e9 100644 --- a/common/src/test/java/dev/cel/common/internal/CombinedDescriptorPoolTest.java +++ b/common/src/test/java/dev/cel/common/internal/CombinedDescriptorPoolTest.java @@ -16,14 +16,13 @@ import static com.google.common.truth.Truth.assertThat; +import com.google.api.expr.test.v1.proto2.TestAllTypesExtensions; +import com.google.api.expr.test.v1.proto2.TestAllTypesProto.TestAllTypes; import com.google.common.collect.ImmutableList; import com.google.protobuf.Descriptors.FieldDescriptor; import com.google.protobuf.ExtensionRegistry; import com.google.protobuf.Value; import dev.cel.common.CelDescriptorUtil; -import dev.cel.testing.testdata.proto2.MessagesProto2Extensions; -import dev.cel.testing.testdata.proto2.Proto2Message; -import dev.cel.testing.testdata.proto2.TestAllTypesProto.TestAllTypes; import java.util.Optional; import org.junit.Test; import org.junit.runner.RunWith; @@ -67,19 +66,19 @@ public void findExtensionDescriptor_success() { CelDescriptorPool dynamicDescriptorPool = DefaultDescriptorPool.create( CelDescriptorUtil.getAllDescriptorsFromFileDescriptor( - MessagesProto2Extensions.getDescriptor().getFile())); + TestAllTypesExtensions.getDescriptor().getFile())); CombinedDescriptorPool combinedDescriptorPool = CombinedDescriptorPool.create( ImmutableList.of(DefaultDescriptorPool.INSTANCE, dynamicDescriptorPool)); Optional fieldDescriptor = combinedDescriptorPool.findExtensionDescriptor( - Proto2Message.getDescriptor(), "dev.cel.testing.testdata.proto2.test_all_types_ext"); + TestAllTypes.getDescriptor(), "google.api.expr.test.v1.proto2.test_all_types_ext"); assertThat(fieldDescriptor).isPresent(); assertThat(fieldDescriptor.get().isExtension()).isTrue(); assertThat(fieldDescriptor.get().getFullName()) - .isEqualTo("dev.cel.testing.testdata.proto2.test_all_types_ext"); + .isEqualTo("google.api.expr.test.v1.proto2.test_all_types_ext"); } @Test @@ -87,7 +86,7 @@ public void findExtensionDescriptor_returnsEmpty() { CelDescriptorPool dynamicDescriptorPool = DefaultDescriptorPool.create( CelDescriptorUtil.getAllDescriptorsFromFileDescriptor( - MessagesProto2Extensions.getDescriptor().getFile())); + TestAllTypesExtensions.getDescriptor().getFile())); CombinedDescriptorPool combinedDescriptorPool = CombinedDescriptorPool.create( ImmutableList.of(DefaultDescriptorPool.INSTANCE, dynamicDescriptorPool)); diff --git a/common/src/test/java/dev/cel/common/internal/DefaultInstanceMessageFactoryTest.java b/common/src/test/java/dev/cel/common/internal/DefaultInstanceMessageFactoryTest.java index a167190f9..c035db244 100644 --- a/common/src/test/java/dev/cel/common/internal/DefaultInstanceMessageFactoryTest.java +++ b/common/src/test/java/dev/cel/common/internal/DefaultInstanceMessageFactoryTest.java @@ -18,6 +18,7 @@ import static com.google.common.truth.Truth.assertThat; import static java.util.Arrays.stream; +import com.google.api.expr.test.v1.proto3.TestAllTypesProto.TestAllTypes; import com.google.common.collect.ImmutableList; import com.google.common.util.concurrent.MoreExecutors; import com.google.protobuf.Descriptors.Descriptor; @@ -31,7 +32,6 @@ import com.google.testing.junit.testparameterinjector.TestParameterInjector; import dev.cel.common.testdata.ProtoJavaApiVersion1.Proto2JavaVersion1Message; import dev.cel.common.testing.RepeatedTestProvider; -import dev.cel.testing.testdata.proto3.TestAllTypesProto.TestAllTypes; import java.util.ArrayList; import java.util.List; import java.util.Optional; diff --git a/common/src/test/java/dev/cel/common/internal/DefaultMessageFactoryTest.java b/common/src/test/java/dev/cel/common/internal/DefaultMessageFactoryTest.java index aef6140bf..16f170746 100644 --- a/common/src/test/java/dev/cel/common/internal/DefaultMessageFactoryTest.java +++ b/common/src/test/java/dev/cel/common/internal/DefaultMessageFactoryTest.java @@ -17,6 +17,7 @@ import static com.google.common.truth.Truth.assertThat; import static java.nio.charset.StandardCharsets.UTF_8; +import com.google.api.expr.test.v1.proto2.TestAllTypesProto.TestAllTypes; import com.google.common.base.Ascii; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; @@ -29,7 +30,6 @@ import dev.cel.common.CelDescriptorUtil; import dev.cel.common.CelDescriptors; import dev.cel.common.internal.ProtoMessageFactory.CombinedMessageFactory; -import dev.cel.testing.testdata.proto2.TestAllTypesProto.TestAllTypes; import java.util.Optional; import org.junit.Test; import org.junit.runner.RunWith; @@ -59,7 +59,7 @@ public void newBuilder_withDescriptor_producesNewMessageBuilder() { TestAllTypes.Builder builder = (TestAllTypes.Builder) - messageFactory.newBuilder("dev.cel.testing.testdata.proto2.TestAllTypes").get(); + messageFactory.newBuilder("google.api.expr.test.v1.proto2.TestAllTypes").get(); assertThat(builder.setSingleInt64(5L).build()) .isEqualTo(TestAllTypes.newBuilder().setSingleInt64(5L).build()); diff --git a/common/src/test/java/dev/cel/common/internal/ProtoEqualityTest.java b/common/src/test/java/dev/cel/common/internal/ProtoEqualityTest.java index 7cbabf9bc..722d088b0 100644 --- a/common/src/test/java/dev/cel/common/internal/ProtoEqualityTest.java +++ b/common/src/test/java/dev/cel/common/internal/ProtoEqualityTest.java @@ -16,14 +16,14 @@ import static com.google.common.truth.Truth.assertThat; +import com.google.api.expr.test.v1.proto3.TestAllTypesProto.TestAllTypes; +import com.google.api.expr.test.v1.proto3.TestAllTypesProto.TestAllTypes.NestedEnum; +import com.google.api.expr.test.v1.proto3.TestAllTypesProto.TestAllTypes.NestedMessage; import com.google.protobuf.Any; import com.google.protobuf.DynamicMessage; import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.Struct; import com.google.protobuf.Value; -import dev.cel.testing.testdata.proto3.TestAllTypesProto.TestAllTypes; -import dev.cel.testing.testdata.proto3.TestAllTypesProto.TestAllTypes.NestedEnum; -import dev.cel.testing.testdata.proto3.TestAllTypesProto.TestAllTypes.NestedMessage; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/common/src/test/java/dev/cel/common/navigation/BUILD.bazel b/common/src/test/java/dev/cel/common/navigation/BUILD.bazel index f79a59482..c754e80df 100644 --- a/common/src/test/java/dev/cel/common/navigation/BUILD.bazel +++ b/common/src/test/java/dev/cel/common/navigation/BUILD.bazel @@ -17,12 +17,12 @@ java_library( "//common/navigation", "//common/navigation:common", "//common/navigation:mutable_navigation", - "//common/resources/testdata/proto3:test_all_types_java_proto", "//common/types", "//compiler", "//compiler:compiler_builder", "//parser:macro", "//parser:operator", + "@cel_spec//proto/test/v1/proto3:test_all_types_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_testparameterinjector_test_parameter_injector", "@maven//:junit_junit", diff --git a/common/src/test/java/dev/cel/common/navigation/CelNavigableExprVisitorTest.java b/common/src/test/java/dev/cel/common/navigation/CelNavigableExprVisitorTest.java index 101fb9fdb..a8a35dd67 100644 --- a/common/src/test/java/dev/cel/common/navigation/CelNavigableExprVisitorTest.java +++ b/common/src/test/java/dev/cel/common/navigation/CelNavigableExprVisitorTest.java @@ -20,6 +20,7 @@ import static dev.cel.common.CelOverloadDecl.newMemberOverload; import static org.junit.Assert.assertThrows; +import com.google.api.expr.test.v1.proto3.TestAllTypesProto.TestAllTypes; import com.google.common.collect.ImmutableList; import com.google.common.primitives.UnsignedLong; import com.google.testing.junit.testparameterinjector.TestParameter; @@ -38,7 +39,6 @@ import dev.cel.compiler.CelCompilerFactory; import dev.cel.parser.CelStandardMacro; import dev.cel.parser.Operator; -import dev.cel.testing.testdata.proto3.TestAllTypesProto.TestAllTypes; import java.util.Optional; import org.junit.Test; import org.junit.runner.RunWith; @@ -580,7 +580,7 @@ public void messageConstruction_allNodesReturned() throws Exception { CelCompiler compiler = CelCompilerFactory.standardCelCompilerBuilder() .addMessageTypes(TestAllTypes.getDescriptor()) - .setContainer("dev.cel.testing.testdata.proto3") + .setContainer("google.api.expr.test.v1.proto3") .build(); CelAbstractSyntaxTree ast = compiler.compile("TestAllTypes{single_int64: 1}").getAst(); CelNavigableAst navigableAst = CelNavigableAst.fromAst(ast); @@ -603,7 +603,7 @@ public void messageConstruction_filterStruct_allNodesReturned() throws Exception CelCompiler compiler = CelCompilerFactory.standardCelCompilerBuilder() .addMessageTypes(TestAllTypes.getDescriptor()) - .setContainer("dev.cel.testing.testdata.proto3") + .setContainer("google.api.expr.test.v1.proto3") .build(); CelAbstractSyntaxTree ast = compiler.compile("TestAllTypes{single_int64: 1}").getAst(); CelNavigableAst navigableAst = CelNavigableAst.fromAst(ast); @@ -631,7 +631,7 @@ public void messageConstruction_preOrder_heightSet() throws Exception { CelCompiler compiler = CelCompilerFactory.standardCelCompilerBuilder() .addMessageTypes(TestAllTypes.getDescriptor()) - .setContainer("dev.cel.testing.testdata.proto3") + .setContainer("google.api.expr.test.v1.proto3") .build(); CelAbstractSyntaxTree ast = compiler.compile("TestAllTypes{single_int64: 1}").getAst(); CelNavigableAst navigableAst = CelNavigableAst.fromAst(ast); @@ -651,7 +651,7 @@ public void messageConstruction_postOrder_heightSet() throws Exception { CelCompiler compiler = CelCompilerFactory.standardCelCompilerBuilder() .addMessageTypes(TestAllTypes.getDescriptor()) - .setContainer("dev.cel.testing.testdata.proto3") + .setContainer("google.api.expr.test.v1.proto3") .build(); CelAbstractSyntaxTree ast = compiler.compile("TestAllTypes{single_int64: 1}").getAst(); CelNavigableAst navigableAst = CelNavigableAst.fromAst(ast); @@ -672,7 +672,7 @@ public void messageConstruction_maxIdsSet(@TestParameter TraversalOrder traversa CelCompiler compiler = CelCompilerFactory.standardCelCompilerBuilder() .addMessageTypes(TestAllTypes.getDescriptor()) - .setContainer("dev.cel.testing.testdata.proto3") + .setContainer("google.api.expr.test.v1.proto3") .build(); CelAbstractSyntaxTree ast = compiler.compile("TestAllTypes{single_int64: 1}").getAst(); CelNavigableAst navigableAst = CelNavigableAst.fromAst(ast); diff --git a/common/src/test/java/dev/cel/common/types/BUILD.bazel b/common/src/test/java/dev/cel/common/types/BUILD.bazel index 44f3fac01..432ff1570 100644 --- a/common/src/test/java/dev/cel/common/types/BUILD.bazel +++ b/common/src/test/java/dev/cel/common/types/BUILD.bazel @@ -8,15 +8,14 @@ java_library( srcs = glob(["*.java"]), deps = [ "//:java_truth", - "//common/resources/testdata/proto2:messages_extensions_proto2_java_proto", - "//common/resources/testdata/proto2:messages_proto2_java_proto", - "//common/resources/testdata/proto3:test_all_types_java_proto", "//common/types", "//common/types:cel_internal_types", "//common/types:cel_types", "//common/types:message_type_provider", "//common/types:type_providers", "@cel_spec//proto/cel/expr:expr_java_proto", + "@cel_spec//proto/test/v1/proto2:test_all_types_java_proto", + "@cel_spec//proto/test/v1/proto3:test_all_types_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_testparameterinjector_test_parameter_injector", "@maven//:com_google_truth_extensions_truth_proto_extension", diff --git a/common/src/test/java/dev/cel/common/types/ProtoMessageTypeProviderTest.java b/common/src/test/java/dev/cel/common/types/ProtoMessageTypeProviderTest.java index f07a67b71..a79bb1ffe 100644 --- a/common/src/test/java/dev/cel/common/types/ProtoMessageTypeProviderTest.java +++ b/common/src/test/java/dev/cel/common/types/ProtoMessageTypeProviderTest.java @@ -17,12 +17,12 @@ import static com.google.common.collect.ImmutableList.toImmutableList; import static com.google.common.truth.Truth.assertThat; +import com.google.api.expr.test.v1.proto2.TestAllTypesExtensions; +import com.google.api.expr.test.v1.proto2.TestAllTypesProto; +import com.google.api.expr.test.v1.proto3.TestAllTypesProto.TestAllTypes; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import dev.cel.common.types.CelTypeProvider.CombinedCelTypeProvider; -import dev.cel.testing.testdata.proto2.MessagesProto2; -import dev.cel.testing.testdata.proto2.MessagesProto2Extensions; -import dev.cel.testing.testdata.proto3.TestAllTypesProto.TestAllTypes; import java.util.Optional; import org.junit.Test; import org.junit.runner.RunWith; @@ -39,7 +39,9 @@ public final class ProtoMessageTypeProviderTest { private final ProtoMessageTypeProvider proto2Provider = new ProtoMessageTypeProvider( ImmutableSet.of( - MessagesProto2.getDescriptor(), MessagesProto2Extensions.getDescriptor())); + TestAllTypes.getDescriptor().getFile(), + TestAllTypesProto.TestAllTypes.getDescriptor().getFile(), + TestAllTypesExtensions.getDescriptor())); @Test public void types_emptyTypeSet() { @@ -55,21 +57,21 @@ public void findType_emptyTypeSet() { public void types_allGlobalAndNestedDeclarations() { assertThat(proto3Provider.types().stream().map(CelType::name).collect(toImmutableList())) .containsAtLeast( - "dev.cel.testing.testdata.proto3.GlobalEnum", - "dev.cel.testing.testdata.proto3.TestAllTypes", - "dev.cel.testing.testdata.proto3.TestAllTypes.NestedMessage", - "dev.cel.testing.testdata.proto3.TestAllTypes.NestedEnum", - "dev.cel.testing.testdata.proto3.NestedTestAllTypes"); + "google.api.expr.test.v1.proto3.GlobalEnum", + "google.api.expr.test.v1.proto3.TestAllTypes", + "google.api.expr.test.v1.proto3.TestAllTypes.NestedMessage", + "google.api.expr.test.v1.proto3.TestAllTypes.NestedEnum", + "google.api.expr.test.v1.proto3.NestedTestAllTypes"); } @Test public void findType_globalEnumWithAllNamesAndNumbers() { Optional celType = - proto3Provider.findType("dev.cel.testing.testdata.proto3.GlobalEnum"); + proto3Provider.findType("google.api.expr.test.v1.proto3.GlobalEnum"); assertThat(celType).isPresent(); assertThat(celType.get()).isInstanceOf(EnumType.class); EnumType enumType = (EnumType) celType.get(); - assertThat(enumType.name()).isEqualTo("dev.cel.testing.testdata.proto3.GlobalEnum"); + assertThat(enumType.name()).isEqualTo("google.api.expr.test.v1.proto3.GlobalEnum"); assertThat(enumType.findNameByNumber(0)).hasValue("GOO"); assertThat(enumType.findNameByNumber(1)).hasValue("GAR"); assertThat(enumType.findNameByNumber(2)).hasValue("GAZ"); @@ -79,12 +81,11 @@ public void findType_globalEnumWithAllNamesAndNumbers() { @Test public void findType_nestedEnumWithAllNamesAndNumbers() { Optional celType = - proto3Provider.findType("dev.cel.testing.testdata.proto3.TestAllTypes.NestedEnum"); + proto3Provider.findType("google.api.expr.test.v1.proto3.TestAllTypes.NestedEnum"); assertThat(celType).isPresent(); assertThat(celType.get()).isInstanceOf(EnumType.class); EnumType enumType = (EnumType) celType.get(); - assertThat(enumType.name()) - .isEqualTo("dev.cel.testing.testdata.proto3.TestAllTypes.NestedEnum"); + assertThat(enumType.name()).isEqualTo("google.api.expr.test.v1.proto3.TestAllTypes.NestedEnum"); assertThat(enumType.findNumberByName("FOO")).hasValue(0); assertThat(enumType.findNumberByName("BAR")).hasValue(1); assertThat(enumType.findNumberByName("BAZ")).hasValue(2); @@ -94,11 +95,11 @@ public void findType_nestedEnumWithAllNamesAndNumbers() { @Test public void findType_globalMessageTypeNoExtensions() { Optional celType = - proto3Provider.findType("dev.cel.testing.testdata.proto3.NestedTestAllTypes"); + proto3Provider.findType("google.api.expr.test.v1.proto3.NestedTestAllTypes"); assertThat(celType).isPresent(); assertThat(celType.get()).isInstanceOf(ProtoMessageType.class); ProtoMessageType protoType = (ProtoMessageType) celType.get(); - assertThat(protoType.name()).isEqualTo("dev.cel.testing.testdata.proto3.NestedTestAllTypes"); + assertThat(protoType.name()).isEqualTo("google.api.expr.test.v1.proto3.NestedTestAllTypes"); assertThat(protoType.findField("payload")).isPresent(); assertThat(protoType.findField("child")).isPresent(); assertThat(protoType.findField("missing")).isEmpty(); @@ -109,101 +110,99 @@ public void findType_globalMessageTypeNoExtensions() { @Test public void findType_globalMessageWithExtensions() { Optional celType = - proto2Provider.findType("dev.cel.testing.testdata.proto2.Proto2Message"); + proto2Provider.findType("google.api.expr.test.v1.proto2.TestAllTypes"); assertThat(celType).isPresent(); assertThat(celType.get()).isInstanceOf(ProtoMessageType.class); ProtoMessageType protoType = (ProtoMessageType) celType.get(); - assertThat(protoType.name()).isEqualTo("dev.cel.testing.testdata.proto2.Proto2Message"); + assertThat(protoType.name()).isEqualTo("google.api.expr.test.v1.proto2.TestAllTypes"); assertThat(protoType.findField("single_int32")).isPresent(); - assertThat(protoType.findField("single_enum")).isPresent(); - assertThat(protoType.findField("single_nested_test_all_types")).isPresent(); + assertThat(protoType.findField("single_uint64")).isPresent(); + assertThat(protoType.findField("oneof_type")).isPresent(); assertThat(protoType.findField("nestedgroup")).isPresent(); - assertThat(protoType.findField("nested_ext")).isEmpty(); + assertThat(protoType.findField("nested_enum_ext")).isEmpty(); - assertThat(protoType.findExtension("dev.cel.testing.testdata.proto2.nested_ext")).isPresent(); - assertThat(protoType.findExtension("dev.cel.testing.testdata.proto2.int32_ext")).isPresent(); - assertThat(protoType.findExtension("dev.cel.testing.testdata.proto2.test_all_types_ext")) + assertThat(protoType.findExtension("google.api.expr.test.v1.proto2.nested_ext")).isPresent(); + assertThat(protoType.findExtension("google.api.expr.test.v1.proto2.int32_ext")).isPresent(); + assertThat(protoType.findExtension("google.api.expr.test.v1.proto2.test_all_types_ext")) .isPresent(); - assertThat(protoType.findExtension("dev.cel.testing.testdata.proto2.nested_enum_ext")) + assertThat(protoType.findExtension("google.api.expr.test.v1.proto2.nested_enum_ext")) .isPresent(); - assertThat( - protoType.findExtension("dev.cel.testing.testdata.proto2.repeated_string_holder_ext")) + assertThat(protoType.findExtension("google.api.expr.test.v1.proto2.repeated_test_all_types")) .isPresent(); - assertThat(protoType.findExtension("dev.cel.testing.testdata.proto2.Proto2Message.int32_ext")) + assertThat(protoType.findExtension("google.api.expr.test.v1.proto2.TestAllTypes.int32_ext")) .isEmpty(); Optional holderType = - proto2Provider.findType("dev.cel.testing.testdata.proto2.StringHolder"); + proto2Provider.findType("google.api.expr.test.v1.proto2.TestRequired"); assertThat(holderType).isPresent(); ProtoMessageType stringHolderType = (ProtoMessageType) holderType.get(); - assertThat(stringHolderType.findExtension("dev.cel.testing.testdata.proto2.nested_enum_ext")) + assertThat(stringHolderType.findExtension("google.api.expr.test.v1.proto2.nested_enum_ext")) .isEmpty(); } @Test public void findType_scopedMessageWithExtensions() { Optional celType = - proto2Provider.findType("dev.cel.testing.testdata.proto2.Proto2Message"); + proto2Provider.findType("google.api.expr.test.v1.proto2.TestAllTypes"); assertThat(celType).isPresent(); assertThat(celType.get()).isInstanceOf(ProtoMessageType.class); ProtoMessageType protoType = (ProtoMessageType) celType.get(); assertThat( protoType.findExtension( - "dev.cel.testing.testdata.proto2.Proto2ExtensionScopedMessage.message_scoped_nested_ext")) + "google.api.expr.test.v1.proto2.Proto2ExtensionScopedMessage.message_scoped_nested_ext")) .isPresent(); assertThat( protoType.findExtension( - "dev.cel.testing.testdata.proto2.Proto2ExtensionScopedMessage.int64_ext")) + "google.api.expr.test.v1.proto2.Proto2ExtensionScopedMessage.int64_ext")) .isPresent(); assertThat( protoType.findExtension( - "dev.cel.testing.testdata.proto2.Proto2ExtensionScopedMessage.string_ext")) + "google.api.expr.test.v1.proto2.Proto2ExtensionScopedMessage.message_scoped_repeated_test_all_types")) .isPresent(); assertThat( protoType.findExtension( - "dev.cel.testing.testdata.proto2.Proto2ExtensionScopedMessage.nested_message_inside_ext")) + "google.api.expr.test.v1.proto2.Proto2ExtensionScopedMessage.message_scoped_nested_ext")) .isPresent(); } @Test public void findType_withRepeatedEnumField() { Optional celType = - proto3Provider.findType("dev.cel.testing.testdata.proto3.TestAllTypes"); + proto3Provider.findType("google.api.expr.test.v1.proto3.TestAllTypes"); assertThat(celType).isPresent(); assertThat(celType.get()).isInstanceOf(ProtoMessageType.class); ProtoMessageType protoType = (ProtoMessageType) celType.get(); - assertThat(protoType.name()).isEqualTo("dev.cel.testing.testdata.proto3.TestAllTypes"); + assertThat(protoType.name()).isEqualTo("google.api.expr.test.v1.proto3.TestAllTypes"); assertThat(protoType.findField("repeated_nested_enum")).isPresent(); CelType fieldType = protoType.findField("repeated_nested_enum").get().type(); assertThat(fieldType.kind()).isEqualTo(CelKind.LIST); assertThat(fieldType.parameters()).hasSize(1); CelType elemType = fieldType.parameters().get(0); - assertThat(elemType.name()) - .isEqualTo("dev.cel.testing.testdata.proto3.TestAllTypes.NestedEnum"); + assertThat(elemType.name()).isEqualTo("google.api.expr.test.v1.proto3.TestAllTypes.NestedEnum"); assertThat(elemType.kind()).isEqualTo(CelKind.INT); assertThat(elemType).isInstanceOf(EnumType.class); - assertThat(proto3Provider.findType("dev.cel.testing.testdata.proto3.TestAllTypes.NestedEnum")) + assertThat(proto3Provider.findType("google.api.expr.test.v1.proto3.TestAllTypes.NestedEnum")) .hasValue(elemType); } @Test public void findType_withOneofField() { Optional celType = - proto3Provider.findType("dev.cel.testing.testdata.proto3.TestAllTypes"); + proto3Provider.findType("google.api.expr.test.v1.proto3.TestAllTypes"); ProtoMessageType protoType = (ProtoMessageType) celType.get(); - assertThat(protoType.name()).isEqualTo("dev.cel.testing.testdata.proto3.TestAllTypes"); + assertThat(protoType.name()).isEqualTo("google.api.expr.test.v1.proto3.TestAllTypes"); assertThat(protoType.findField("single_nested_message").map(f -> f.type().name())) - .hasValue("dev.cel.testing.testdata.proto3.TestAllTypes.NestedMessage"); + .hasValue("google.api.expr.test.v1.proto3.TestAllTypes.NestedMessage"); } @Test public void findType_withMapField() { Optional celType = - proto3Provider.findType("dev.cel.testing.testdata.proto3.TestAllTypes"); + proto3Provider.findType("google.api.expr.test.v1.proto3.TestAllTypes"); ProtoMessageType protoType = (ProtoMessageType) celType.get(); CelType fieldType = protoType.findField("map_int64_nested_type").get().type(); @@ -213,14 +212,14 @@ public void findType_withMapField() { CelType valueType = fieldType.parameters().get(1); assertThat(keyType.name()).isEqualTo("int"); assertThat(keyType.kind()).isEqualTo(CelKind.INT); - assertThat(valueType.name()).isEqualTo("dev.cel.testing.testdata.proto3.NestedTestAllTypes"); + assertThat(valueType.name()).isEqualTo("google.api.expr.test.v1.proto3.NestedTestAllTypes"); assertThat(valueType.kind()).isEqualTo(CelKind.STRUCT); } @Test public void findType_withWellKnownTypes() { Optional celType = - proto3Provider.findType("dev.cel.testing.testdata.proto3.TestAllTypes"); + proto3Provider.findType("google.api.expr.test.v1.proto3.TestAllTypes"); ProtoMessageType protoType = (ProtoMessageType) celType.get(); assertThat(protoType.findField("single_any").map(f -> f.type())).hasValue(SimpleType.ANY); assertThat(protoType.findField("single_duration").map(f -> f.type())) @@ -228,7 +227,7 @@ public void findType_withWellKnownTypes() { assertThat(protoType.findField("single_timestamp").map(f -> f.type())) .hasValue(SimpleType.TIMESTAMP); assertThat(protoType.findField("single_value").map(f -> f.type())).hasValue(SimpleType.DYN); - assertThat(protoType.findField("single_list_value").map(f -> f.type())) + assertThat(protoType.findField("list_value").map(f -> f.type())) .hasValue(ListType.create(SimpleType.DYN)); assertThat(protoType.findField("single_struct").map(f -> f.type())) .hasValue(MapType.create(SimpleType.STRING, SimpleType.DYN)); diff --git a/common/src/test/java/dev/cel/common/values/BUILD.bazel b/common/src/test/java/dev/cel/common/values/BUILD.bazel index 388e4d6fb..92b71c6db 100644 --- a/common/src/test/java/dev/cel/common/values/BUILD.bazel +++ b/common/src/test/java/dev/cel/common/values/BUILD.bazel @@ -16,9 +16,6 @@ java_library( "//common/internal:default_message_factory", "//common/internal:dynamic_proto", "//common/internal:proto_message_factory", - "//common/resources/testdata/proto2:messages_extensions_proto2_java_proto", - "//common/resources/testdata/proto2:messages_proto2_java_proto", - "//common/resources/testdata/proto2:test_all_types_java_proto", "//common/types", "//common/types:type_providers", "//common/values", @@ -28,6 +25,7 @@ java_library( "//common/values:proto_message_value", "//common/values:proto_message_value_provider", "@@protobuf~//java/core", + "@cel_spec//proto/test/v1/proto2:test_all_types_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_guava_guava_testlib", "@maven//:com_google_protobuf_protobuf_java_util", diff --git a/common/src/test/java/dev/cel/common/values/ProtoMessageValueProviderTest.java b/common/src/test/java/dev/cel/common/values/ProtoMessageValueProviderTest.java index 6dfb01344..0a2fe2ca6 100644 --- a/common/src/test/java/dev/cel/common/values/ProtoMessageValueProviderTest.java +++ b/common/src/test/java/dev/cel/common/values/ProtoMessageValueProviderTest.java @@ -17,6 +17,8 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertThrows; +import com.google.api.expr.test.v1.proto2.TestAllTypesExtensions; +import com.google.api.expr.test.v1.proto2.TestAllTypesProto.TestAllTypes; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.primitives.UnsignedLong; @@ -32,9 +34,6 @@ import dev.cel.common.internal.DynamicProto; import dev.cel.common.internal.ProtoMessageFactory; import dev.cel.common.values.CelValueProvider.CombinedCelValueProvider; -import dev.cel.testing.testdata.proto2.MessagesProto2Extensions; -import dev.cel.testing.testdata.proto2.Proto2Message; -import dev.cel.testing.testdata.proto2.TestAllTypesProto.TestAllTypes; import java.time.Duration; import java.time.Instant; import java.util.Optional; @@ -48,8 +47,7 @@ public class ProtoMessageValueProviderTest { DefaultDescriptorPool.create( CelDescriptorUtil.getAllDescriptorsFromFileDescriptor( ImmutableList.of( - TestAllTypes.getDescriptor().getFile(), - MessagesProto2Extensions.getDescriptor()))); + TestAllTypes.getDescriptor().getFile(), TestAllTypesExtensions.getDescriptor()))); private static final ProtoMessageFactory MESSAGE_FACTORY = DefaultMessageFactory.create(DESCRIPTOR_POOL); @@ -198,14 +196,14 @@ public void newValue_createProtoMessage_extensionFieldsPopulated() { (ProtoMessageValue) protoMessageValueProvider .newValue( - Proto2Message.getDescriptor().getFullName(), - ImmutableMap.of("dev.cel.testing.testdata.proto2.int32_ext", 1)) + TestAllTypes.getDescriptor().getFullName(), + ImmutableMap.of("google.api.expr.test.v1.proto2.int32_ext", 1)) .get(); assertThat(protoMessageValue.isZeroValue()).isFalse(); assertThat( protoMessageValue - .select(StringValue.create("dev.cel.testing.testdata.proto2.int32_ext")) + .select(StringValue.create("google.api.expr.test.v1.proto2.int32_ext")) .value()) .isEqualTo(1); } @@ -241,7 +239,7 @@ public void newValue_invalidField_throws() { .hasMessageThat() .isEqualTo( "field 'bogus' is not declared in message" - + " 'dev.cel.testing.testdata.proto2.TestAllTypes'"); + + " 'google.api.expr.test.v1.proto2.TestAllTypes'"); } @Test diff --git a/common/src/test/java/dev/cel/common/values/ProtoMessageValueTest.java b/common/src/test/java/dev/cel/common/values/ProtoMessageValueTest.java index 32f89e7a1..3a0f6e14e 100644 --- a/common/src/test/java/dev/cel/common/values/ProtoMessageValueTest.java +++ b/common/src/test/java/dev/cel/common/values/ProtoMessageValueTest.java @@ -17,6 +17,10 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertThrows; +import com.google.api.expr.test.v1.proto2.TestAllTypesExtensions; +import com.google.api.expr.test.v1.proto2.TestAllTypesProto.TestAllTypes; +import com.google.api.expr.test.v1.proto2.TestAllTypesProto.TestAllTypes.NestedEnum; +import com.google.api.expr.test.v1.proto2.TestAllTypesProto.TestAllTypes.NestedMessage; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.primitives.UnsignedLong; @@ -41,11 +45,6 @@ import dev.cel.common.internal.DefaultMessageFactory; import dev.cel.common.internal.DynamicProto; import dev.cel.common.types.StructTypeReference; -import dev.cel.testing.testdata.proto2.MessagesProto2Extensions; -import dev.cel.testing.testdata.proto2.Proto2Message; -import dev.cel.testing.testdata.proto2.TestAllTypesProto.TestAllTypes; -import dev.cel.testing.testdata.proto2.TestAllTypesProto.TestAllTypes.NestedEnum; -import dev.cel.testing.testdata.proto2.TestAllTypesProto.TestAllTypes.NestedMessage; import java.time.Duration; import java.time.Instant; import org.junit.Test; @@ -130,7 +129,7 @@ public void findField_fieldIsUndeclared_throwsException() { .hasMessageThat() .isEqualTo( "field 'bogus' is not declared in message" - + " 'dev.cel.testing.testdata.proto2.TestAllTypes'"); + + " 'google.api.expr.test.v1.proto2.TestAllTypes'"); } @Test @@ -138,27 +137,27 @@ public void findField_extensionField_success() { CelDescriptorPool descriptorPool = DefaultDescriptorPool.create( CelDescriptorUtil.getAllDescriptorsFromFileDescriptor( - ImmutableList.of(MessagesProto2Extensions.getDescriptor()))); + ImmutableList.of(TestAllTypesExtensions.getDescriptor()))); ProtoCelValueConverter protoCelValueConverter = ProtoCelValueConverter.newInstance( CelOptions.DEFAULT, DefaultDescriptorPool.INSTANCE, DynamicProto.create(DefaultMessageFactory.create(descriptorPool))); - Proto2Message proto2Message = - Proto2Message.newBuilder().setExtension(MessagesProto2Extensions.int32Ext, 1).build(); + TestAllTypes proto2Message = + TestAllTypes.newBuilder().setExtension(TestAllTypesExtensions.int32Ext, 1).build(); ProtoMessageValue protoMessageValue = ProtoMessageValue.create(proto2Message, descriptorPool, protoCelValueConverter); assertThat( - protoMessageValue.find(StringValue.create("dev.cel.testing.testdata.proto2.int32_ext"))) + protoMessageValue.find(StringValue.create("google.api.expr.test.v1.proto2.int32_ext"))) .isPresent(); } @Test public void findField_extensionField_throwsWhenDescriptorMissing() { - Proto2Message proto2Message = - Proto2Message.newBuilder().setExtension(MessagesProto2Extensions.int32Ext, 1).build(); + TestAllTypes proto2Message = + TestAllTypes.newBuilder().setExtension(TestAllTypesExtensions.int32Ext, 1).build(); ProtoMessageValue protoMessageValue = ProtoMessageValue.create( @@ -169,12 +168,12 @@ public void findField_extensionField_throwsWhenDescriptorMissing() { IllegalArgumentException.class, () -> protoMessageValue.select( - StringValue.create("dev.cel.testing.testdata.proto2.int32_ext"))); + StringValue.create("google.api.expr.test.v1.proto2.int32_ext"))); assertThat(exception) .hasMessageThat() .isEqualTo( - "field 'dev.cel.testing.testdata.proto2.int32_ext' is not declared in message" - + " 'dev.cel.testing.testdata.proto2.Proto2Message'"); + "field 'google.api.expr.test.v1.proto2.int32_ext' is not declared in message" + + " 'google.api.expr.test.v1.proto2.TestAllTypes'"); } private enum SelectFieldTestCase { diff --git a/extensions/src/test/java/dev/cel/extensions/BUILD.bazel b/extensions/src/test/java/dev/cel/extensions/BUILD.bazel index 6cfbe3381..13411adb0 100644 --- a/extensions/src/test/java/dev/cel/extensions/BUILD.bazel +++ b/extensions/src/test/java/dev/cel/extensions/BUILD.bazel @@ -12,10 +12,6 @@ java_library( "//common", "//common:compiler_common", "//common:options", - "//common/resources/testdata/proto2:messages_extensions_proto2_java_proto", - "//common/resources/testdata/proto2:messages_proto2_java_proto", - "//common/resources/testdata/proto2:test_all_types_java_proto", - "//common/resources/testdata/proto3:test_all_types_java_proto", "//common/types", "//common/types:type_providers", "//compiler", @@ -30,6 +26,8 @@ java_library( "//runtime:interpreter_util", "@@protobuf~//java/core", "@cel_spec//proto/cel/expr:expr_java_proto", + "@cel_spec//proto/test/v1/proto2:test_all_types_java_proto", + "@cel_spec//proto/test/v1/proto3:test_all_types_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java_util", "@maven//:com_google_testparameterinjector_test_parameter_injector", diff --git a/extensions/src/test/java/dev/cel/extensions/CelBindingsExtensionsTest.java b/extensions/src/test/java/dev/cel/extensions/CelBindingsExtensionsTest.java index 1eba6e22c..05caf8000 100644 --- a/extensions/src/test/java/dev/cel/extensions/CelBindingsExtensionsTest.java +++ b/extensions/src/test/java/dev/cel/extensions/CelBindingsExtensionsTest.java @@ -17,6 +17,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertThrows; +import com.google.api.expr.test.v1.proto3.TestAllTypesProto.TestAllTypes; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.testing.junit.testparameterinjector.TestParameter; @@ -34,7 +35,6 @@ import dev.cel.runtime.CelRuntime; import dev.cel.runtime.CelRuntime.CelFunctionBinding; import dev.cel.runtime.CelRuntimeFactory; -import dev.cel.testing.testdata.proto3.TestAllTypesProto.TestAllTypes; import java.util.Arrays; import java.util.concurrent.atomic.AtomicInteger; import org.junit.Test; diff --git a/extensions/src/test/java/dev/cel/extensions/CelOptionalLibraryTest.java b/extensions/src/test/java/dev/cel/extensions/CelOptionalLibraryTest.java index 12eab47c4..c877555c2 100644 --- a/extensions/src/test/java/dev/cel/extensions/CelOptionalLibraryTest.java +++ b/extensions/src/test/java/dev/cel/extensions/CelOptionalLibraryTest.java @@ -18,6 +18,8 @@ import static org.junit.Assert.assertThrows; import dev.cel.expr.Value; +import com.google.api.expr.test.v1.proto2.TestAllTypesProto.TestAllTypes; +import com.google.api.expr.test.v1.proto2.TestAllTypesProto.TestAllTypes.NestedMessage; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.primitives.UnsignedLong; @@ -48,8 +50,6 @@ import dev.cel.runtime.CelRuntime; import dev.cel.runtime.CelRuntime.CelFunctionBinding; import dev.cel.runtime.InterpreterUtil; -import dev.cel.testing.testdata.proto2.TestAllTypesProto.TestAllTypes; -import dev.cel.testing.testdata.proto2.TestAllTypesProto.TestAllTypes.NestedMessage; import java.util.List; import java.util.Map; import java.util.Optional; @@ -94,7 +94,7 @@ private static CelBuilder newCelBuilder() { .setOptions( CelOptions.current().enableUnsignedLongs(true).enableTimestampEpoch(true).build()) .setStandardMacros(CelStandardMacro.STANDARD_MACROS) - .setContainer("dev.cel.testing.testdata.proto2") + .setContainer("google.api.expr.test.v1.proto2") .addMessageTypes(TestAllTypes.getDescriptor()) .addRuntimeLibraries(CelOptionalLibrary.INSTANCE) .addCompilerLibraries(CelOptionalLibrary.INSTANCE); diff --git a/extensions/src/test/java/dev/cel/extensions/CelProtoExtensionsTest.java b/extensions/src/test/java/dev/cel/extensions/CelProtoExtensionsTest.java index d7b66cb1d..530ba73ae 100644 --- a/extensions/src/test/java/dev/cel/extensions/CelProtoExtensionsTest.java +++ b/extensions/src/test/java/dev/cel/extensions/CelProtoExtensionsTest.java @@ -17,6 +17,10 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertThrows; +import com.google.api.expr.test.v1.proto2.Proto2ExtensionScopedMessage; +import com.google.api.expr.test.v1.proto2.TestAllTypesExtensions; +import com.google.api.expr.test.v1.proto2.TestAllTypesProto.TestAllTypes; +import com.google.api.expr.test.v1.proto2.TestAllTypesProto.TestAllTypes.NestedEnum; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.protobuf.Any; @@ -39,12 +43,6 @@ import dev.cel.runtime.CelRuntime; import dev.cel.runtime.CelRuntime.CelFunctionBinding; import dev.cel.runtime.CelRuntimeFactory; -import dev.cel.testing.testdata.proto2.MessagesProto2Extensions; -import dev.cel.testing.testdata.proto2.NestedMessageInsideExtensions; -import dev.cel.testing.testdata.proto2.Proto2ExtensionScopedMessage; -import dev.cel.testing.testdata.proto2.Proto2Message; -import dev.cel.testing.testdata.proto2.StringHolder; -import dev.cel.testing.testdata.proto2.TestAllTypesProto.TestAllTypes.NestedEnum; import org.junit.Test; import org.junit.runner.RunWith; @@ -55,47 +53,44 @@ public final class CelProtoExtensionsTest { CelCompilerFactory.standardCelCompilerBuilder() .addLibraries(CelExtensions.protos()) .setStandardMacros(CelStandardMacro.STANDARD_MACROS) - .addFileTypes(MessagesProto2Extensions.getDescriptor()) - .addVar( - "msg", StructTypeReference.create("dev.cel.testing.testdata.proto2.Proto2Message")) - .setContainer("dev.cel.testing.testdata.proto2") + .addFileTypes(TestAllTypesExtensions.getDescriptor()) + .addVar("msg", StructTypeReference.create("google.api.expr.test.v1.proto2.TestAllTypes")) + .setContainer("google.api.expr.test.v1.proto2") .build(); private static final CelRuntime CEL_RUNTIME = CelRuntimeFactory.standardCelRuntimeBuilder() - .addFileTypes(MessagesProto2Extensions.getDescriptor()) + .addFileTypes(TestAllTypesExtensions.getDescriptor()) .build(); - private static final Proto2Message PACKAGE_SCOPED_EXT_MSG = - Proto2Message.newBuilder() - .setExtension(MessagesProto2Extensions.int32Ext, 1) + private static final TestAllTypes PACKAGE_SCOPED_EXT_MSG = + TestAllTypes.newBuilder() + .setExtension(TestAllTypesExtensions.int32Ext, 1) .setExtension( - MessagesProto2Extensions.nestedExt, - Proto2Message.newBuilder().setSingleInt32(5).build()) - .setExtension(MessagesProto2Extensions.nestedEnumExt, NestedEnum.BAR) + TestAllTypesExtensions.nestedExt, TestAllTypes.newBuilder().setSingleInt32(5).build()) + .setExtension(TestAllTypesExtensions.nestedEnumExt, NestedEnum.BAR) .setExtension( - MessagesProto2Extensions.repeatedStringHolderExt, + TestAllTypesExtensions.repeatedTestAllTypes, ImmutableList.of( - StringHolder.newBuilder().setS("A").build(), - StringHolder.newBuilder().setS("B").build())) + TestAllTypes.newBuilder().setSingleString("A").build(), + TestAllTypes.newBuilder().setSingleString("B").build())) .build(); - private static final Proto2Message MESSAGE_SCOPED_EXT_MSG = - Proto2Message.newBuilder() + private static final TestAllTypes MESSAGE_SCOPED_EXT_MSG = + TestAllTypes.newBuilder() .setExtension( - Proto2ExtensionScopedMessage.nestedMessageInsideExt, - NestedMessageInsideExtensions.newBuilder().setField("test").build()) + Proto2ExtensionScopedMessage.messageScopedNestedExt, + TestAllTypes.newBuilder().setSingleString("test").build()) .setExtension(Proto2ExtensionScopedMessage.int64Ext, 1L) .build(); @Test - @TestParameters("{expr: 'proto.hasExt(msg, dev.cel.testing.testdata.proto2.int32_ext)'}") - @TestParameters("{expr: 'proto.hasExt(msg, dev.cel.testing.testdata.proto2.nested_ext)'}") - @TestParameters("{expr: 'proto.hasExt(msg, dev.cel.testing.testdata.proto2.nested_enum_ext)'}") + @TestParameters("{expr: 'proto.hasExt(msg, google.api.expr.test.v1.proto2.int32_ext)'}") + @TestParameters("{expr: 'proto.hasExt(msg, google.api.expr.test.v1.proto2.nested_ext)'}") + @TestParameters("{expr: 'proto.hasExt(msg, google.api.expr.test.v1.proto2.nested_enum_ext)'}") @TestParameters( - "{expr: 'proto.hasExt(msg, dev.cel.testing.testdata.proto2.repeated_string_holder_ext)'}") - @TestParameters( - "{expr: '!proto.hasExt(msg, dev.cel.testing.testdata.proto2.test_all_types_ext)'}") + "{expr: 'proto.hasExt(msg, google.api.expr.test.v1.proto2.repeated_test_all_types)'}") + @TestParameters("{expr: '!proto.hasExt(msg, google.api.expr.test.v1.proto2.test_all_types_ext)'}") public void hasExt_packageScoped_success(String expr) throws Exception { CelAbstractSyntaxTree ast = CEL_COMPILER.compile(expr).getAst(); boolean result = @@ -108,16 +103,16 @@ public void hasExt_packageScoped_success(String expr) throws Exception { @Test @TestParameters( "{expr: 'proto.hasExt(msg," - + " dev.cel.testing.testdata.proto2.Proto2ExtensionScopedMessage.nested_message_inside_ext)'}") + + " google.api.expr.test.v1.proto2.Proto2ExtensionScopedMessage.message_scoped_nested_ext)'}") @TestParameters( "{expr: 'proto.hasExt(msg," - + " dev.cel.testing.testdata.proto2.Proto2ExtensionScopedMessage.int64_ext)'}") + + " google.api.expr.test.v1.proto2.Proto2ExtensionScopedMessage.int64_ext)'}") @TestParameters( "{expr: '!proto.hasExt(msg," - + " dev.cel.testing.testdata.proto2.Proto2ExtensionScopedMessage.message_scoped_nested_ext)'}") + + " google.api.expr.test.v1.proto2.Proto2ExtensionScopedMessage.message_scoped_repeated_test_all_types)'}") @TestParameters( "{expr: '!proto.hasExt(msg," - + " dev.cel.testing.testdata.proto2.Proto2ExtensionScopedMessage.string_ext)'}") + + " google.api.expr.test.v1.proto2.Proto2ExtensionScopedMessage.nested_enum_ext)'}") public void hasExt_messageScoped_success(String expr) throws Exception { CelAbstractSyntaxTree ast = CEL_COMPILER.compile(expr).getAst(); boolean result = @@ -128,11 +123,11 @@ public void hasExt_messageScoped_success(String expr) throws Exception { } @Test - @TestParameters("{expr: 'msg.hasExt(''dev.cel.testing.testdata.proto2.int32_ext'', 0)'}") - @TestParameters("{expr: 'dyn(msg).hasExt(''dev.cel.testing.testdata.proto2.int32_ext'', 0)'}") + @TestParameters("{expr: 'msg.hasExt(''google.api.expr.test.v1.proto2.int32_ext'', 0)'}") + @TestParameters("{expr: 'dyn(msg).hasExt(''google.api.expr.test.v1.proto2.int32_ext'', 0)'}") public void hasExt_nonProtoNamespace_success(String expr) throws Exception { StructTypeReference proto2MessageTypeReference = - StructTypeReference.create("dev.cel.testing.testdata.proto2.Proto2Message"); + StructTypeReference.create("google.api.expr.test.v1.proto2.TestAllTypes"); CelCompiler celCompiler = CelCompilerFactory.standardCelCompilerBuilder() .addLibraries(CelExtensions.protos()) @@ -151,9 +146,9 @@ public void hasExt_nonProtoNamespace_success(String expr) throws Exception { .addFunctionBindings( CelFunctionBinding.from( "msg_hasExt", - ImmutableList.of(Proto2Message.class, String.class, Long.class), + ImmutableList.of(TestAllTypes.class, String.class, Long.class), (arg) -> { - Proto2Message msg = (Proto2Message) arg[0]; + TestAllTypes msg = (TestAllTypes) arg[0]; String extensionField = (String) arg[1]; return msg.getAllFields().keySet().stream() .anyMatch(fd -> fd.getFullName().equals(extensionField)); @@ -175,25 +170,25 @@ public void hasExt_undefinedField_throwsException() { CelValidationException.class, () -> CEL_COMPILER - .compile("!proto.hasExt(msg, dev.cel.testing.testdata.proto2.undefined_field)") + .compile("!proto.hasExt(msg, google.api.expr.test.v1.proto2.undefined_field)") .getAst()); assertThat(exception) .hasMessageThat() - .contains("undefined field 'dev.cel.testing.testdata.proto2.undefined_field'"); + .contains("undefined field 'google.api.expr.test.v1.proto2.undefined_field'"); } @Test - @TestParameters("{expr: 'proto.getExt(msg, dev.cel.testing.testdata.proto2.int32_ext) == 1'}") + @TestParameters("{expr: 'proto.getExt(msg, google.api.expr.test.v1.proto2.int32_ext) == 1'}") @TestParameters( - "{expr: 'proto.getExt(msg, dev.cel.testing.testdata.proto2.nested_ext) ==" - + " Proto2Message{single_int32: 5}'}") + "{expr: 'proto.getExt(msg, google.api.expr.test.v1.proto2.nested_ext) ==" + + " TestAllTypes{single_int32: 5}'}") @TestParameters( - "{expr: 'proto.getExt(msg, dev.cel.testing.testdata.proto2.nested_enum_ext) ==" + "{expr: 'proto.getExt(msg, google.api.expr.test.v1.proto2.nested_enum_ext) ==" + " TestAllTypes.NestedEnum.BAR'}") @TestParameters( - "{expr: 'proto.getExt(msg, dev.cel.testing.testdata.proto2.repeated_string_holder_ext) ==" - + " [StringHolder{s: ''A''}, StringHolder{s: ''B''}]'}") + "{expr: 'proto.getExt(msg, google.api.expr.test.v1.proto2.repeated_test_all_types) ==" + + " [TestAllTypes{single_string: ''A''}, TestAllTypes{single_string: ''B''}]'}") public void getExt_packageScoped_success(String expr) throws Exception { CelAbstractSyntaxTree ast = CEL_COMPILER.compile(expr).getAst(); boolean result = @@ -206,11 +201,11 @@ public void getExt_packageScoped_success(String expr) throws Exception { @Test @TestParameters( "{expr: 'proto.getExt(msg," - + " dev.cel.testing.testdata.proto2.Proto2ExtensionScopedMessage.nested_message_inside_ext)" - + " == NestedMessageInsideExtensions{field: ''test''}'}") + + " google.api.expr.test.v1.proto2.Proto2ExtensionScopedMessage.message_scoped_nested_ext)" + + " == TestAllTypes{single_string: ''test''}'}") @TestParameters( "{expr: 'proto.getExt(msg," - + " dev.cel.testing.testdata.proto2.Proto2ExtensionScopedMessage.int64_ext) == 1'}") + + " google.api.expr.test.v1.proto2.Proto2ExtensionScopedMessage.int64_ext) == 1'}") public void getExt_messageScopedSuccess(String expr) throws Exception { CelAbstractSyntaxTree ast = CEL_COMPILER.compile(expr).getAst(); boolean result = @@ -227,21 +222,20 @@ public void getExt_undefinedField_throwsException() { CelValidationException.class, () -> CEL_COMPILER - .compile("!proto.getExt(msg, dev.cel.testing.testdata.proto2.undefined_field)") + .compile("!proto.getExt(msg, google.api.expr.test.v1.proto2.undefined_field)") .getAst()); assertThat(exception) .hasMessageThat() - .contains("undefined field 'dev.cel.testing.testdata.proto2.undefined_field'"); + .contains("undefined field 'google.api.expr.test.v1.proto2.undefined_field'"); } @Test - @TestParameters("{expr: 'msg.getExt(''dev.cel.testing.testdata.proto2.int32_ext'', 0) == 1'}") - @TestParameters( - "{expr: 'dyn(msg).getExt(''dev.cel.testing.testdata.proto2.int32_ext'', 0) == 1'}") + @TestParameters("{expr: 'msg.getExt(''google.api.expr.test.v1.proto2.int32_ext'', 0) == 1'}") + @TestParameters("{expr: 'dyn(msg).getExt(''google.api.expr.test.v1.proto2.int32_ext'', 0) == 1'}") public void getExt_nonProtoNamespace_success(String expr) throws Exception { StructTypeReference proto2MessageTypeReference = - StructTypeReference.create("dev.cel.testing.testdata.proto2.Proto2Message"); + StructTypeReference.create("google.api.expr.test.v1.proto2.TestAllTypes"); CelCompiler celCompiler = CelCompilerFactory.standardCelCompilerBuilder() .addLibraries(CelExtensions.protos()) @@ -260,9 +254,9 @@ public void getExt_nonProtoNamespace_success(String expr) throws Exception { .addFunctionBindings( CelFunctionBinding.from( "msg_getExt", - ImmutableList.of(Proto2Message.class, String.class, Long.class), + ImmutableList.of(TestAllTypes.class, String.class, Long.class), (arg) -> { - Proto2Message msg = (Proto2Message) arg[0]; + TestAllTypes msg = (TestAllTypes) arg[0]; String extensionField = (String) arg[1]; FieldDescriptor extensionDescriptor = msg.getAllFields().keySet().stream() @@ -284,20 +278,20 @@ public void getExt_nonProtoNamespace_success(String expr) throws Exception { @Test public void getExt_onAnyPackedExtensionField_success() throws Exception { ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance(); - MessagesProto2Extensions.registerAllExtensions(extensionRegistry); + TestAllTypesExtensions.registerAllExtensions(extensionRegistry); Cel cel = CelFactory.standardCelBuilder() .addCompilerLibraries(CelExtensions.protos()) - .addFileTypes(MessagesProto2Extensions.getDescriptor()) + .addFileTypes(TestAllTypesExtensions.getDescriptor()) .setExtensionRegistry(extensionRegistry) .addVar( - "msg", StructTypeReference.create("dev.cel.testing.testdata.proto2.Proto2Message")) + "msg", StructTypeReference.create("google.api.expr.test.v1.proto2.TestAllTypes")) .build(); CelAbstractSyntaxTree ast = - cel.compile("proto.getExt(msg, dev.cel.testing.testdata.proto2.int32_ext)").getAst(); + cel.compile("proto.getExt(msg, google.api.expr.test.v1.proto2.int32_ext)").getAst(); Any anyMsg = Any.pack( - Proto2Message.newBuilder().setExtension(MessagesProto2Extensions.int32Ext, 1).build()); + TestAllTypes.newBuilder().setExtension(TestAllTypesExtensions.int32Ext, 1).build()); Long result = (Long) cel.createProgram(ast).eval(ImmutableMap.of("msg", anyMsg)); @@ -317,10 +311,10 @@ private enum ParseErrorTestCase { + " | ...................................................^"), FIELD_INSIDE_PRESENCE_TEST( "proto.getExt(Proto2ExtensionScopedMessage{}," - + " has(dev.cel.testing.testdata.proto2.Proto2ExtensionScopedMessage.int64_ext))", + + " has(google.api.expr.test.v1.proto2.Proto2ExtensionScopedMessage.int64_ext))", "ERROR: :1:49: invalid extension field\n" + " | proto.getExt(Proto2ExtensionScopedMessage{}," - + " has(dev.cel.testing.testdata.proto2.Proto2ExtensionScopedMessage.int64_ext))\n" + + " has(google.api.expr.test.v1.proto2.Proto2ExtensionScopedMessage.int64_ext))\n" + " | ................................................^"); private final String expr; diff --git a/extensions/src/test/java/dev/cel/extensions/CelSetsExtensionsTest.java b/extensions/src/test/java/dev/cel/extensions/CelSetsExtensionsTest.java index 120ac25d6..ef11ff658 100644 --- a/extensions/src/test/java/dev/cel/extensions/CelSetsExtensionsTest.java +++ b/extensions/src/test/java/dev/cel/extensions/CelSetsExtensionsTest.java @@ -17,6 +17,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertThrows; +import com.google.api.expr.test.v1.proto3.TestAllTypesProto.TestAllTypes; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.testing.junit.testparameterinjector.TestParameterInjector; @@ -36,7 +37,6 @@ import dev.cel.runtime.CelRuntime; import dev.cel.runtime.CelRuntime.CelFunctionBinding; import dev.cel.runtime.CelRuntimeFactory; -import dev.cel.testing.testdata.proto3.TestAllTypesProto.TestAllTypes; import java.util.List; import org.junit.Test; import org.junit.runner.RunWith; @@ -49,7 +49,7 @@ public final class CelSetsExtensionsTest { CelCompilerFactory.standardCelCompilerBuilder() .addMessageTypes(TestAllTypes.getDescriptor()) .setOptions(CEL_OPTIONS) - .setContainer("dev.cel.testing.testdata.proto3") + .setContainer("google.api.expr.test.v1.proto3") .addLibraries(CelExtensions.sets(CEL_OPTIONS)) .addVar("list", ListType.create(SimpleType.INT)) .addVar("subList", ListType.create(SimpleType.INT)) diff --git a/optimizer/src/test/java/dev/cel/optimizer/AstMutatorTest.java b/optimizer/src/test/java/dev/cel/optimizer/AstMutatorTest.java index 31cabdb9d..3a3983747 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/AstMutatorTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/AstMutatorTest.java @@ -18,6 +18,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertThrows; +import com.google.api.expr.test.v1.proto3.TestAllTypesProto.TestAllTypes; import com.google.common.collect.ImmutableMap; import com.google.testing.junit.testparameterinjector.TestParameterInjector; import com.google.testing.junit.testparameterinjector.TestParameters; @@ -50,7 +51,6 @@ import dev.cel.parser.CelUnparser; import dev.cel.parser.CelUnparserFactory; import dev.cel.parser.Operator; -import dev.cel.testing.testdata.proto3.TestAllTypesProto.TestAllTypes; import java.util.List; import org.junit.Test; import org.junit.runner.RunWith; @@ -64,7 +64,7 @@ public class AstMutatorTest { .addMessageTypes(TestAllTypes.getDescriptor()) .addCompilerLibraries(CelOptionalLibrary.INSTANCE, CelExtensions.bindings()) .addRuntimeLibraries(CelOptionalLibrary.INSTANCE) - .setContainer("dev.cel.testing.testdata.proto3") + .setContainer("google.api.expr.test.v1.proto3") .addVar("msg", StructTypeReference.create(TestAllTypes.getDescriptor().getFullName())) .addVar("x", SimpleType.INT) .build(); diff --git a/optimizer/src/test/java/dev/cel/optimizer/BUILD.bazel b/optimizer/src/test/java/dev/cel/optimizer/BUILD.bazel index 83ccd8a3c..322b642a7 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/BUILD.bazel +++ b/optimizer/src/test/java/dev/cel/optimizer/BUILD.bazel @@ -17,7 +17,6 @@ java_library( "//common/ast:mutable_expr", "//common/navigation", "//common/navigation:mutable_navigation", - "//common/resources/testdata/proto3:test_all_types_java_proto", "//common/types", "//compiler", "//extensions", @@ -33,6 +32,7 @@ java_library( "//parser:operator", "//parser:unparser", "//runtime", + "@cel_spec//proto/test/v1/proto3:test_all_types_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_testparameterinjector_test_parameter_injector", "@maven//:junit_junit", diff --git a/optimizer/src/test/java/dev/cel/optimizer/optimizers/BUILD.bazel b/optimizer/src/test/java/dev/cel/optimizer/optimizers/BUILD.bazel index e1ac3bd52..d988c4e56 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/optimizers/BUILD.bazel +++ b/optimizer/src/test/java/dev/cel/optimizer/optimizers/BUILD.bazel @@ -16,7 +16,6 @@ java_library( "//common:options", "//common/ast", "//common/navigation:mutable_navigation", - "//common/resources/testdata/proto3:test_all_types_java_proto", "//common/types", "//extensions", "//extensions:optional_library", @@ -33,6 +32,7 @@ java_library( "@maven//:junit_junit", "@maven//:com_google_testparameterinjector_test_parameter_injector", "//:java_truth", + "@cel_spec//proto/test/v1/proto3:test_all_types_java_proto", "@maven//:com_google_guava_guava", ], ) diff --git a/optimizer/src/test/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizerTest.java b/optimizer/src/test/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizerTest.java index 96040b508..b416eb2d5 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizerTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizerTest.java @@ -17,6 +17,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertThrows; +import com.google.api.expr.test.v1.proto3.TestAllTypesProto.TestAllTypes; import com.google.common.collect.ImmutableList; import com.google.testing.junit.testparameterinjector.TestParameterInjector; import com.google.testing.junit.testparameterinjector.TestParameters; @@ -39,7 +40,6 @@ import dev.cel.parser.CelUnparser; import dev.cel.parser.CelUnparserFactory; import dev.cel.runtime.CelRuntime.CelFunctionBinding; -import dev.cel.testing.testdata.proto3.TestAllTypesProto.TestAllTypes; import org.junit.Test; import org.junit.runner.RunWith; @@ -58,7 +58,7 @@ public class ConstantFoldingOptimizerTest { .addFunctionBindings( CelFunctionBinding.from("get_true_overload", ImmutableList.of(), unused -> true)) .addMessageTypes(TestAllTypes.getDescriptor()) - .setContainer("dev.cel.testing.testdata.proto3") + .setContainer("google.api.expr.test.v1.proto3") .addCompilerLibraries( CelExtensions.bindings(), CelOptionalLibrary.INSTANCE, diff --git a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerBaselineTest.java b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerBaselineTest.java index e2035be1b..9e67bda85 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerBaselineTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerBaselineTest.java @@ -17,6 +17,8 @@ import static com.google.common.truth.Truth.assertThat; import static dev.cel.common.CelOverloadDecl.newGlobalOverload; +import com.google.api.expr.test.v1.proto3.TestAllTypesProto.NestedTestAllTypes; +import com.google.api.expr.test.v1.proto3.TestAllTypesProto.TestAllTypes; import com.google.common.base.Ascii; import com.google.common.collect.ImmutableMap; import com.google.testing.junit.testparameterinjector.TestParameter; @@ -41,8 +43,6 @@ import dev.cel.parser.CelUnparserFactory; import dev.cel.runtime.CelRuntime.CelFunctionBinding; import dev.cel.testing.BaselineTestCase; -import dev.cel.testing.testdata.proto3.TestAllTypesProto.NestedTestAllTypes; -import dev.cel.testing.testdata.proto3.TestAllTypesProto.TestAllTypes; import java.util.Optional; import org.junit.Before; import org.junit.Test; @@ -320,7 +320,7 @@ private void runLargeTestCases(CelOptimizer celOptimizer) throws Exception { private static CelBuilder newCelBuilder() { return CelFactory.standardCelBuilder() .addMessageTypes(TestAllTypes.getDescriptor()) - .setContainer("dev.cel.testing.testdata.proto3") + .setContainer("google.api.expr.test.v1.proto3") .setStandardMacros(CelStandardMacro.STANDARD_MACROS) .setOptions( CelOptions.current().enableTimestampEpoch(true).populateMacroCalls(true).build()) diff --git a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java index 3febca67c..2f196b292 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java @@ -18,6 +18,7 @@ import static dev.cel.common.CelOverloadDecl.newGlobalOverload; import static org.junit.Assert.assertThrows; +import com.google.api.expr.test.v1.proto3.TestAllTypesProto.TestAllTypes; import com.google.common.base.VerifyException; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; @@ -57,7 +58,6 @@ import dev.cel.runtime.CelRuntime; import dev.cel.runtime.CelRuntime.CelFunctionBinding; import dev.cel.runtime.CelRuntimeFactory; -import dev.cel.testing.testdata.proto3.TestAllTypesProto.TestAllTypes; import java.util.Optional; import java.util.concurrent.atomic.AtomicInteger; import org.junit.Test; diff --git a/policy/src/test/java/dev/cel/policy/BUILD.bazel b/policy/src/test/java/dev/cel/policy/BUILD.bazel index 4ae85cb55..dff3e974d 100644 --- a/policy/src/test/java/dev/cel/policy/BUILD.bazel +++ b/policy/src/test/java/dev/cel/policy/BUILD.bazel @@ -15,7 +15,6 @@ java_library( "//common", "//common:options", "//common/internal", - "//common/resources/testdata/proto3:test_all_types_java_proto", "//compiler", "//extensions:optional_library", "//parser", @@ -32,6 +31,7 @@ java_library( "//policy:validation_exception", "//policy:value_string", "//runtime", + "@cel_spec//proto/test/v1/proto3:test_all_types_java_proto", "@com_google_googleapis//google/rpc/context:attribute_context_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_testparameterinjector_test_parameter_injector", diff --git a/policy/src/test/java/dev/cel/policy/CelPolicyCompilerImplTest.java b/policy/src/test/java/dev/cel/policy/CelPolicyCompilerImplTest.java index bf435f90a..9ff04cfe4 100644 --- a/policy/src/test/java/dev/cel/policy/CelPolicyCompilerImplTest.java +++ b/policy/src/test/java/dev/cel/policy/CelPolicyCompilerImplTest.java @@ -19,6 +19,7 @@ import static dev.cel.policy.PolicyTestHelper.readFromYaml; import static org.junit.Assert.assertThrows; +import com.google.api.expr.test.v1.proto3.TestAllTypesProto.TestAllTypes; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.testing.junit.testparameterinjector.TestParameter; @@ -39,7 +40,6 @@ import dev.cel.policy.PolicyTestHelper.PolicyTestSuite.PolicyTestSection.PolicyTestCase.PolicyTestInput; import dev.cel.policy.PolicyTestHelper.TestYamlPolicy; import dev.cel.runtime.CelRuntime.CelFunctionBinding; -import dev.cel.testing.testdata.proto3.TestAllTypesProto.TestAllTypes; import java.io.IOException; import java.util.Map; import java.util.Optional; diff --git a/policy/src/test/resources/pb/config.yaml b/policy/src/test/resources/pb/config.yaml index d412ec012..dc38a6a23 100644 --- a/policy/src/test/resources/pb/config.yaml +++ b/policy/src/test/resources/pb/config.yaml @@ -13,11 +13,11 @@ # limitations under the License. name: "pb" -container: "dev.cel.testing.testdata.proto3" +container: "google.api.expr.test.v1.proto3" extensions: - name: "strings" version: 2 variables: - name: "spec" type: - type_name: "dev.cel.testing.testdata.proto3.TestAllTypes" + type_name: "google.api.expr.test.v1.proto3.TestAllTypes" diff --git a/runtime/src/test/java/dev/cel/runtime/ActivationTest.java b/runtime/src/test/java/dev/cel/runtime/ActivationTest.java index 04bc1cfb2..003a72e05 100644 --- a/runtime/src/test/java/dev/cel/runtime/ActivationTest.java +++ b/runtime/src/test/java/dev/cel/runtime/ActivationTest.java @@ -16,12 +16,12 @@ import static com.google.common.truth.Truth.assertThat; +import com.google.api.expr.test.v1.proto3.TestAllTypesProto.NestedTestAllTypes; +import com.google.api.expr.test.v1.proto3.TestAllTypesProto.TestAllTypes; +import com.google.api.expr.test.v1.proto3.TestAllTypesProto.TestAllTypes.NestedMessage; import com.google.common.primitives.UnsignedLong; import com.google.protobuf.NullValue; import dev.cel.common.CelOptions; -import dev.cel.testing.testdata.proto3.TestAllTypesProto.NestedTestAllTypes; -import dev.cel.testing.testdata.proto3.TestAllTypesProto.TestAllTypes; -import dev.cel.testing.testdata.proto3.TestAllTypesProto.TestAllTypes.NestedMessage; import java.util.HashMap; import java.util.List; import java.util.Map; diff --git a/runtime/src/test/java/dev/cel/runtime/BUILD.bazel b/runtime/src/test/java/dev/cel/runtime/BUILD.bazel index dd188ea28..56e66137c 100644 --- a/runtime/src/test/java/dev/cel/runtime/BUILD.bazel +++ b/runtime/src/test/java/dev/cel/runtime/BUILD.bazel @@ -28,9 +28,6 @@ java_library( "//common/internal:dynamic_proto", "//common/internal:proto_message_factory", "//common/internal:well_known_proto", - "//common/resources/testdata/proto2:messages_extensions_proto2_java_proto", - "//common/resources/testdata/proto2:messages_proto2_java_proto", - "//common/resources/testdata/proto3:test_all_types_java_proto", "//common/types", "//common/types:cel_v1alpha1_types", "//compiler", @@ -44,6 +41,8 @@ java_library( "//runtime:unknown_attributes", "//runtime:unknown_options", "@@protobuf~//java/core", + "@cel_spec//proto/test/v1/proto2:test_all_types_java_proto", + "@cel_spec//proto/test/v1/proto3:test_all_types_java_proto", "@com_google_googleapis//google/api/expr/v1alpha1:expr_java_proto", "@com_google_googleapis//google/rpc/context:attribute_context_java_proto", "@maven//:com_google_guava_guava", diff --git a/runtime/src/test/java/dev/cel/runtime/CelRuntimeLegacyImplTest.java b/runtime/src/test/java/dev/cel/runtime/CelRuntimeLegacyImplTest.java index 2ce5e4d0b..5aecde577 100644 --- a/runtime/src/test/java/dev/cel/runtime/CelRuntimeLegacyImplTest.java +++ b/runtime/src/test/java/dev/cel/runtime/CelRuntimeLegacyImplTest.java @@ -16,11 +16,11 @@ import static com.google.common.truth.Truth.assertThat; +import com.google.api.expr.test.v1.proto3.TestAllTypesProto.TestAllTypes; import dev.cel.common.CelException; import dev.cel.compiler.CelCompiler; import dev.cel.compiler.CelCompilerFactory; import dev.cel.runtime.CelRuntime.CelFunctionBinding; -import dev.cel.testing.testdata.proto3.TestAllTypesProto.TestAllTypes; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; @@ -75,7 +75,7 @@ public void toRuntimeBuilder_collectionProperties_copied() { assertThat(newRuntimeBuilder.getFunctionBindings()).hasSize(1); assertThat(newRuntimeBuilder.getRuntimeLibraries().build()).hasSize(1); - assertThat(newRuntimeBuilder.getFileTypes().build()).hasSize(6); + assertThat(newRuntimeBuilder.getFileTypes().build()).hasSize(8); } @Test diff --git a/runtime/src/test/java/dev/cel/runtime/CelRuntimeTest.java b/runtime/src/test/java/dev/cel/runtime/CelRuntimeTest.java index fd4de8179..867a8ea06 100644 --- a/runtime/src/test/java/dev/cel/runtime/CelRuntimeTest.java +++ b/runtime/src/test/java/dev/cel/runtime/CelRuntimeTest.java @@ -17,6 +17,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertThrows; +import com.google.api.expr.test.v1.proto3.TestAllTypesProto.TestAllTypes; import com.google.api.expr.v1alpha1.Constant; import com.google.api.expr.v1alpha1.Expr; import com.google.api.expr.v1alpha1.Type.PrimitiveType; @@ -47,7 +48,6 @@ import dev.cel.compiler.CelCompilerFactory; import dev.cel.parser.CelStandardMacro; import dev.cel.parser.CelUnparserFactory; -import dev.cel.testing.testdata.proto3.TestAllTypesProto.TestAllTypes; import java.util.List; import java.util.Map; import java.util.Optional; @@ -279,7 +279,7 @@ public void trace_select() throws Exception { Cel cel = CelFactory.standardCelBuilder() .addMessageTypes(TestAllTypes.getDescriptor()) - .setContainer("dev.cel.testing.testdata.proto3") + .setContainer("google.api.expr.test.v1.proto3") .build(); CelAbstractSyntaxTree ast = cel.compile("TestAllTypes{single_int64: 3}.single_int64").getAst(); @@ -298,7 +298,7 @@ public void trace_struct() throws Exception { Cel cel = CelFactory.standardCelBuilder() .addMessageTypes(TestAllTypes.getDescriptor()) - .setContainer("dev.cel.testing.testdata.proto3") + .setContainer("google.api.expr.test.v1.proto3") .build(); CelAbstractSyntaxTree ast = cel.compile("TestAllTypes{}").getAst(); diff --git a/runtime/src/test/java/dev/cel/runtime/DescriptorMessageProviderTest.java b/runtime/src/test/java/dev/cel/runtime/DescriptorMessageProviderTest.java index afe7ca4c0..c4622a7ab 100644 --- a/runtime/src/test/java/dev/cel/runtime/DescriptorMessageProviderTest.java +++ b/runtime/src/test/java/dev/cel/runtime/DescriptorMessageProviderTest.java @@ -17,6 +17,10 @@ import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; +import com.google.api.expr.test.v1.proto2.TestAllTypesExtensions; +import com.google.api.expr.test.v1.proto2.TestAllTypesProto; +import com.google.api.expr.test.v1.proto2.TestAllTypesProto.TestAllTypes.NestedGroup; +import com.google.api.expr.test.v1.proto3.TestAllTypesProto.TestAllTypes; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.protobuf.Any; @@ -38,11 +42,6 @@ // CEL-Internal-3 import dev.cel.common.internal.ProtoMessageFactory; import dev.cel.common.internal.WellKnownProto; -import dev.cel.testing.testdata.proto2.MessagesProto2; -import dev.cel.testing.testdata.proto2.MessagesProto2Extensions; -import dev.cel.testing.testdata.proto2.Proto2Message; -import dev.cel.testing.testdata.proto2.Proto2Message.NestedGroup; -import dev.cel.testing.testdata.proto3.TestAllTypesProto.TestAllTypes; import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -87,8 +86,10 @@ public void createMessageDynamic_success() { @Test public void createNestedGroup_success() throws Exception { - String groupType = "dev.cel.testing.testdata.proto2.Proto2Message.NestedGroup"; - provider = DynamicMessageFactory.typeProvider(ImmutableList.of(NestedGroup.getDescriptor())); + String groupType = "google.api.expr.test.v1.proto2.TestAllTypes.NestedGroup"; + provider = + DynamicMessageFactory.typeProvider( + ImmutableList.of(TestAllTypesProto.TestAllTypes.NestedGroup.getDescriptor())); Message message = (Message) provider.createMessage( @@ -173,7 +174,7 @@ public void selectField_nonProtoObjectError() { public void selectField_extensionUsingDynamicTypes() { CelDescriptors celDescriptors = CelDescriptorUtil.getAllDescriptorsFromFileDescriptor( - ImmutableList.of(MessagesProto2Extensions.getDescriptor())); + ImmutableList.of(TestAllTypesExtensions.getDescriptor())); CelDescriptorPool pool = DefaultDescriptorPool.create(celDescriptors); provider = @@ -183,10 +184,10 @@ public void selectField_extensionUsingDynamicTypes() { long result = (long) provider.selectField( - Proto2Message.newBuilder() - .setExtension(MessagesProto2Extensions.int32Ext, 10) + TestAllTypesProto.TestAllTypes.newBuilder() + .setExtension(TestAllTypesExtensions.int32Ext, 10) .build(), - MessagesProto2.getDescriptor().getPackage() + ".int32_ext"); + TestAllTypesProto.getDescriptor().getPackage() + ".int32_ext"); assertThat(result).isEqualTo(10); } diff --git a/runtime/src/test/java/dev/cel/runtime/MessageFactoryTest.java b/runtime/src/test/java/dev/cel/runtime/MessageFactoryTest.java index 701a1e9c0..b19434ff1 100644 --- a/runtime/src/test/java/dev/cel/runtime/MessageFactoryTest.java +++ b/runtime/src/test/java/dev/cel/runtime/MessageFactoryTest.java @@ -16,10 +16,10 @@ import static com.google.common.truth.Truth.assertThat; +import com.google.api.expr.test.v1.proto3.TestAllTypesProto.TestAllTypes; import com.google.common.collect.ImmutableList; import com.google.protobuf.Message; import dev.cel.runtime.MessageFactory.CombinedMessageFactory; -import dev.cel.testing.testdata.proto3.TestAllTypesProto.TestAllTypes; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; diff --git a/runtime/src/test/java/dev/cel/runtime/async/BUILD.bazel b/runtime/src/test/java/dev/cel/runtime/async/BUILD.bazel index 599a76835..98a575c2e 100644 --- a/runtime/src/test/java/dev/cel/runtime/async/BUILD.bazel +++ b/runtime/src/test/java/dev/cel/runtime/async/BUILD.bazel @@ -13,7 +13,6 @@ java_library( "//bundle:cel", "//common", "//common:options", - "//common/resources/testdata/proto3:test_all_types_java_proto", "//common/testing", "//common/types", "//runtime", @@ -21,6 +20,7 @@ java_library( "//runtime:unknown_options", "//runtime/async", "@cel_spec//proto/cel/expr:expr_java_proto", + "@cel_spec//proto/test/v1/proto3:test_all_types_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_testparameterinjector_test_parameter_injector", "@maven//:junit_junit", diff --git a/runtime/src/test/java/dev/cel/runtime/async/CelAsyncRuntimeImplTest.java b/runtime/src/test/java/dev/cel/runtime/async/CelAsyncRuntimeImplTest.java index 4eebb499b..fc9fcc3e4 100644 --- a/runtime/src/test/java/dev/cel/runtime/async/CelAsyncRuntimeImplTest.java +++ b/runtime/src/test/java/dev/cel/runtime/async/CelAsyncRuntimeImplTest.java @@ -23,6 +23,7 @@ import dev.cel.expr.Type; import dev.cel.expr.Type.ListType; import dev.cel.expr.Type.PrimitiveType; +import com.google.api.expr.test.v1.proto3.TestAllTypesProto.TestAllTypes; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.SettableFuture; import com.google.testing.junit.testparameterinjector.TestParameter; @@ -38,7 +39,6 @@ import dev.cel.runtime.CelEvaluationException; import dev.cel.runtime.UnknownContext; import dev.cel.runtime.async.CelAsyncRuntime.AsyncProgram; -import dev.cel.testing.testdata.proto3.TestAllTypesProto.TestAllTypes; import java.time.Duration; import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; diff --git a/runtime/src/test/resources/dynamicMessage_adapted.baseline b/runtime/src/test/resources/dynamicMessage_adapted.baseline index 21751184b..d4e7b12b2 100644 --- a/runtime/src/test/resources/dynamicMessage_adapted.baseline +++ b/runtime/src/test/resources/dynamicMessage_adapted.baseline @@ -1,10 +1,10 @@ Source: msg.single_any declare msg { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {msg=single_any { - type_url: "type.googleapis.com/dev.cel.testing.testdata.proto3.TestAllTypes.NestedMessage" + type_url: "type.googleapis.com/google.api.expr.test.v1.proto3.TestAllTypes.NestedMessage" value: "\b*" } single_duration { @@ -53,7 +53,7 @@ single_bool_wrapper { single_bytes_wrapper { value: "hi" } -single_list_value { +list_value { values { string_value: "d" } @@ -64,11 +64,11 @@ result: bb: 42 Source: msg.single_bool_wrapper declare msg { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {msg=single_any { - type_url: "type.googleapis.com/dev.cel.testing.testdata.proto3.TestAllTypes.NestedMessage" + type_url: "type.googleapis.com/google.api.expr.test.v1.proto3.TestAllTypes.NestedMessage" value: "\b*" } single_duration { @@ -117,7 +117,7 @@ single_bool_wrapper { single_bytes_wrapper { value: "hi" } -single_list_value { +list_value { values { string_value: "d" } @@ -127,11 +127,11 @@ result: true Source: msg.single_bytes_wrapper declare msg { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {msg=single_any { - type_url: "type.googleapis.com/dev.cel.testing.testdata.proto3.TestAllTypes.NestedMessage" + type_url: "type.googleapis.com/google.api.expr.test.v1.proto3.TestAllTypes.NestedMessage" value: "\b*" } single_duration { @@ -180,7 +180,7 @@ single_bool_wrapper { single_bytes_wrapper { value: "hi" } -single_list_value { +list_value { values { string_value: "d" } @@ -190,11 +190,11 @@ result: hi Source: msg.single_double_wrapper declare msg { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {msg=single_any { - type_url: "type.googleapis.com/dev.cel.testing.testdata.proto3.TestAllTypes.NestedMessage" + type_url: "type.googleapis.com/google.api.expr.test.v1.proto3.TestAllTypes.NestedMessage" value: "\b*" } single_duration { @@ -243,7 +243,7 @@ single_bool_wrapper { single_bytes_wrapper { value: "hi" } -single_list_value { +list_value { values { string_value: "d" } @@ -253,11 +253,11 @@ result: -3.0 Source: msg.single_float_wrapper declare msg { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {msg=single_any { - type_url: "type.googleapis.com/dev.cel.testing.testdata.proto3.TestAllTypes.NestedMessage" + type_url: "type.googleapis.com/google.api.expr.test.v1.proto3.TestAllTypes.NestedMessage" value: "\b*" } single_duration { @@ -306,7 +306,7 @@ single_bool_wrapper { single_bytes_wrapper { value: "hi" } -single_list_value { +list_value { values { string_value: "d" } @@ -316,11 +316,11 @@ result: 1.5 Source: msg.single_int32_wrapper declare msg { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {msg=single_any { - type_url: "type.googleapis.com/dev.cel.testing.testdata.proto3.TestAllTypes.NestedMessage" + type_url: "type.googleapis.com/google.api.expr.test.v1.proto3.TestAllTypes.NestedMessage" value: "\b*" } single_duration { @@ -369,7 +369,7 @@ single_bool_wrapper { single_bytes_wrapper { value: "hi" } -single_list_value { +list_value { values { string_value: "d" } @@ -379,11 +379,11 @@ result: -12 Source: msg.single_int64_wrapper declare msg { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {msg=single_any { - type_url: "type.googleapis.com/dev.cel.testing.testdata.proto3.TestAllTypes.NestedMessage" + type_url: "type.googleapis.com/google.api.expr.test.v1.proto3.TestAllTypes.NestedMessage" value: "\b*" } single_duration { @@ -432,7 +432,7 @@ single_bool_wrapper { single_bytes_wrapper { value: "hi" } -single_list_value { +list_value { values { string_value: "d" } @@ -442,11 +442,11 @@ result: -34 Source: msg.single_string_wrapper declare msg { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {msg=single_any { - type_url: "type.googleapis.com/dev.cel.testing.testdata.proto3.TestAllTypes.NestedMessage" + type_url: "type.googleapis.com/google.api.expr.test.v1.proto3.TestAllTypes.NestedMessage" value: "\b*" } single_duration { @@ -495,7 +495,7 @@ single_bool_wrapper { single_bytes_wrapper { value: "hi" } -single_list_value { +list_value { values { string_value: "d" } @@ -505,11 +505,11 @@ result: hello Source: msg.single_uint32_wrapper declare msg { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {msg=single_any { - type_url: "type.googleapis.com/dev.cel.testing.testdata.proto3.TestAllTypes.NestedMessage" + type_url: "type.googleapis.com/google.api.expr.test.v1.proto3.TestAllTypes.NestedMessage" value: "\b*" } single_duration { @@ -558,7 +558,7 @@ single_bool_wrapper { single_bytes_wrapper { value: "hi" } -single_list_value { +list_value { values { string_value: "d" } @@ -568,11 +568,11 @@ result: 12 Source: msg.single_uint64_wrapper declare msg { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {msg=single_any { - type_url: "type.googleapis.com/dev.cel.testing.testdata.proto3.TestAllTypes.NestedMessage" + type_url: "type.googleapis.com/google.api.expr.test.v1.proto3.TestAllTypes.NestedMessage" value: "\b*" } single_duration { @@ -621,7 +621,7 @@ single_bool_wrapper { single_bytes_wrapper { value: "hi" } -single_list_value { +list_value { values { string_value: "d" } @@ -631,11 +631,11 @@ result: 34 Source: msg.single_duration declare msg { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {msg=single_any { - type_url: "type.googleapis.com/dev.cel.testing.testdata.proto3.TestAllTypes.NestedMessage" + type_url: "type.googleapis.com/google.api.expr.test.v1.proto3.TestAllTypes.NestedMessage" value: "\b*" } single_duration { @@ -684,7 +684,7 @@ single_bool_wrapper { single_bytes_wrapper { value: "hi" } -single_list_value { +list_value { values { string_value: "d" } @@ -696,11 +696,11 @@ nanos: 20 Source: msg.single_timestamp declare msg { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {msg=single_any { - type_url: "type.googleapis.com/dev.cel.testing.testdata.proto3.TestAllTypes.NestedMessage" + type_url: "type.googleapis.com/google.api.expr.test.v1.proto3.TestAllTypes.NestedMessage" value: "\b*" } single_duration { @@ -749,7 +749,7 @@ single_bool_wrapper { single_bytes_wrapper { value: "hi" } -single_list_value { +list_value { values { string_value: "d" } @@ -761,11 +761,11 @@ nanos: 200 Source: msg.single_value declare msg { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {msg=single_any { - type_url: "type.googleapis.com/dev.cel.testing.testdata.proto3.TestAllTypes.NestedMessage" + type_url: "type.googleapis.com/google.api.expr.test.v1.proto3.TestAllTypes.NestedMessage" value: "\b*" } single_duration { @@ -814,7 +814,7 @@ single_bool_wrapper { single_bytes_wrapper { value: "hi" } -single_list_value { +list_value { values { string_value: "d" } @@ -824,11 +824,11 @@ result: a Source: msg.single_struct declare msg { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {msg=single_any { - type_url: "type.googleapis.com/dev.cel.testing.testdata.proto3.TestAllTypes.NestedMessage" + type_url: "type.googleapis.com/google.api.expr.test.v1.proto3.TestAllTypes.NestedMessage" value: "\b*" } single_duration { @@ -877,7 +877,7 @@ single_bool_wrapper { single_bytes_wrapper { value: "hi" } -single_list_value { +list_value { values { string_value: "d" } @@ -885,13 +885,13 @@ single_list_value { } result: {b=c} -Source: msg.single_list_value +Source: msg.list_value declare msg { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {msg=single_any { - type_url: "type.googleapis.com/dev.cel.testing.testdata.proto3.TestAllTypes.NestedMessage" + type_url: "type.googleapis.com/google.api.expr.test.v1.proto3.TestAllTypes.NestedMessage" value: "\b*" } single_duration { @@ -940,7 +940,7 @@ single_bool_wrapper { single_bytes_wrapper { value: "hi" } -single_list_value { +list_value { values { string_value: "d" } diff --git a/runtime/src/test/resources/dynamicMessage_dynamicDescriptor.baseline b/runtime/src/test/resources/dynamicMessage_dynamicDescriptor.baseline index 6de5a507d..5d30b1fec 100644 --- a/runtime/src/test/resources/dynamicMessage_dynamicDescriptor.baseline +++ b/runtime/src/test/resources/dynamicMessage_dynamicDescriptor.baseline @@ -108,10 +108,10 @@ result: seconds: 100 Source: TestAllTypes { single_any: any_packed_test_msg }.single_any declare any_packed_test_msg { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> -bindings: {any_packed_test_msg=type_url: "type.googleapis.com/dev.cel.testing.testdata.proto3.TestAllTypes" +bindings: {any_packed_test_msg=type_url: "type.googleapis.com/google.api.expr.test.v1.proto3.TestAllTypes" value: "r\005hello" } result: single_string: "hello" @@ -119,10 +119,10 @@ result: single_string: "hello" Source: dynamic_msg declare any_packed_test_msg { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare test_msg { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare dynamic_msg { value dev.cel.testing.testdata.serialized.proto3.TestAllTypes @@ -141,10 +141,10 @@ result: map_string_string { Source: dynamic_msg.map_string_string declare any_packed_test_msg { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare test_msg { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare dynamic_msg { value dev.cel.testing.testdata.serialized.proto3.TestAllTypes @@ -159,10 +159,10 @@ result: {foo=bar} Source: dynamic_msg.map_string_string['foo'] declare any_packed_test_msg { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare test_msg { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare dynamic_msg { value dev.cel.testing.testdata.serialized.proto3.TestAllTypes @@ -177,16 +177,16 @@ result: bar Source: f_msg(dynamic_msg) declare any_packed_test_msg { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare test_msg { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare dynamic_msg { value dev.cel.testing.testdata.serialized.proto3.TestAllTypes } declare f_msg { - function f_msg_generated (dev.cel.testing.testdata.proto3.TestAllTypes) -> bool + function f_msg_generated (google.api.expr.test.v1.proto3.TestAllTypes) -> bool function f_msg_dynamic (dev.cel.testing.testdata.serialized.proto3.TestAllTypes) -> bool } =====> @@ -200,16 +200,16 @@ result: true Source: f_msg(test_msg) declare any_packed_test_msg { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare test_msg { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare dynamic_msg { value dev.cel.testing.testdata.serialized.proto3.TestAllTypes } declare f_msg { - function f_msg_generated (dev.cel.testing.testdata.proto3.TestAllTypes) -> bool + function f_msg_generated (google.api.expr.test.v1.proto3.TestAllTypes) -> bool function f_msg_dynamic (dev.cel.testing.testdata.serialized.proto3.TestAllTypes) -> bool } =====> diff --git a/runtime/src/test/resources/extensionManipulation.baseline b/runtime/src/test/resources/extensionManipulation.baseline index 5c64f9bf8..50f7897e0 100644 --- a/runtime/src/test/resources/extensionManipulation.baseline +++ b/runtime/src/test/resources/extensionManipulation.baseline @@ -5,60 +5,60 @@ Source: [y.hasI(), y.getI() == 200, !n.hasI(), n.getI() == 0, y.hasN(), y.getN().getI() == 0, !y.getN().hasN(), y.getN().getN().getI() == 0, !n.hasN(), n.assignN(y).getN().hasN(), !n.clearN().hasN(), !y.clearN().hasN(), - n.getR() == [], y.getR().map(h, h.s) == ["alpha", "beta"], - n.assignR(["a", "b"].map(s, StringHolder{s:s})).getR().map(h, h.s) == ["a", "b"], + n.getR() == [], y.getR().map(h, h.single_string) == ["alpha", "beta"], + n.assignR(["a", "b"].map(s, TestAllTypes{single_string:s})).getR().map(h, h.single_string) == ["a", "b"], y.clearR().getR() == []] declare y { - value dev.cel.testing.testdata.proto2.Proto2Message + value google.api.expr.test.v1.proto3.TestAllTypes } declare n { - value dev.cel.testing.testdata.proto2.Proto2Message + value google.api.expr.test.v1.proto3.TestAllTypes } declare getI { - function getI dev.cel.testing.testdata.proto2.Proto2Message.() -> int + function getI google.api.expr.test.v1.proto3.TestAllTypes.() -> int } declare hasI { - function hasI dev.cel.testing.testdata.proto2.Proto2Message.() -> bool + function hasI google.api.expr.test.v1.proto3.TestAllTypes.() -> bool } declare assignI { - function assignI dev.cel.testing.testdata.proto2.Proto2Message.(int) -> dev.cel.testing.testdata.proto2.Proto2Message + function assignI google.api.expr.test.v1.proto3.TestAllTypes.(int) -> google.api.expr.test.v1.proto3.TestAllTypes } declare clearI { - function clearI dev.cel.testing.testdata.proto2.Proto2Message.() -> dev.cel.testing.testdata.proto2.Proto2Message + function clearI google.api.expr.test.v1.proto3.TestAllTypes.() -> google.api.expr.test.v1.proto3.TestAllTypes } declare getN { - function getN dev.cel.testing.testdata.proto2.Proto2Message.() -> dev.cel.testing.testdata.proto2.Proto2Message + function getN google.api.expr.test.v1.proto3.TestAllTypes.() -> google.api.expr.test.v1.proto3.TestAllTypes } declare hasN { - function hasN dev.cel.testing.testdata.proto2.Proto2Message.() -> bool + function hasN google.api.expr.test.v1.proto3.TestAllTypes.() -> bool } declare assignN { - function assignN dev.cel.testing.testdata.proto2.Proto2Message.(dev.cel.testing.testdata.proto2.Proto2Message) -> dev.cel.testing.testdata.proto2.Proto2Message + function assignN google.api.expr.test.v1.proto3.TestAllTypes.(google.api.expr.test.v1.proto3.TestAllTypes) -> google.api.expr.test.v1.proto3.TestAllTypes } declare clearN { - function clearN dev.cel.testing.testdata.proto2.Proto2Message.() -> dev.cel.testing.testdata.proto2.Proto2Message + function clearN google.api.expr.test.v1.proto3.TestAllTypes.() -> google.api.expr.test.v1.proto3.TestAllTypes } declare getR { - function getR dev.cel.testing.testdata.proto2.Proto2Message.() -> list(dev.cel.testing.testdata.proto2.StringHolder) + function getR google.api.expr.test.v1.proto3.TestAllTypes.() -> list(google.api.expr.test.v1.proto2.TestAllTypes) } declare assignR { - function assignR dev.cel.testing.testdata.proto2.Proto2Message.(list(dev.cel.testing.testdata.proto2.StringHolder)) -> dev.cel.testing.testdata.proto2.Proto2Message + function assignR google.api.expr.test.v1.proto3.TestAllTypes.(list(google.api.expr.test.v1.proto2.TestAllTypes)) -> google.api.expr.test.v1.proto3.TestAllTypes } declare clearR { - function clearR dev.cel.testing.testdata.proto2.Proto2Message.() -> dev.cel.testing.testdata.proto2.Proto2Message + function clearR google.api.expr.test.v1.proto3.TestAllTypes.() -> google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {y=single_int32: 100 -[dev.cel.testing.testdata.proto2.nested_ext] { +[google.api.expr.test.v1.proto2.int32_ext]: 200 +[google.api.expr.test.v1.proto2.nested_ext] { single_int32: 50 } -[dev.cel.testing.testdata.proto2.int32_ext]: 200 -[dev.cel.testing.testdata.proto2.repeated_string_holder_ext] { - s: "alpha" +[google.api.expr.test.v1.proto2.repeated_test_all_types] { + single_string: "alpha" } -[dev.cel.testing.testdata.proto2.repeated_string_holder_ext] { - s: "beta" +[google.api.expr.test.v1.proto2.repeated_test_all_types] { + single_string: "alpha" } , n=single_int32: 50 } -result: [true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true] +result: [true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, false, true, true] diff --git a/runtime/src/test/resources/fieldManipulation.baseline b/runtime/src/test/resources/fieldManipulation.baseline index acacef93f..7734ee7f4 100644 --- a/runtime/src/test/resources/fieldManipulation.baseline +++ b/runtime/src/test/resources/fieldManipulation.baseline @@ -1,18 +1,18 @@ Source: TestAllTypes{single_bool: true}.assignSingleInt64(1) == TestAllTypes{single_bool: true, single_int64: 1} declare assignSingleInt64 { - function assignSingleInt64 dev.cel.testing.testdata.proto3.TestAllTypes.(int) -> dev.cel.testing.testdata.proto3.TestAllTypes + function assignSingleInt64 google.api.expr.test.v1.proto3.TestAllTypes.(int) -> google.api.expr.test.v1.proto3.TestAllTypes } declare assignRepeatedInt64 { - function assignRepeatedInt64 dev.cel.testing.testdata.proto3.TestAllTypes.(list(int)) -> dev.cel.testing.testdata.proto3.TestAllTypes + function assignRepeatedInt64 google.api.expr.test.v1.proto3.TestAllTypes.(list(int)) -> google.api.expr.test.v1.proto3.TestAllTypes } declare assignMap { - function assignMap dev.cel.testing.testdata.proto3.TestAllTypes.(map(int, int)) -> dev.cel.testing.testdata.proto3.TestAllTypes + function assignMap google.api.expr.test.v1.proto3.TestAllTypes.(map(int, int)) -> google.api.expr.test.v1.proto3.TestAllTypes } declare clearField { - function clearField dev.cel.testing.testdata.proto3.TestAllTypes.(string) -> dev.cel.testing.testdata.proto3.TestAllTypes + function clearField google.api.expr.test.v1.proto3.TestAllTypes.(string) -> google.api.expr.test.v1.proto3.TestAllTypes } declare singletonInt64 { - function singletonInt64 (int) -> dev.cel.testing.testdata.proto3.TestAllTypes + function singletonInt64 (int) -> google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {} @@ -20,19 +20,19 @@ result: true Source: TestAllTypes{repeated_int64: [1, 2]}.assignRepeatedInt64([3, 1, 4]) == TestAllTypes{repeated_int64: [3, 1, 4]} declare assignSingleInt64 { - function assignSingleInt64 dev.cel.testing.testdata.proto3.TestAllTypes.(int) -> dev.cel.testing.testdata.proto3.TestAllTypes + function assignSingleInt64 google.api.expr.test.v1.proto3.TestAllTypes.(int) -> google.api.expr.test.v1.proto3.TestAllTypes } declare assignRepeatedInt64 { - function assignRepeatedInt64 dev.cel.testing.testdata.proto3.TestAllTypes.(list(int)) -> dev.cel.testing.testdata.proto3.TestAllTypes + function assignRepeatedInt64 google.api.expr.test.v1.proto3.TestAllTypes.(list(int)) -> google.api.expr.test.v1.proto3.TestAllTypes } declare assignMap { - function assignMap dev.cel.testing.testdata.proto3.TestAllTypes.(map(int, int)) -> dev.cel.testing.testdata.proto3.TestAllTypes + function assignMap google.api.expr.test.v1.proto3.TestAllTypes.(map(int, int)) -> google.api.expr.test.v1.proto3.TestAllTypes } declare clearField { - function clearField dev.cel.testing.testdata.proto3.TestAllTypes.(string) -> dev.cel.testing.testdata.proto3.TestAllTypes + function clearField google.api.expr.test.v1.proto3.TestAllTypes.(string) -> google.api.expr.test.v1.proto3.TestAllTypes } declare singletonInt64 { - function singletonInt64 (int) -> dev.cel.testing.testdata.proto3.TestAllTypes + function singletonInt64 (int) -> google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {} @@ -40,19 +40,19 @@ result: true Source: TestAllTypes{single_bool: true, single_int64: 1}.clearField("single_bool") == TestAllTypes{single_int64: 1} declare assignSingleInt64 { - function assignSingleInt64 dev.cel.testing.testdata.proto3.TestAllTypes.(int) -> dev.cel.testing.testdata.proto3.TestAllTypes + function assignSingleInt64 google.api.expr.test.v1.proto3.TestAllTypes.(int) -> google.api.expr.test.v1.proto3.TestAllTypes } declare assignRepeatedInt64 { - function assignRepeatedInt64 dev.cel.testing.testdata.proto3.TestAllTypes.(list(int)) -> dev.cel.testing.testdata.proto3.TestAllTypes + function assignRepeatedInt64 google.api.expr.test.v1.proto3.TestAllTypes.(list(int)) -> google.api.expr.test.v1.proto3.TestAllTypes } declare assignMap { - function assignMap dev.cel.testing.testdata.proto3.TestAllTypes.(map(int, int)) -> dev.cel.testing.testdata.proto3.TestAllTypes + function assignMap google.api.expr.test.v1.proto3.TestAllTypes.(map(int, int)) -> google.api.expr.test.v1.proto3.TestAllTypes } declare clearField { - function clearField dev.cel.testing.testdata.proto3.TestAllTypes.(string) -> dev.cel.testing.testdata.proto3.TestAllTypes + function clearField google.api.expr.test.v1.proto3.TestAllTypes.(string) -> google.api.expr.test.v1.proto3.TestAllTypes } declare singletonInt64 { - function singletonInt64 (int) -> dev.cel.testing.testdata.proto3.TestAllTypes + function singletonInt64 (int) -> google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {} @@ -60,19 +60,19 @@ result: true Source: TestAllTypes{single_bool: false}.assignMap({13: 26, 22: 42}).map_int32_int64[22] == 42 declare assignSingleInt64 { - function assignSingleInt64 dev.cel.testing.testdata.proto3.TestAllTypes.(int) -> dev.cel.testing.testdata.proto3.TestAllTypes + function assignSingleInt64 google.api.expr.test.v1.proto3.TestAllTypes.(int) -> google.api.expr.test.v1.proto3.TestAllTypes } declare assignRepeatedInt64 { - function assignRepeatedInt64 dev.cel.testing.testdata.proto3.TestAllTypes.(list(int)) -> dev.cel.testing.testdata.proto3.TestAllTypes + function assignRepeatedInt64 google.api.expr.test.v1.proto3.TestAllTypes.(list(int)) -> google.api.expr.test.v1.proto3.TestAllTypes } declare assignMap { - function assignMap dev.cel.testing.testdata.proto3.TestAllTypes.(map(int, int)) -> dev.cel.testing.testdata.proto3.TestAllTypes + function assignMap google.api.expr.test.v1.proto3.TestAllTypes.(map(int, int)) -> google.api.expr.test.v1.proto3.TestAllTypes } declare clearField { - function clearField dev.cel.testing.testdata.proto3.TestAllTypes.(string) -> dev.cel.testing.testdata.proto3.TestAllTypes + function clearField google.api.expr.test.v1.proto3.TestAllTypes.(string) -> google.api.expr.test.v1.proto3.TestAllTypes } declare singletonInt64 { - function singletonInt64 (int) -> dev.cel.testing.testdata.proto3.TestAllTypes + function singletonInt64 (int) -> google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {} @@ -80,19 +80,19 @@ result: true Source: TestAllTypes{single_bool: true, repeated_int64: [1, 2]}.clearField("repeated_int64") == TestAllTypes{single_bool: true} declare assignSingleInt64 { - function assignSingleInt64 dev.cel.testing.testdata.proto3.TestAllTypes.(int) -> dev.cel.testing.testdata.proto3.TestAllTypes + function assignSingleInt64 google.api.expr.test.v1.proto3.TestAllTypes.(int) -> google.api.expr.test.v1.proto3.TestAllTypes } declare assignRepeatedInt64 { - function assignRepeatedInt64 dev.cel.testing.testdata.proto3.TestAllTypes.(list(int)) -> dev.cel.testing.testdata.proto3.TestAllTypes + function assignRepeatedInt64 google.api.expr.test.v1.proto3.TestAllTypes.(list(int)) -> google.api.expr.test.v1.proto3.TestAllTypes } declare assignMap { - function assignMap dev.cel.testing.testdata.proto3.TestAllTypes.(map(int, int)) -> dev.cel.testing.testdata.proto3.TestAllTypes + function assignMap google.api.expr.test.v1.proto3.TestAllTypes.(map(int, int)) -> google.api.expr.test.v1.proto3.TestAllTypes } declare clearField { - function clearField dev.cel.testing.testdata.proto3.TestAllTypes.(string) -> dev.cel.testing.testdata.proto3.TestAllTypes + function clearField google.api.expr.test.v1.proto3.TestAllTypes.(string) -> google.api.expr.test.v1.proto3.TestAllTypes } declare singletonInt64 { - function singletonInt64 (int) -> dev.cel.testing.testdata.proto3.TestAllTypes + function singletonInt64 (int) -> google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {} @@ -100,19 +100,19 @@ result: true Source: singletonInt64(12) == TestAllTypes{single_int64: 12} declare assignSingleInt64 { - function assignSingleInt64 dev.cel.testing.testdata.proto3.TestAllTypes.(int) -> dev.cel.testing.testdata.proto3.TestAllTypes + function assignSingleInt64 google.api.expr.test.v1.proto3.TestAllTypes.(int) -> google.api.expr.test.v1.proto3.TestAllTypes } declare assignRepeatedInt64 { - function assignRepeatedInt64 dev.cel.testing.testdata.proto3.TestAllTypes.(list(int)) -> dev.cel.testing.testdata.proto3.TestAllTypes + function assignRepeatedInt64 google.api.expr.test.v1.proto3.TestAllTypes.(list(int)) -> google.api.expr.test.v1.proto3.TestAllTypes } declare assignMap { - function assignMap dev.cel.testing.testdata.proto3.TestAllTypes.(map(int, int)) -> dev.cel.testing.testdata.proto3.TestAllTypes + function assignMap google.api.expr.test.v1.proto3.TestAllTypes.(map(int, int)) -> google.api.expr.test.v1.proto3.TestAllTypes } declare clearField { - function clearField dev.cel.testing.testdata.proto3.TestAllTypes.(string) -> dev.cel.testing.testdata.proto3.TestAllTypes + function clearField google.api.expr.test.v1.proto3.TestAllTypes.(string) -> google.api.expr.test.v1.proto3.TestAllTypes } declare singletonInt64 { - function singletonInt64 (int) -> dev.cel.testing.testdata.proto3.TestAllTypes + function singletonInt64 (int) -> google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {} diff --git a/runtime/src/test/resources/has.baseline b/runtime/src/test/resources/has.baseline index 1d14601fc..3a32d3389 100644 --- a/runtime/src/test/resources/has.baseline +++ b/runtime/src/test/resources/has.baseline @@ -1,6 +1,6 @@ Source: has(x.single_int32) && !has(x.single_int64) && has(x.single_bool_wrapper) && has(x.single_int32_wrapper) && !has(x.single_int64_wrapper) && has(x.repeated_int32) && !has(x.repeated_int64) && has(x.optional_bool) && !has(x.optional_string) && has(x.oneof_bool) && !has(x.oneof_type) && has(x.map_int32_int64) && !has(x.map_string_string) && has(x.single_nested_message) && !has(x.single_duration) declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {x=single_int32: 1 @@ -13,11 +13,11 @@ map_int32_int64 { key: 1 value: 2 } -oneof_bool: false single_int32_wrapper { value: 42 } single_bool_wrapper { } +oneof_bool: false } result: true diff --git a/runtime/src/test/resources/jsonValueTypes.baseline b/runtime/src/test/resources/jsonValueTypes.baseline index b6bb53e1f..9a116c090 100644 --- a/runtime/src/test/resources/jsonValueTypes.baseline +++ b/runtime/src/test/resources/jsonValueTypes.baseline @@ -1,6 +1,6 @@ Source: x.single_value declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {x=single_value { @@ -11,7 +11,7 @@ result: true Source: x.single_value == double(1) declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {x=single_value { @@ -22,7 +22,7 @@ result: true Source: x.single_value == 1.1 declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {x=single_value { @@ -33,7 +33,7 @@ result: true Source: x.single_value == null declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {x=single_value { @@ -44,7 +44,7 @@ result: true Source: x.single_value == 'hello' declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {x=single_value { @@ -55,7 +55,7 @@ result: true Source: x.single_value[0] == [['hello'], -1.1][0] declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {x=single_value { @@ -77,7 +77,7 @@ result: true Source: x.single_struct.num == {'str': ['hello'], 'num': -1.1}['num'] declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {x=single_struct { @@ -103,7 +103,7 @@ result: true Source: TestAllTypes{single_struct: TestAllTypes{single_value: {'str': ['hello']}}.single_value} declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {} @@ -123,7 +123,7 @@ result: single_struct { Source: pair(x.single_struct.str[0], 'val') declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare pair { function pair (string, string) -> dyn diff --git a/runtime/src/test/resources/lists.baseline b/runtime/src/test/resources/lists.baseline index d97984ed2..493b1c60a 100644 --- a/runtime/src/test/resources/lists.baseline +++ b/runtime/src/test/resources/lists.baseline @@ -1,6 +1,6 @@ Source: ([1, 2, 3] + x.repeated_int32)[3] == 4 declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare y { value int @@ -12,7 +12,7 @@ result: true Source: !(y in [1, 2, 3]) && y in [4, 5, 6] declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare y { value int @@ -23,7 +23,7 @@ result: true Source: TestAllTypes{repeated_int32: [1,2]}.repeated_int32[1] == 2 declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare y { value int @@ -34,7 +34,7 @@ result: true Source: 1 in TestAllTypes{repeated_int32: [1,2]}.repeated_int32 declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare y { value int @@ -45,7 +45,7 @@ result: true Source: !(4 in [1, 2, 3]) && 1 in [1, 2, 3] declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare y { value int @@ -56,7 +56,7 @@ result: true Source: !(4 in list) && 1 in list declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare y { value int @@ -70,7 +70,7 @@ result: true Source: !(y in list) declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare y { value int @@ -84,7 +84,7 @@ result: true Source: y in list declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare y { value int @@ -98,7 +98,7 @@ result: true Source: list[3] declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare y { value int diff --git a/runtime/src/test/resources/maps.baseline b/runtime/src/test/resources/maps.baseline index da0f857ad..33c0cd0c7 100644 --- a/runtime/src/test/resources/maps.baseline +++ b/runtime/src/test/resources/maps.baseline @@ -1,6 +1,6 @@ Source: {1: 2, 3: 4}[3] == 4 declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {} @@ -8,7 +8,7 @@ result: true Source: 3 in {1: 2, 3: 4} && !(4 in {1: 2, 3: 4}) declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {} @@ -16,7 +16,7 @@ result: true Source: x.map_int32_int64[22] == 23 declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {x=map_int32_int64 { @@ -28,7 +28,7 @@ result: true Source: TestAllTypes{map_int32_int64: {21: 22, 22: 23}}.map_int32_int64[22] == 23 declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {} @@ -36,7 +36,7 @@ result: true Source: TestAllTypes{oneof_type: NestedTestAllTypes{payload: x}}.oneof_type.payload.map_int32_int64[22] == 23 declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {x=map_int32_int64 { @@ -48,7 +48,7 @@ result: true Source: !(4 in map) && 1 in map declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare y { value int @@ -62,7 +62,7 @@ result: true Source: !(y in {1: 4, 2: 3, 3: 2}) && y in {5: 3, 4: 2, 3: 3} declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare y { value int @@ -76,7 +76,7 @@ result: true Source: !(y in map) && (y + 3) in map declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare y { value int @@ -90,7 +90,7 @@ result: true Source: TestAllTypes{map_int64_nested_type:{42:NestedTestAllTypes{payload:TestAllTypes{}}}} declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare y { value int @@ -111,7 +111,7 @@ result: map_int64_nested_type { Source: {true: 1, false: 2, true: 3}[true] declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare y { value int @@ -126,7 +126,7 @@ error_code: DUPLICATE_ATTRIBUTE Source: {b: 1, !b: 2, b: 3}[true] declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare y { value int diff --git a/runtime/src/test/resources/messages.baseline b/runtime/src/test/resources/messages.baseline index df7a6579d..3a5dcf81b 100644 --- a/runtime/src/test/resources/messages.baseline +++ b/runtime/src/test/resources/messages.baseline @@ -1,6 +1,6 @@ Source: x.single_nested_message.bb == 43 && has(x.single_nested_message) declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {x=single_nested_message { @@ -11,10 +11,10 @@ result: true Source: single_nested_message.bb == 43 declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare single_nested_message { - value dev.cel.testing.testdata.proto3.TestAllTypes.NestedMessage + value google.api.expr.test.v1.proto3.TestAllTypes.NestedMessage } =====> bindings: {single_nested_message=bb: 43 @@ -23,10 +23,10 @@ result: true Source: TestAllTypes{single_int64: 1, single_sfixed64: 2, single_int32: 2}.single_int32 == 2 declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare single_nested_message { - value dev.cel.testing.testdata.proto3.TestAllTypes.NestedMessage + value google.api.expr.test.v1.proto3.TestAllTypes.NestedMessage } =====> bindings: {} diff --git a/runtime/src/test/resources/namespacedVariables.baseline b/runtime/src/test/resources/namespacedVariables.baseline index 1013e1b66..2b58cc41a 100644 --- a/runtime/src/test/resources/namespacedVariables.baseline +++ b/runtime/src/test/resources/namespacedVariables.baseline @@ -11,7 +11,7 @@ declare ns.x { value int } declare dev.cel.testing.testdata.proto3.msgVar { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {dev.cel.testing.testdata.proto3.msgVar=single_int32: 5 diff --git a/runtime/src/test/resources/nestedEnums.baseline b/runtime/src/test/resources/nestedEnums.baseline index 6dfee68f2..035a95726 100644 --- a/runtime/src/test/resources/nestedEnums.baseline +++ b/runtime/src/test/resources/nestedEnums.baseline @@ -1,6 +1,6 @@ Source: x.single_nested_enum == TestAllTypes.NestedEnum.BAR declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {x=single_nested_enum: BAR @@ -9,7 +9,7 @@ result: true Source: single_nested_enum == TestAllTypes.NestedEnum.BAR declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare single_nested_enum { value int @@ -20,7 +20,7 @@ result: true Source: TestAllTypes{single_nested_enum : TestAllTypes.NestedEnum.BAR}.single_nested_enum == 1 declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare single_nested_enum { value int diff --git a/runtime/src/test/resources/packUnpackAny.baseline b/runtime/src/test/resources/packUnpackAny.baseline index 2d57e9131..81e9f1a96 100644 --- a/runtime/src/test/resources/packUnpackAny.baseline +++ b/runtime/src/test/resources/packUnpackAny.baseline @@ -6,7 +6,7 @@ declare d { value google.protobuf.Duration } declare message { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare list { value list(dyn) @@ -26,7 +26,7 @@ declare d { value google.protobuf.Duration } declare message { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare list { value list(dyn) @@ -49,7 +49,7 @@ declare d { value google.protobuf.Duration } declare message { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare list { value list(dyn) @@ -71,7 +71,7 @@ declare d { value google.protobuf.Duration } declare message { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare list { value list(dyn) @@ -89,7 +89,7 @@ declare d { value google.protobuf.Duration } declare message { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare list { value list(dyn) @@ -108,13 +108,13 @@ declare d { value google.protobuf.Duration } declare message { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare list { value list(dyn) } =====> -bindings: {list=[type_url: "type.googleapis.com/dev.cel.testing.testdata.proto3.TestAllTypes" +bindings: {list=[type_url: "type.googleapis.com/google.api.expr.test.v1.proto3.TestAllTypes" value: "\242\0062\n,type.googleapis.com/google.protobuf.Duration\022\002\bd" ], message=single_any { type_url: "type.googleapis.com/google.protobuf.Duration" @@ -131,7 +131,7 @@ declare d { value google.protobuf.Duration } declare message { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare list { value list(dyn) @@ -153,7 +153,7 @@ declare d { value google.protobuf.Duration } declare message { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare list { value list(dyn) @@ -175,7 +175,7 @@ declare d { value google.protobuf.Duration } declare message { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare list { value list(dyn) @@ -197,7 +197,7 @@ declare d { value google.protobuf.Duration } declare message { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare list { value list(dyn) @@ -218,7 +218,7 @@ declare d { value google.protobuf.Duration } declare message { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare list { value list(dyn) @@ -239,7 +239,7 @@ declare d { value google.protobuf.Duration } declare message { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare list { value list(dyn) @@ -260,7 +260,7 @@ declare d { value google.protobuf.Duration } declare message { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare list { value list(dyn) diff --git a/runtime/src/test/resources/typeComparisons.baseline b/runtime/src/test/resources/typeComparisons.baseline index 3af41c3da..915bdf4d9 100644 --- a/runtime/src/test/resources/typeComparisons.baseline +++ b/runtime/src/test/resources/typeComparisons.baseline @@ -23,7 +23,7 @@ Source: type(duration('10s')) == google.protobuf.Duration bindings: {} result: true -Source: type(TestAllTypes{}) == TestAllTypes && type(TestAllTypes{}) == proto3.TestAllTypes && type(TestAllTypes{}) == .dev.cel.testing.testdata.proto3.TestAllTypes && type(proto3.TestAllTypes{}) == TestAllTypes && type(proto3.TestAllTypes{}) == proto3.TestAllTypes && type(proto3.TestAllTypes{}) == .dev.cel.testing.testdata.proto3.TestAllTypes && type(.dev.cel.testing.testdata.proto3.TestAllTypes{}) == TestAllTypes && type(.dev.cel.testing.testdata.proto3.TestAllTypes{}) == proto3.TestAllTypes && type(.dev.cel.testing.testdata.proto3.TestAllTypes{}) == .dev.cel.testing.testdata.proto3.TestAllTypes +Source: type(TestAllTypes{}) == TestAllTypes && type(TestAllTypes{}) == proto3.TestAllTypes && type(TestAllTypes{}) == .google.api.expr.test.v1.proto3.TestAllTypes && type(proto3.TestAllTypes{}) == TestAllTypes && type(proto3.TestAllTypes{}) == proto3.TestAllTypes && type(proto3.TestAllTypes{}) == .google.api.expr.test.v1.proto3.TestAllTypes && type(.google.api.expr.test.v1.proto3.TestAllTypes{}) == TestAllTypes && type(.google.api.expr.test.v1.proto3.TestAllTypes{}) == proto3.TestAllTypes && type(.google.api.expr.test.v1.proto3.TestAllTypes{}) == .google.api.expr.test.v1.proto3.TestAllTypes =====> bindings: {} result: true diff --git a/runtime/src/test/resources/unknownField.baseline b/runtime/src/test/resources/unknownField.baseline index 92f0a7385..5ddc80da5 100644 --- a/runtime/src/test/resources/unknownField.baseline +++ b/runtime/src/test/resources/unknownField.baseline @@ -1,6 +1,6 @@ Source: x.single_int32 declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {} @@ -11,7 +11,7 @@ result: unknown { Source: x.map_int32_int64[22] declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {} @@ -22,7 +22,7 @@ result: unknown { Source: x.repeated_nested_message[1] declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {} @@ -33,7 +33,7 @@ result: unknown { Source: x.single_timestamp.getSeconds() declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {} @@ -44,7 +44,7 @@ result: unknown { Source: x.single_nested_message.bb declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {} @@ -55,7 +55,7 @@ result: unknown { Source: {1: x.single_int32} declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {} @@ -66,7 +66,7 @@ result: unknown { Source: [1, x.single_int32] declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {} diff --git a/runtime/src/test/resources/unknownResultSet.baseline b/runtime/src/test/resources/unknownResultSet.baseline index eb7532b8b..2b2c61f62 100644 --- a/runtime/src/test/resources/unknownResultSet.baseline +++ b/runtime/src/test/resources/unknownResultSet.baseline @@ -1,6 +1,6 @@ Source: x.single_int32 == 1 && true declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {} @@ -11,7 +11,7 @@ result: unknown { Source: x.single_int32 == 1 && false declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {} @@ -19,7 +19,7 @@ result: false Source: x.single_int32 == 1 && x.single_int64 == 1 declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {} @@ -31,7 +31,7 @@ result: unknown { Source: x.single_int32 == 1 && x.single_timestamp <= timestamp("bad timestamp string") declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {} @@ -42,7 +42,7 @@ result: unknown { Source: true && x.single_int32 == 1 declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {} @@ -53,7 +53,7 @@ result: unknown { Source: false && x.single_int32 == 1 declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {} @@ -61,7 +61,7 @@ result: false Source: x.single_timestamp <= timestamp("bad timestamp string") && x.single_int32 == 1 declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {} @@ -72,7 +72,7 @@ result: unknown { Source: x.single_timestamp <= timestamp("bad timestamp string") && x.single_timestamp > timestamp("another bad timestamp string") declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {} @@ -81,7 +81,7 @@ error_code: BAD_FORMAT Source: x.single_int32 == 1 || x.single_string == "test" declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {} @@ -93,7 +93,7 @@ result: unknown { Source: x.single_int32 == 1 || x.single_string != "test" declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {} @@ -105,7 +105,7 @@ result: unknown { Source: x.single_int32 == 1 || x.single_int64 == 1 declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {} @@ -117,7 +117,7 @@ result: unknown { Source: x.single_int32 == 1 || x.single_timestamp <= timestamp("bad timestamp string") declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {} @@ -128,7 +128,7 @@ result: unknown { Source: true || x.single_int32 == 1 declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {} @@ -136,7 +136,7 @@ result: true Source: false || x.single_int32 == 1 declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {} @@ -147,7 +147,7 @@ result: unknown { Source: x.single_timestamp <= timestamp("bad timestamp string") || x.single_int32 == 1 declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {} @@ -158,7 +158,7 @@ result: unknown { Source: x.single_timestamp <= timestamp("bad timestamp string") || x.single_timestamp > timestamp("another bad timestamp string") declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {} @@ -167,7 +167,7 @@ error_code: BAD_FORMAT Source: x.single_int32.f(1) declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare f { function f int.(int) -> bool @@ -181,7 +181,7 @@ result: unknown { Source: 1.f(x.single_int32) declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare f { function f int.(int) -> bool @@ -195,7 +195,7 @@ result: unknown { Source: x.single_int64.f(x.single_int32) declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare f { function f int.(int) -> bool @@ -210,7 +210,7 @@ result: unknown { Source: x declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare f { function f int.(int) -> bool @@ -228,7 +228,7 @@ result: unknown { Source: x declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare f { function f int.(int) -> bool @@ -244,7 +244,7 @@ result: unknown { Source: x.map_int32_int64.map(x, x > 0, x + 1) declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare f { function f int.(int) -> bool @@ -258,7 +258,7 @@ result: unknown { Source: [0, 2, 4].exists(z, z == 2 || z == x.single_int32) declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare f { function f int.(int) -> bool @@ -269,7 +269,7 @@ result: true Source: [0, 2, 4].exists(z, z == x.single_int32) declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare f { function f int.(int) -> bool @@ -283,7 +283,7 @@ result: unknown { Source: [0, 2, 4].exists_one(z, z == 0 || (z == 2 && z == x.single_int32) || (z == 4 && z == x.single_int64)) declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare f { function f int.(int) -> bool @@ -297,7 +297,7 @@ result: unknown { Source: [0, 2].all(z, z == 2 || z == x.single_int32) declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare f { function f int.(int) -> bool @@ -311,7 +311,7 @@ result: unknown { Source: [0, 2, 4].filter(z, z == 0 || (z == 2 && z == x.single_int32) || (z == 4 && z == x.single_int64)) declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare f { function f int.(int) -> bool @@ -325,7 +325,7 @@ result: unknown { Source: [0, 2, 4].map(z, z == 0 || (z == 2 && z == x.single_int32) || (z == 4 && z == x.single_int64)) declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare f { function f int.(int) -> bool @@ -340,7 +340,7 @@ result: unknown { Source: x.single_int32 == 1 ? 1 : 2 declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare f { function f int.(int) -> bool @@ -354,7 +354,7 @@ result: unknown { Source: true ? x.single_int32 : 2 declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare f { function f int.(int) -> bool @@ -368,7 +368,7 @@ result: unknown { Source: true ? 1 : x.single_int32 declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare f { function f int.(int) -> bool @@ -379,7 +379,7 @@ result: 1 Source: false ? x.single_int32 : 2 declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare f { function f int.(int) -> bool @@ -390,7 +390,7 @@ result: 2 Source: false ? 1 : x.single_int32 declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare f { function f int.(int) -> bool @@ -404,7 +404,7 @@ result: unknown { Source: x.single_int64 == 1 ? x.single_int32 : x.single_int32 declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare f { function f int.(int) -> bool @@ -418,7 +418,7 @@ result: unknown { Source: {x.single_int32: 2, 3: 4} declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare f { function f int.(int) -> bool @@ -432,7 +432,7 @@ result: unknown { Source: {1: x.single_int32, 3: 4} declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare f { function f int.(int) -> bool @@ -446,7 +446,7 @@ result: unknown { Source: {1: x.single_int32, x.single_int64: 4} declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare f { function f int.(int) -> bool @@ -461,7 +461,7 @@ result: unknown { Source: [1, x.single_int32, 3, 4] declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare f { function f int.(int) -> bool @@ -475,7 +475,7 @@ result: unknown { Source: [1, x.single_int32, x.single_int64, 4] declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare f { function f int.(int) -> bool @@ -490,7 +490,7 @@ result: unknown { Source: TestAllTypes{single_int32: x.single_int32}.single_int32 == 2 declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare f { function f int.(int) -> bool @@ -504,7 +504,7 @@ result: unknown { Source: TestAllTypes{single_int32: x.single_int32, single_int64: x.single_int64} declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } declare f { function f int.(int) -> bool diff --git a/runtime/src/test/resources/wrappers.baseline b/runtime/src/test/resources/wrappers.baseline index 3305bbde4..718130bde 100644 --- a/runtime/src/test/resources/wrappers.baseline +++ b/runtime/src/test/resources/wrappers.baseline @@ -1,6 +1,6 @@ Source: x.single_bool_wrapper == true && x.single_bytes_wrapper == b'hi' && x.single_double_wrapper == -3.0 && x.single_float_wrapper == 1.5 && x.single_int32_wrapper == -12 && x.single_int64_wrapper == -34 && x.single_string_wrapper == 'hello' && x.single_uint32_wrapper == 12u && x.single_uint64_wrapper == 34u declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {x=single_int64_wrapper { @@ -35,7 +35,7 @@ result: true Source: x.single_bool_wrapper == google.protobuf.BoolValue{} && x.single_bytes_wrapper == google.protobuf.BytesValue{value: b'hi'} && x.single_double_wrapper == google.protobuf.DoubleValue{value: -3.0} && x.single_float_wrapper == google.protobuf.FloatValue{value: 1.5} && x.single_int32_wrapper == google.protobuf.Int32Value{value: -12} && x.single_int64_wrapper == google.protobuf.Int64Value{value: -34} && x.single_string_wrapper == google.protobuf.StringValue{} && x.single_uint32_wrapper == google.protobuf.UInt32Value{value: 12u} && x.single_uint64_wrapper == google.protobuf.UInt64Value{value: 34u} declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {x=single_int64_wrapper { @@ -68,7 +68,7 @@ result: true Source: x.single_bool_wrapper == null && x.single_bytes_wrapper == null && x.single_double_wrapper == null && x.single_float_wrapper == null && x.single_int32_wrapper == null && x.single_int64_wrapper == null && x.single_string_wrapper == null && x.single_uint32_wrapper == null && x.single_uint64_wrapper == null declare x { - value dev.cel.testing.testdata.proto3.TestAllTypes + value google.api.expr.test.v1.proto3.TestAllTypes } =====> bindings: {x=} diff --git a/testing/src/main/java/dev/cel/testing/BUILD.bazel b/testing/src/main/java/dev/cel/testing/BUILD.bazel index 4643e1272..c708ad57f 100644 --- a/testing/src/main/java/dev/cel/testing/BUILD.bazel +++ b/testing/src/main/java/dev/cel/testing/BUILD.bazel @@ -153,11 +153,11 @@ java_library( "//common/internal:cel_descriptor_pools", "//common/internal:file_descriptor_converter", "//common/resources/testdata/proto3:standalone_global_enum_java_proto", - "//common/resources/testdata/proto3:test_all_types_java_proto", "//common/types:cel_types", "//runtime:interpreter", "@@protobuf~//java/core", "@cel_spec//proto/cel/expr:expr_java_proto", + "@cel_spec//proto/test/v1/proto3:test_all_types_java_proto", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java_util", diff --git a/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java b/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java index 811af7033..54fbe3382 100644 --- a/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java +++ b/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java @@ -23,6 +23,9 @@ import dev.cel.expr.Type; import dev.cel.expr.Type.AbstractType; import dev.cel.expr.UnknownSet; +import com.google.api.expr.test.v1.proto3.TestAllTypesProto.TestAllTypes; +import com.google.api.expr.test.v1.proto3.TestAllTypesProto.TestAllTypes.NestedEnum; +import com.google.api.expr.test.v1.proto3.TestAllTypesProto.TestAllTypes.NestedMessage; import com.google.common.base.Ascii; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; @@ -63,9 +66,6 @@ import dev.cel.runtime.Activation; import dev.cel.runtime.InterpreterException; import dev.cel.testing.testdata.proto3.StandaloneGlobalEnum; -import dev.cel.testing.testdata.proto3.TestAllTypesProto.TestAllTypes; -import dev.cel.testing.testdata.proto3.TestAllTypesProto.TestAllTypes.NestedEnum; -import dev.cel.testing.testdata.proto3.TestAllTypesProto.TestAllTypes.NestedMessage; import java.io.IOException; import java.util.Arrays; import java.util.List; @@ -836,7 +836,7 @@ public void namespacedVariables() throws Exception { runTest(Activation.of("ns.x", 2)); container = "dev.cel.testing.testdata.proto3"; - Type messageType = CelTypes.createMessage("dev.cel.testing.testdata.proto3.TestAllTypes"); + Type messageType = CelTypes.createMessage("google.api.expr.test.v1.proto3.TestAllTypes"); declareVariable("dev.cel.testing.testdata.proto3.msgVar", messageType); source = "msgVar.single_int32"; runTest( @@ -1767,14 +1767,14 @@ public void typeComparisons() throws Exception { source = "type(TestAllTypes{}) == TestAllTypes && " + "type(TestAllTypes{}) == proto3.TestAllTypes && " - + "type(TestAllTypes{}) == .dev.cel.testing.testdata.proto3.TestAllTypes && " + + "type(TestAllTypes{}) == .google.api.expr.test.v1.proto3.TestAllTypes && " + "type(proto3.TestAllTypes{}) == TestAllTypes && " + "type(proto3.TestAllTypes{}) == proto3.TestAllTypes && " - + "type(proto3.TestAllTypes{}) == .dev.cel.testing.testdata.proto3.TestAllTypes && " - + "type(.dev.cel.testing.testdata.proto3.TestAllTypes{}) == TestAllTypes && " - + "type(.dev.cel.testing.testdata.proto3.TestAllTypes{}) == proto3.TestAllTypes && " - + "type(.dev.cel.testing.testdata.proto3.TestAllTypes{}) == " - + ".dev.cel.testing.testdata.proto3.TestAllTypes"; + + "type(proto3.TestAllTypes{}) == .google.api.expr.test.v1.proto3.TestAllTypes && " + + "type(.google.api.expr.test.v1.proto3.TestAllTypes{}) == TestAllTypes && " + + "type(.google.api.expr.test.v1.proto3.TestAllTypes{}) == proto3.TestAllTypes && " + + "type(.google.api.expr.test.v1.proto3.TestAllTypes{}) == " + + ".google.api.expr.test.v1.proto3.TestAllTypes"; runTest(Activation.EMPTY); // Test whether a type name is recognized as a type. @@ -1944,7 +1944,7 @@ public void dynamicMessage_adapted() throws Exception { .setSingleValue(Value.newBuilder().setStringValue("a")) .setSingleStruct( Struct.newBuilder().putFields("b", Value.newBuilder().setStringValue("c").build())) - .setSingleListValue( + .setListValue( ListValue.newBuilder().addValues(Value.newBuilder().setStringValue("d")).build()) .build(); @@ -2002,7 +2002,7 @@ public void dynamicMessage_adapted() throws Exception { source = "msg.single_struct"; assertThat(runTest(activation)).isInstanceOf(Map.class); - source = "msg.single_list_value"; + source = "msg.list_value"; assertThat(runTest(activation)).isInstanceOf(List.class); } From eb2e557231c322ebfe4f4f15ff85f26409478daa Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Thu, 22 Aug 2024 09:07:46 -0700 Subject: [PATCH 186/486] Add ListsExtension with flatten function (single level only) Recursive implementation will be added in the future. PiperOrigin-RevId: 666372924 --- .../main/java/dev/cel/extensions/BUILD.bazel | 16 +++ .../dev/cel/extensions/CelExtensions.java | 49 ++++++++- .../cel/extensions/CelListsExtensions.java | 101 ++++++++++++++++++ .../main/java/dev/cel/extensions/README.md | 30 ++++++ .../dev/cel/extensions/CelExtensionsTest.java | 3 +- .../extensions/CelListsExtensionsTest.java | 62 +++++++++++ 6 files changed, 256 insertions(+), 5 deletions(-) create mode 100644 extensions/src/main/java/dev/cel/extensions/CelListsExtensions.java create mode 100644 extensions/src/test/java/dev/cel/extensions/CelListsExtensionsTest.java diff --git a/extensions/src/main/java/dev/cel/extensions/BUILD.bazel b/extensions/src/main/java/dev/cel/extensions/BUILD.bazel index b92bd9b54..7f6652666 100644 --- a/extensions/src/main/java/dev/cel/extensions/BUILD.bazel +++ b/extensions/src/main/java/dev/cel/extensions/BUILD.bazel @@ -16,6 +16,7 @@ java_library( deps = [ ":bindings", ":encoders", + ":lists", ":math", ":protos", ":sets", @@ -148,3 +149,18 @@ java_library( "@maven//:com_google_guava_guava", ], ) + +java_library( + name = "lists", + srcs = ["CelListsExtensions.java"], + tags = [ + ], + deps = [ + "//checker:checker_builder", + "//common:compiler_common", + "//common/types", + "//compiler:compiler_builder", + "//runtime", + "@maven//:com_google_guava_guava", + ], +) diff --git a/extensions/src/main/java/dev/cel/extensions/CelExtensions.java b/extensions/src/main/java/dev/cel/extensions/CelExtensions.java index 353acdad3..eb795341e 100644 --- a/extensions/src/main/java/dev/cel/extensions/CelExtensions.java +++ b/extensions/src/main/java/dev/cel/extensions/CelExtensions.java @@ -20,6 +20,7 @@ import com.google.common.collect.ImmutableSet; import com.google.common.collect.Streams; import dev.cel.common.CelOptions; +import dev.cel.extensions.CelListsExtensions.Function; import java.util.Set; /** @@ -34,6 +35,7 @@ public final class CelExtensions { private static final CelProtoExtensions PROTO_EXTENSIONS = new CelProtoExtensions(); private static final CelBindingsExtensions BINDINGS_EXTENSIONS = new CelBindingsExtensions(); private static final CelEncoderExtensions ENCODER_EXTENSIONS = new CelEncoderExtensions(); + private static final CelListsExtensions LISTS_EXTENSIONS_ALL = new CelListsExtensions(); /** * Extended functions for string manipulation. @@ -187,9 +189,9 @@ public static CelSetsExtensions sets() { * *

Refer to README.md for available functions. * - *

This will include all functions denoted in {@link CelSetExtensions.Function}, including any - * future additions. To expose only a subset of functions, use {@link - * #sets(CelSetExtensions.Function...)} instead. + *

This will include all functions denoted in {@link CelSetsExtensions.Function}, including any + * future additions. To expose only a subset of functions, use {@link #sets(CelOptions, + * CelSetsExtensions.Function...)} instead. */ public static CelSetsExtensions sets(CelOptions celOptions) { return new CelSetsExtensions(celOptions); @@ -219,6 +221,43 @@ public static CelSetsExtensions sets( return new CelSetsExtensions(celOptions, functions); } + /** + * Extended functions for List manipulation. + * + *

Refer to README.md for available functions. + * + *

This will include only the specific functions denoted by {@link + * CelListsExtensions.Function}. + */ + public static CelListsExtensions lists() { + return LISTS_EXTENSIONS_ALL; + } + + /** + * Extended functions for List manipulation. + * + *

Refer to README.md for available functions. + * + *

This will include only the specific functions denoted by {@link + * CelListsExtensions.Function}. + */ + public static CelListsExtensions lists(CelListsExtensions.Function... functions) { + return lists(ImmutableSet.copyOf(functions)); + } + + /** + * Extended functions for List manipulation. + * + *

Refer to README.md for available functions. + * + *

This will include all functions denoted in {@link CelListsExtensions.Function}, including + * any future additions. To expose only a subset of functions, use {@link #lists(Function...)} + * instead. + */ + public static CelListsExtensions lists(Set functions) { + return new CelListsExtensions(functions); + } + /** * Retrieves all function names used by every extension libraries. * @@ -235,7 +274,9 @@ public static ImmutableSet getAllFunctionNames() { stream(CelSetsExtensions.Function.values()) .map(CelSetsExtensions.Function::getFunction), stream(CelEncoderExtensions.Function.values()) - .map(CelEncoderExtensions.Function::getFunction)) + .map(CelEncoderExtensions.Function::getFunction), + stream(CelListsExtensions.Function.values()) + .map(CelListsExtensions.Function::getFunction)) .collect(toImmutableSet()); } diff --git a/extensions/src/main/java/dev/cel/extensions/CelListsExtensions.java b/extensions/src/main/java/dev/cel/extensions/CelListsExtensions.java new file mode 100644 index 000000000..06eccd16b --- /dev/null +++ b/extensions/src/main/java/dev/cel/extensions/CelListsExtensions.java @@ -0,0 +1,101 @@ +// Copyright 2024 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.extensions; + +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import dev.cel.checker.CelCheckerBuilder; +import dev.cel.common.CelFunctionDecl; +import dev.cel.common.CelOverloadDecl; +import dev.cel.common.types.ListType; +import dev.cel.common.types.TypeParamType; +import dev.cel.compiler.CelCompilerLibrary; +import dev.cel.runtime.CelRuntime; +import dev.cel.runtime.CelRuntime.CelFunctionBinding; +import dev.cel.runtime.CelRuntimeBuilder; +import dev.cel.runtime.CelRuntimeLibrary; +import java.util.Collection; +import java.util.Set; + +/** Internal implementation of CEL lists extensions. */ +final class CelListsExtensions implements CelCompilerLibrary, CelRuntimeLibrary { + + private static final TypeParamType LIST_PARAM_TYPE = TypeParamType.create("T"); + + @SuppressWarnings({"unchecked"}) // Unchecked: Type-checker guarantees casting safety. + public enum Function { + FLATTEN( + CelFunctionDecl.newFunctionDeclaration( + "flatten", + CelOverloadDecl.newMemberOverload( + "list_flatten", + "Flattens a list by a single level", + ListType.create(LIST_PARAM_TYPE), + ListType.create(ListType.create(LIST_PARAM_TYPE)))), + // TODO: add list_flatten_list_int + CelRuntime.CelFunctionBinding.from( + "list_flatten", Collection.class, list -> flatten(list, 1))), + ; + + private final CelFunctionDecl functionDecl; + private final ImmutableSet functionBindings; + + String getFunction() { + return functionDecl.name(); + } + + Function(CelFunctionDecl functionDecl, CelRuntime.CelFunctionBinding... functionBindings) { + this.functionDecl = functionDecl; + this.functionBindings = ImmutableSet.copyOf(functionBindings); + } + } + + private final ImmutableSet functions; + + CelListsExtensions() { + this.functions = ImmutableSet.copyOf(Function.values()); + } + + CelListsExtensions(Set functions) { + this.functions = ImmutableSet.copyOf(functions); + } + + @Override + public void setCheckerOptions(CelCheckerBuilder checkerBuilder) { + functions.forEach(function -> checkerBuilder.addFunctionDeclarations(function.functionDecl)); + } + + @Override + public void setRuntimeOptions(CelRuntimeBuilder runtimeBuilder) { + functions.forEach(function -> runtimeBuilder.addFunctionBindings(function.functionBindings)); + } + + @SuppressWarnings("unchecked") + private static ImmutableList flatten(Collection list, int level) { + Preconditions.checkArgument(level == 1, "recursive flatten is not supported yet."); + ImmutableList.Builder builder = ImmutableList.builder(); + for (Object element : list) { + if (element instanceof Collection) { + Collection listItem = (Collection) element; + builder.addAll(listItem); + } else { + builder.add(element); + } + } + + return builder.build(); + } +} diff --git a/extensions/src/main/java/dev/cel/extensions/README.md b/extensions/src/main/java/dev/cel/extensions/README.md index 1163f334c..e99e6a93f 100644 --- a/extensions/src/main/java/dev/cel/extensions/README.md +++ b/extensions/src/main/java/dev/cel/extensions/README.md @@ -406,3 +406,33 @@ sets.intersects([1], [1, 2]) // true sets.intersects([[1], [2, 3]], [[1, 2], [2, 3.0]]) // true ``` +## Lists + +Extended functions for list manipulation. As a general note, all indices are +zero-based. + +### Flatten + +Flattens a list by one level. Support for flattening to a specified level +will be provided in the future. + +Examples: + +``` +[].flatten() // [] +[1,[2,3],[4]].flatten() // [1, 2, 3, 4] +[1,[2,[3,4]]].flatten() // [1, 2, [3, 4]] +[1,2,[],[],[3,4]].flatten() // [1, 2, 3, 4] +``` + +Note that due to the current limitations of type-checker, a compilation error +will occur if an already flat list is populated. For time being, you must wrap +the list in dyn if you anticipate having to deal with a flat list: + +``` +[1,2,3].flatten() // error +dyn([1,2,3]).flatten() // [1,2,3] +``` + +This will be addressed once we add the appropriate capabilities in the +type-checker to handle type-reductions, or union types. diff --git a/extensions/src/test/java/dev/cel/extensions/CelExtensionsTest.java b/extensions/src/test/java/dev/cel/extensions/CelExtensionsTest.java index d7b75f8dd..26c51b1f4 100644 --- a/extensions/src/test/java/dev/cel/extensions/CelExtensionsTest.java +++ b/extensions/src/test/java/dev/cel/extensions/CelExtensionsTest.java @@ -159,6 +159,7 @@ public void getAllFunctionNames() { "sets.equivalent", "sets.intersects", "base64.decode", - "base64.encode"); + "base64.encode", + "flatten"); } } diff --git a/extensions/src/test/java/dev/cel/extensions/CelListsExtensionsTest.java b/extensions/src/test/java/dev/cel/extensions/CelListsExtensionsTest.java new file mode 100644 index 000000000..cee8de5b7 --- /dev/null +++ b/extensions/src/test/java/dev/cel/extensions/CelListsExtensionsTest.java @@ -0,0 +1,62 @@ +// Copyright 2024 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.extensions; + +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertThrows; + +import com.google.testing.junit.testparameterinjector.TestParameterInjector; +import com.google.testing.junit.testparameterinjector.TestParameters; +import dev.cel.bundle.Cel; +import dev.cel.bundle.CelFactory; +import dev.cel.common.CelValidationException; +import dev.cel.parser.CelStandardMacro; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(TestParameterInjector.class) +public class CelListsExtensionsTest { + private static final Cel CEL = + CelFactory.standardCelBuilder() + .setStandardMacros(CelStandardMacro.STANDARD_MACROS) + .addCompilerLibraries(CelExtensions.lists()) + .addRuntimeLibraries(CelExtensions.lists()) + .build(); + + @Test + @TestParameters("{expression: '[].flatten() == []'}") + @TestParameters("{expression: '[[1, 2]].flatten().exists(i, i == 1)'}") + @TestParameters("{expression: '[[], [[]], [[[]]]].flatten() == [[], [[]]]'}") + @TestParameters("{expression: '[1,[2,[3,4]]].flatten() == [1,2,[3,4]]'}") + @TestParameters("{expression: '[1,2,[],[],[3,4]].flatten() == [1,2,3,4]'}") + @TestParameters("{expression: '[1,[2,3],[[4,5]], [[[6,7]]]].flatten() == [1,2,3,[4,5],[[6,7]]]'}") + @TestParameters("{expression: 'dyn([1]).flatten() == [1]'}") + @TestParameters("{expression: 'dyn([{1: 2}]).flatten() == [{1: 2}]'}") + @TestParameters("{expression: 'dyn([1,2,3,4]).flatten() == [1,2,3,4]'}") + public void flattenSingleLevel_success(String expression) throws Exception { + boolean result = (boolean) CEL.createProgram(CEL.compile(expression).getAst()).eval(); + + assertThat(result).isTrue(); + } + + @Test + @TestParameters("{expression: '[1].flatten()'}") + @TestParameters("{expression: '[{1: 2}].flatten()'}") + @TestParameters("{expression: '[1,2,3,4].flatten()'}") + public void flattenSingleLevel_listIsSingleLevel_throws(String expression) { + // Note: Java lacks the capability of conditionally disabling type guards + // due to the lack of full-fledged dynamic dispatch. + assertThrows(CelValidationException.class, () -> CEL.compile(expression).getAst()); + } +} From dae82c6d10114bb1da643203569f90a757c6c5e6 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Thu, 22 Aug 2024 09:34:38 -0700 Subject: [PATCH 187/486] Enable retainComprehensionStructure by default PiperOrigin-RevId: 666382519 --- .../cel/optimizer/optimizers/SubexpressionOptimizer.java | 6 +++--- .../optimizers/SubexpressionOptimizerBaselineTest.java | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java index 293481d8f..ff3162cf4 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java @@ -744,8 +744,8 @@ public abstract static class Builder { * + @index0.map(@it0, [@it0 + @it0, @it0 + @it0]))} * * - * If targeting CEL-Java for the runtime, the recommended setting is to - * leave this disabled for maximal optimization efficiency. + * If targeting CEL-Java for the runtime, the recommended setting is to leave this disabled + * for maximal optimization efficiency. */ public abstract Builder retainComprehensionStructure(boolean value); @@ -783,7 +783,7 @@ public static Builder newBuilder() { .iterationLimit(500) .populateMacroCalls(false) .enableCelBlock(false) - .retainComprehensionStructure(false) + .retainComprehensionStructure(true) .subexpressionMaxRecursionDepth(0); } diff --git a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerBaselineTest.java b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerBaselineTest.java index 9e67bda85..1f7de0a7e 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerBaselineTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerBaselineTest.java @@ -259,6 +259,7 @@ public void large_expressions_block_recursion_depth_1() throws Exception { CEL, SubexpressionOptimizerOptions.newBuilder() .populateMacroCalls(true) + .retainComprehensionStructure(false) .enableCelBlock(true) .subexpressionMaxRecursionDepth(1) .build()); @@ -273,6 +274,7 @@ public void large_expressions_block_recursion_depth_2() throws Exception { CEL, SubexpressionOptimizerOptions.newBuilder() .populateMacroCalls(true) + .retainComprehensionStructure(false) .enableCelBlock(true) .subexpressionMaxRecursionDepth(2) .build()); @@ -287,6 +289,7 @@ public void large_expressions_block_recursion_depth_3() throws Exception { CEL, SubexpressionOptimizerOptions.newBuilder() .populateMacroCalls(true) + .retainComprehensionStructure(false) .enableCelBlock(true) .subexpressionMaxRecursionDepth(3) .build()); From 6c71f1602f23ea7f75020091d7091ede9ab3b03d Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Fri, 30 Aug 2024 09:06:47 -0700 Subject: [PATCH 188/486] Migrate interpreter tests to fluent APIs PiperOrigin-RevId: 669345287 --- .../src/main/java/dev/cel/runtime/BUILD.bazel | 1 + .../dev/cel/runtime/CelVariableResolver.java | 5 +- .../runtime/HierarchicalVariableResolver.java | 44 + .../src/test/java/dev/cel/runtime/BUILD.bazel | 8 +- .../cel/runtime/CelValueInterpreterTest.java | 54 +- .../java/dev/cel/runtime/InterpreterTest.java | 46 +- testing/BUILD.bazel | 15 - .../src/main/java/dev/cel/testing/BUILD.bazel | 60 +- .../dev/cel/testing/BaseInterpreterTest.java | 1362 +++++++++-------- .../dev/cel/testing/BaselineTestCase.java | 4 + .../src/main/java/dev/cel/testing/Eval.java | 44 - .../dev/cel/testing/EvalCelValueSync.java | 95 -- .../main/java/dev/cel/testing/EvalSync.java | 79 - .../src/test/java/dev/cel/testing/BUILD.bazel | 12 - .../java/dev/cel/testing/EvalSyncTest.java | 185 --- 15 files changed, 817 insertions(+), 1197 deletions(-) create mode 100644 runtime/src/main/java/dev/cel/runtime/HierarchicalVariableResolver.java delete mode 100644 testing/src/main/java/dev/cel/testing/Eval.java delete mode 100644 testing/src/main/java/dev/cel/testing/EvalCelValueSync.java delete mode 100644 testing/src/main/java/dev/cel/testing/EvalSync.java delete mode 100644 testing/src/test/java/dev/cel/testing/EvalSyncTest.java diff --git a/runtime/src/main/java/dev/cel/runtime/BUILD.bazel b/runtime/src/main/java/dev/cel/runtime/BUILD.bazel index 20031fc22..109e13d97 100644 --- a/runtime/src/main/java/dev/cel/runtime/BUILD.bazel +++ b/runtime/src/main/java/dev/cel/runtime/BUILD.bazel @@ -135,6 +135,7 @@ RUNTIME_SOURCES = [ "CelRuntimeLegacyImpl.java", "CelRuntimeLibrary.java", "CelVariableResolver.java", + "HierarchicalVariableResolver.java", "UnknownContext.java", ] diff --git a/runtime/src/main/java/dev/cel/runtime/CelVariableResolver.java b/runtime/src/main/java/dev/cel/runtime/CelVariableResolver.java index ea5cfb4ac..76e6bc76e 100644 --- a/runtime/src/main/java/dev/cel/runtime/CelVariableResolver.java +++ b/runtime/src/main/java/dev/cel/runtime/CelVariableResolver.java @@ -50,9 +50,6 @@ public interface CelVariableResolver { */ static CelVariableResolver hierarchicalVariableResolver( CelVariableResolver primary, CelVariableResolver secondary) { - return (name) -> { - Optional value = primary.find(name); - return value.isPresent() ? value : secondary.find(name); - }; + return HierarchicalVariableResolver.newInstance(primary, secondary); } } diff --git a/runtime/src/main/java/dev/cel/runtime/HierarchicalVariableResolver.java b/runtime/src/main/java/dev/cel/runtime/HierarchicalVariableResolver.java new file mode 100644 index 000000000..5efc4fea4 --- /dev/null +++ b/runtime/src/main/java/dev/cel/runtime/HierarchicalVariableResolver.java @@ -0,0 +1,44 @@ +// Copyright 2024 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.runtime; + +import java.util.Optional; + +final class HierarchicalVariableResolver implements CelVariableResolver { + + private final CelVariableResolver primary; + private final CelVariableResolver secondary; + + @Override + public Optional find(String name) { + Optional value = primary.find(name); + return value.isPresent() ? value : secondary.find(name); + } + + @Override + public String toString() { + return secondary + " +> " + primary; + } + + static HierarchicalVariableResolver newInstance( + CelVariableResolver primary, CelVariableResolver secondary) { + return new HierarchicalVariableResolver(primary, secondary); + } + + private HierarchicalVariableResolver(CelVariableResolver primary, CelVariableResolver secondary) { + this.primary = primary; + this.secondary = secondary; + } +} diff --git a/runtime/src/test/java/dev/cel/runtime/BUILD.bazel b/runtime/src/test/java/dev/cel/runtime/BUILD.bazel index 56e66137c..0cafcda6b 100644 --- a/runtime/src/test/java/dev/cel/runtime/BUILD.bazel +++ b/runtime/src/test/java/dev/cel/runtime/BUILD.bazel @@ -62,11 +62,9 @@ java_library( ], deps = [ # "//java/com/google/testing/testsize:annotations", - "//common:options", "//testing:base_interpreter_test", - "//testing:eval", - "//testing:sync", "@maven//:junit_junit", + "@maven//:com_google_testparameterinjector_test_parameter_injector", ], ) @@ -78,11 +76,9 @@ java_library( ], deps = [ # "//java/com/google/testing/testsize:annotations", - "//common:options", "//testing:base_interpreter_test", - "//testing:cel_value_sync", - "//testing:eval", "@maven//:junit_junit", + "@maven//:com_google_testparameterinjector_test_parameter_injector", ], ) diff --git a/runtime/src/test/java/dev/cel/runtime/CelValueInterpreterTest.java b/runtime/src/test/java/dev/cel/runtime/CelValueInterpreterTest.java index 2ef7a250f..2a7de836d 100644 --- a/runtime/src/test/java/dev/cel/runtime/CelValueInterpreterTest.java +++ b/runtime/src/test/java/dev/cel/runtime/CelValueInterpreterTest.java @@ -14,60 +14,20 @@ package dev.cel.runtime; +import com.google.testing.junit.testparameterinjector.TestParameter; +import com.google.testing.junit.testparameterinjector.TestParameterInjector; // import com.google.testing.testsize.MediumTest; -import dev.cel.common.CelOptions; import dev.cel.testing.BaseInterpreterTest; -import dev.cel.testing.Eval; -import dev.cel.testing.EvalCelValueSync; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; /** Tests for {@link Interpreter} and related functionality using {@code CelValue}. */ // @MediumTest -@RunWith(Parameterized.class) +@RunWith(TestParameterInjector.class) public class CelValueInterpreterTest extends BaseInterpreterTest { - private static final CelOptions SIGNED_UINT_TEST_OPTIONS = - CelOptions.current() - .enableTimestampEpoch(true) - .enableHeterogeneousNumericComparisons(true) - .enableCelValue(true) - .comprehensionMaxIterations(1_000) - .build(); - - public CelValueInterpreterTest(boolean declareWithCelType, Eval eval) { - super(declareWithCelType, eval); - } - - @Parameters - public static List testData() { - return new ArrayList<>( - Arrays.asList( - new Object[][] { - // SYNC_PROTO_TYPE - { - /* declareWithCelType= */ false, - new EvalCelValueSync(TEST_FILE_DESCRIPTORS, TEST_OPTIONS) - }, - // SYNC_PROTO_TYPE_SIGNED_UINT - { - /* declareWithCelType= */ false, - new EvalCelValueSync(TEST_FILE_DESCRIPTORS, SIGNED_UINT_TEST_OPTIONS) - }, - // SYNC_CEL_TYPE - { - /* declareWithCelType= */ true, - new EvalCelValueSync(TEST_FILE_DESCRIPTORS, TEST_OPTIONS) - }, - // SYNC_CEL_TYPE_SIGNED_UINT - { - /* declareWithCelType= */ true, - new EvalCelValueSync(TEST_FILE_DESCRIPTORS, SIGNED_UINT_TEST_OPTIONS) - }, - })); + public CelValueInterpreterTest(@TestParameter InterpreterTestOption testOption) { + super( + testOption.celOptions.toBuilder().enableCelValue(true).build(), + testOption.useNativeCelType); } } diff --git a/runtime/src/test/java/dev/cel/runtime/InterpreterTest.java b/runtime/src/test/java/dev/cel/runtime/InterpreterTest.java index b59c16c28..1f8c18c22 100644 --- a/runtime/src/test/java/dev/cel/runtime/InterpreterTest.java +++ b/runtime/src/test/java/dev/cel/runtime/InterpreterTest.java @@ -14,54 +14,18 @@ package dev.cel.runtime; +import com.google.testing.junit.testparameterinjector.TestParameter; +import com.google.testing.junit.testparameterinjector.TestParameterInjector; // import com.google.testing.testsize.MediumTest; -import dev.cel.common.CelOptions; import dev.cel.testing.BaseInterpreterTest; -import dev.cel.testing.Eval; -import dev.cel.testing.EvalSync; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; /** Tests for {@link Interpreter} and related functionality. */ // @MediumTest -@RunWith(Parameterized.class) +@RunWith(TestParameterInjector.class) public class InterpreterTest extends BaseInterpreterTest { - private static final CelOptions SIGNED_UINT_TEST_OPTIONS = - CelOptions.current() - .enableTimestampEpoch(true) - .enableHeterogeneousNumericComparisons(true) - .comprehensionMaxIterations(1_000) - .build(); - - public InterpreterTest(boolean declareWithCelType, Eval eval) { - super(declareWithCelType, eval); - } - - @Parameters - public static List testData() { - - return new ArrayList<>( - Arrays.asList( - new Object[][] { - // SYNC_PROTO_TYPE - {/* declareWithCelType= */ false, new EvalSync(TEST_FILE_DESCRIPTORS, TEST_OPTIONS)}, - // SYNC_PROTO_TYPE_SIGNED_UINT - { - /* declareWithCelType= */ false, - new EvalSync(TEST_FILE_DESCRIPTORS, SIGNED_UINT_TEST_OPTIONS) - }, - // SYNC_CEL_TYPE - {/* declareWithCelType= */ true, new EvalSync(TEST_FILE_DESCRIPTORS, TEST_OPTIONS)}, - // SYNC_CEL_TYPE_SIGNED_UINT - { - /* declareWithCelType= */ true, - new EvalSync(TEST_FILE_DESCRIPTORS, SIGNED_UINT_TEST_OPTIONS) - }, - })); + public InterpreterTest(@TestParameter InterpreterTestOption testOption) { + super(testOption.celOptions, testOption.useNativeCelType); } } diff --git a/testing/BUILD.bazel b/testing/BUILD.bazel index bd958decc..1370356ba 100644 --- a/testing/BUILD.bazel +++ b/testing/BUILD.bazel @@ -29,21 +29,6 @@ java_library( exports = ["//testing/src/main/java/dev/cel/testing:cel_baseline_test_case"], ) -java_library( - name = "sync", - exports = ["//testing/src/main/java/dev/cel/testing:sync"], -) - -java_library( - name = "cel_value_sync", - exports = ["//testing/src/main/java/dev/cel/testing:cel_value_sync"], -) - -java_library( - name = "eval", - exports = ["//testing/src/main/java/dev/cel/testing:eval"], -) - java_library( name = "base_interpreter_test", exports = ["//testing/src/main/java/dev/cel/testing:base_interpreter_test"], diff --git a/testing/src/main/java/dev/cel/testing/BUILD.bazel b/testing/src/main/java/dev/cel/testing/BUILD.bazel index c708ad57f..5594c37be 100644 --- a/testing/src/main/java/dev/cel/testing/BUILD.bazel +++ b/testing/src/main/java/dev/cel/testing/BUILD.bazel @@ -81,60 +81,6 @@ java_library( ], ) -java_library( - name = "cel_value_sync", - testonly = 1, - srcs = ["EvalCelValueSync.java"], - deps = [ - ":eval", - "//common", - "//common:options", - "//common/internal:cel_descriptor_pools", - "//common/internal:default_message_factory", - "//common/internal:dynamic_proto", - "//common/internal:proto_message_factory", - "//common/values:cel_value_provider", - "//common/values:proto_message_value_provider", - "//runtime:interpreter", - "//runtime:runtime_type_provider_legacy", - "@@protobuf~//java/core", - "@maven//:com_google_guava_guava", - ], -) - -java_library( - name = "sync", - testonly = 1, - srcs = ["EvalSync.java"], - deps = [ - ":eval", - "//common", - "//common:options", - "//common/internal:cel_descriptor_pools", - "//common/internal:default_message_factory", - "//runtime:interpreter", - "@@protobuf~//java/core", - "@maven//:com_google_guava_guava", - ], -) - -java_library( - name = "eval", - testonly = 1, - srcs = [ - "Eval.java", - ], - deps = [ - "//common", - "//common:options", - "//runtime:base", - "//runtime:interpreter", - "@@protobuf~//java/core", - "@maven//:com_google_errorprone_error_prone_annotations", - "@maven//:com_google_guava_guava", - ], -) - java_library( name = "base_interpreter_test", testonly = 1, @@ -147,18 +93,18 @@ java_library( ], deps = [ ":cel_baseline_test_case", - ":eval", "//:java_truth", "//common", + "//common:options", "//common/internal:cel_descriptor_pools", "//common/internal:file_descriptor_converter", "//common/resources/testdata/proto3:standalone_global_enum_java_proto", "//common/types:cel_types", - "//runtime:interpreter", + "//runtime", + "//runtime:runtime_helper", "@@protobuf~//java/core", "@cel_spec//proto/cel/expr:expr_java_proto", "@cel_spec//proto/test/v1/proto3:test_all_types_java_proto", - "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java_util", "@maven//:junit_junit", diff --git a/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java b/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java index 54fbe3382..edcf5a260 100644 --- a/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java +++ b/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java @@ -16,6 +16,7 @@ import static com.google.common.collect.ImmutableList.toImmutableList; import static com.google.common.truth.Truth.assertThat; +import static dev.cel.runtime.CelVariableResolver.hierarchicalVariableResolver; import static java.nio.charset.StandardCharsets.UTF_8; import dev.cel.expr.CheckedExpr; @@ -32,10 +33,10 @@ import com.google.common.collect.ImmutableSet; import com.google.common.io.Resources; import com.google.common.primitives.UnsignedLong; -import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.protobuf.Any; import com.google.protobuf.BoolValue; import com.google.protobuf.ByteString; +import com.google.protobuf.ByteString.ByteIterator; import com.google.protobuf.BytesValue; import com.google.protobuf.DescriptorProtos.FileDescriptorSet; import com.google.protobuf.Descriptors.Descriptor; @@ -47,6 +48,7 @@ import com.google.protobuf.Int32Value; import com.google.protobuf.Int64Value; import com.google.protobuf.ListValue; +import com.google.protobuf.Message; import com.google.protobuf.NullValue; import com.google.protobuf.StringValue; import com.google.protobuf.Struct; @@ -59,24 +61,55 @@ import com.google.protobuf.util.JsonFormat; import com.google.protobuf.util.Timestamps; import dev.cel.common.CelAbstractSyntaxTree; +import dev.cel.common.CelOptions; import dev.cel.common.CelProtoAbstractSyntaxTree; import dev.cel.common.internal.DefaultDescriptorPool; import dev.cel.common.internal.FileDescriptorSetConverter; import dev.cel.common.types.CelTypes; -import dev.cel.runtime.Activation; -import dev.cel.runtime.InterpreterException; +import dev.cel.runtime.CelEvaluationException; +import dev.cel.runtime.CelRuntime; +import dev.cel.runtime.CelRuntime.CelFunctionBinding; +import dev.cel.runtime.CelRuntimeFactory; +import dev.cel.runtime.CelVariableResolver; +import dev.cel.runtime.RuntimeHelpers; import dev.cel.testing.testdata.proto3.StandaloneGlobalEnum; import java.io.IOException; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.stream.LongStream; import org.junit.Test; /** Base class for evaluation outputs that can be stored and used as a baseline test. */ public abstract class BaseInterpreterTest extends CelBaselineTestCase { + private static CelOptions.Builder newBaseOptions() { + return CelOptions.current() + .enableTimestampEpoch(true) + .enableHeterogeneousNumericComparisons(true) + .enableOptionalSyntax(true) + .comprehensionMaxIterations(1_000); + } + + /** Test options to supply for interpreter tests. */ + protected enum InterpreterTestOption { + CEL_TYPE_SIGNED_UINT(newBaseOptions().enableUnsignedLongs(false).build(), true), + CEL_TYPE_UNSIGNED_UINT(newBaseOptions().enableUnsignedLongs(true).build(), true), + PROTO_TYPE_SIGNED_UINT(newBaseOptions().enableUnsignedLongs(false).build(), false), + PROTO_TYPE_UNSIGNED_UINT(newBaseOptions().enableUnsignedLongs(true).build(), false), + ; + + public final CelOptions celOptions; + public final boolean useNativeCelType; + + InterpreterTestOption(CelOptions celOptions, boolean useNativeCelType) { + this.celOptions = celOptions; + this.useNativeCelType = useNativeCelType; + } + } + protected static final Descriptor TEST_ALL_TYPE_DYNAMIC_DESCRIPTOR = getDeserializedTestAllTypeDescriptor(); @@ -86,187 +119,188 @@ public abstract class BaseInterpreterTest extends CelBaselineTestCase { StandaloneGlobalEnum.getDescriptor().getFile(), TEST_ALL_TYPE_DYNAMIC_DESCRIPTOR.getFile()); - private final Eval eval; + private final CelOptions celOptions; + private CelRuntime celRuntime; - private static Descriptor getDeserializedTestAllTypeDescriptor() { - try { - String fdsContent = readResourceContent("testdata/proto3/test_all_types.fds"); - FileDescriptorSet fds = TextFormat.parse(fdsContent, FileDescriptorSet.class); - ImmutableSet fileDescriptors = FileDescriptorSetConverter.convert(fds); + public BaseInterpreterTest(CelOptions celOptions, boolean useNativeCelType) { + super(useNativeCelType); + this.celOptions = celOptions; + this.celRuntime = + CelRuntimeFactory.standardCelRuntimeBuilder() + .addFileTypes(TEST_FILE_DESCRIPTORS) + .setOptions(celOptions) + .build(); + } - return fileDescriptors.stream() - .flatMap(f -> f.getMessageTypes().stream()) - .filter( - x -> - x.getFullName().equals("dev.cel.testing.testdata.serialized.proto3.TestAllTypes")) - .findAny() - .orElseThrow( - () -> - new IllegalStateException( - "Could not find deserialized TestAllTypes descriptor.")); - } catch (IOException e) { - throw new RuntimeException("Error loading TestAllTypes descriptor", e); + private CelAbstractSyntaxTree compileTestCase() { + CelAbstractSyntaxTree ast = prepareTest(TEST_FILE_DESCRIPTORS); + if (ast == null) { + return ast; } + assertAstRoundTrip(ast); + + return ast; + } + + private Object runTest() { + return runTest(ImmutableMap.of()); } - public BaseInterpreterTest(boolean declareWithCelType, Eval eval) { - super(declareWithCelType); - this.eval = eval; + private Object runTest(CelVariableResolver variableResolver) { + return runTestInternal(variableResolver); } /** Helper to run a test for configured instance variables. */ - @CanIgnoreReturnValue // Test generates a file to diff against baseline. Ignoring Intermediary - // evaluation is not a concern. - private Object runTest(Activation activation) throws Exception { - CelAbstractSyntaxTree ast = prepareTest(eval.fileDescriptors()); - if (ast == null) { - return null; - } - assertAstRoundTrip(ast); + private Object runTest(Map input) { + return runTestInternal(input); + } - testOutput().println("bindings: " + activation); + /** + * Helper to run a test for configured instance variables. Input must be of type map or {@link + * CelVariableResolver}. + */ + @SuppressWarnings("unchecked") + private Object runTestInternal(Object input) { + CelAbstractSyntaxTree ast = compileTestCase(); + printBinding(input); Object result = null; try { - result = eval.eval(ast, activation); + CelRuntime.Program program = celRuntime.createProgram(ast); + result = + input instanceof Map + ? program.eval(((Map) input)) + : program.eval((CelVariableResolver) input); if (result instanceof ByteString) { // Note: this call may fail for printing byte sequences that are not valid UTF-8, but works // pretty well for test purposes. result = ((ByteString) result).toStringUtf8(); } - testOutput().println("result: " + result); - } catch (InterpreterException e) { - testOutput().println("error: " + e.getMessage()); - testOutput().println("error_code: " + e.getErrorCode()); + println("result: " + result); + } catch (CelEvaluationException e) { + println("error: " + e.getMessage()); + println("error_code: " + e.getErrorCode()); } - testOutput().println(); + println(""); return result; } - /** - * Checks that the CheckedExpr produced by CelCompiler is equal to the one reproduced by the - * native CelAbstractSyntaxTree - */ - private void assertAstRoundTrip(CelAbstractSyntaxTree ast) { - CheckedExpr checkedExpr = CelProtoAbstractSyntaxTree.fromCelAst(ast).toCheckedExpr(); - CelProtoAbstractSyntaxTree protoAst = CelProtoAbstractSyntaxTree.fromCelAst(ast); - assertThat(checkedExpr).isEqualTo(protoAst.toCheckedExpr()); - } - @Test - public void arithmInt64() throws Exception { + public void arithmInt64() { source = "1 < 2 && 1 <= 1 && 2 > 1 && 1 >= 1 && 1 == 1 && 2 != 1"; - runTest(Activation.EMPTY); + runTest(); declareVariable("x", CelTypes.INT64); source = "1 + 2 - x * 3 / x + (x % 3)"; - runTest(Activation.of("x", -5L)); + runTest(ImmutableMap.of("x", -5L)); declareVariable("y", CelTypes.DYN); source = "x + y == 1"; - runTest(Activation.of("x", -5L).extend(Activation.of("y", 6))); + runTest(extend(ImmutableMap.of("x", -5L), ImmutableMap.of("y", 6))); } @Test - public void arithmInt64_error() throws Exception { + public void arithmInt64_error() { source = "9223372036854775807 + 1"; - runTest(Activation.EMPTY); + runTest(); source = "-9223372036854775808 - 1"; - runTest(Activation.EMPTY); + runTest(); source = "-(-9223372036854775808)"; - runTest(Activation.EMPTY); + runTest(); source = "5000000000 * 5000000000"; - runTest(Activation.EMPTY); + runTest(); source = "(-9223372036854775808)/-1"; - runTest(Activation.EMPTY); + runTest(); source = "1 / 0"; - runTest(Activation.EMPTY); + runTest(); source = "1 % 0"; - runTest(Activation.EMPTY); + runTest(); } @Test - public void arithmUInt64() throws Exception { + public void arithmUInt64() { source = "1u < 2u && 1u <= 1u && 2u > 1u && 1u >= 1u && 1u == 1u && 2u != 1u"; - runTest(Activation.EMPTY); + runTest(); - boolean useUnsignedLongs = eval.celOptions().enableUnsignedLongs(); + boolean useUnsignedLongs = celOptions.enableUnsignedLongs(); declareVariable("x", CelTypes.UINT64); source = "1u + 2u + x * 3u / x + (x % 3u)"; - runTest(Activation.of("x", useUnsignedLongs ? UnsignedLong.valueOf(5L) : 5L)); + runTest(ImmutableMap.of("x", useUnsignedLongs ? UnsignedLong.valueOf(5L) : 5L)); declareVariable("y", CelTypes.DYN); source = "x + y == 11u"; runTest( - Activation.of("x", useUnsignedLongs ? UnsignedLong.valueOf(5L) : 5L) - .extend(Activation.of("y", useUnsignedLongs ? UnsignedLong.valueOf(6L) : 6))); + extend( + ImmutableMap.of("x", useUnsignedLongs ? UnsignedLong.valueOf(5L) : 5L), + ImmutableMap.of("y", useUnsignedLongs ? UnsignedLong.valueOf(6L) : 6))); source = "x - y == 1u"; runTest( - Activation.of("x", useUnsignedLongs ? UnsignedLong.valueOf(6L) : 6L) - .extend(Activation.of("y", useUnsignedLongs ? UnsignedLong.valueOf(5) : 5))); + extend( + ImmutableMap.of("x", useUnsignedLongs ? UnsignedLong.valueOf(6L) : 6L), + ImmutableMap.of("y", useUnsignedLongs ? UnsignedLong.valueOf(5) : 5))); } @Test - public void arithmUInt64_error() throws Exception { + public void arithmUInt64_error() { source = "18446744073709551615u + 1u"; - runTest(Activation.EMPTY); + runTest(); source = "0u - 1u"; - runTest(Activation.EMPTY); + runTest(); source = "5000000000u * 5000000000u"; - runTest(Activation.EMPTY); + runTest(); source = "1u / 0u"; - runTest(Activation.EMPTY); + runTest(); source = "1u % 0u"; - runTest(Activation.EMPTY); + runTest(); } @Test - public void arithmDouble() throws Exception { + public void arithmDouble() { source = "1.9 < 2.0 && 1.1 <= 1.1 && 2.0 > 1.9 && 1.1 >= 1.1 && 1.1 == 1.1 && 2.0 != 1.9"; - runTest(Activation.EMPTY); + runTest(); declareVariable("x", CelTypes.DOUBLE); source = "1.0 + 2.3 + x * 3.0 / x"; - runTest(Activation.of("x", 3.33)); + runTest(ImmutableMap.of("x", 3.33)); declareVariable("y", CelTypes.DYN); source = "x + y == 9.99"; - runTest(Activation.of("x", 3.33d).extend(Activation.of("y", 6.66))); + runTest(extend(ImmutableMap.of("x", 3.33d), ImmutableMap.of("y", 6.66))); } @Test - public void quantifiers() throws Exception { + public void quantifiers() { source = "[1,-2,3].exists_one(x, x > 0)"; - runTest(Activation.EMPTY); + runTest(); source = "[-1,-2,3].exists_one(x, x > 0)"; - runTest(Activation.EMPTY); + runTest(); source = "[-1,-2,-3].exists(x, x > 0)"; - runTest(Activation.EMPTY); + runTest(); source = "[1,-2,3].exists(x, x > 0)"; - runTest(Activation.EMPTY); + runTest(); source = "[1,-2,3].all(x, x > 0)"; - runTest(Activation.EMPTY); + runTest(); source = "[1,2,3].all(x, x > 0)"; - runTest(Activation.EMPTY); + runTest(); } @Test - public void arithmTimestamp() throws Exception { + public void arithmTimestamp() { container = Type.getDescriptor().getFile().getPackage(); declareVariable("ts1", CelTypes.TIMESTAMP); declareVariable("ts2", CelTypes.TIMESTAMP); @@ -274,24 +308,26 @@ public void arithmTimestamp() throws Exception { Duration d1 = Duration.newBuilder().setSeconds(15).setNanos(25).build(); Timestamp ts1 = Timestamp.newBuilder().setSeconds(25).setNanos(35).build(); Timestamp ts2 = Timestamp.newBuilder().setSeconds(10).setNanos(10).build(); - Activation activation = - Activation.of("d1", d1).extend(Activation.of("ts1", ts1)).extend(Activation.of("ts2", ts2)); + CelVariableResolver resolver = + extend( + extend(ImmutableMap.of("d1", d1), ImmutableMap.of("ts1", ts1)), + ImmutableMap.of("ts2", ts2)); source = "ts1 - ts2 == d1"; - runTest(activation); + runTest(resolver); source = "ts1 - d1 == ts2"; - runTest(activation); + runTest(resolver); source = "ts2 + d1 == ts1"; - runTest(activation); + runTest(resolver); source = "d1 + ts2 == ts1"; - runTest(activation); + runTest(resolver); } @Test - public void arithmDuration() throws Exception { + public void arithmDuration() { container = Type.getDescriptor().getFile().getPackage(); declareVariable("d1", CelTypes.DURATION); declareVariable("d2", CelTypes.DURATION); @@ -299,120 +335,123 @@ public void arithmDuration() throws Exception { Duration d1 = Duration.newBuilder().setSeconds(15).setNanos(25).build(); Duration d2 = Duration.newBuilder().setSeconds(10).setNanos(20).build(); Duration d3 = Duration.newBuilder().setSeconds(25).setNanos(45).build(); - Activation activation = - Activation.of("d1", d1).extend(Activation.of("d2", d2)).extend(Activation.of("d3", d3)); + + CelVariableResolver resolver = + extend( + extend(ImmutableMap.of("d1", d1), ImmutableMap.of("d2", d2)), + ImmutableMap.of("d3", d3)); source = "d1 + d2 == d3"; - runTest(activation); + runTest(resolver); source = "d3 - d1 == d2"; - runTest(activation); + runTest(resolver); } @Test - public void arithCrossNumericTypes() throws Exception { - if (!eval.celOptions().enableUnsignedLongs()) { + public void arithCrossNumericTypes() { + if (!celOptions.enableUnsignedLongs()) { skipBaselineVerification(); return; } source = "1.9 < 2 && 1 < 1.1 && 2u < 2.9 && 1.1 < 2u && 1 < 2u && 2u < 3"; - runTest(Activation.EMPTY); + runTest(); source = "1.9 <= 2 && 1 <= 1.1 && 2u <= 2.9 && 1.1 <= 2u && 2 <= 2u && 2u <= 2"; - runTest(Activation.EMPTY); + runTest(); source = "1.9 > 2 && 1 > 1.1 && 2u > 2.9 && 1.1 > 2u && 2 > 2u && 2u > 2"; - runTest(Activation.EMPTY); + runTest(); source = "1.9 >= 2 && 1 >= 1.1 && 2u >= 2.9 && 1.1 >= 2u && 2 >= 2u && 2u >= 2"; - runTest(Activation.EMPTY); + runTest(); } @Test - public void booleans() throws Exception { + public void booleans() { declareVariable("x", CelTypes.BOOL); source = "x ? 1 : 0"; - runTest(Activation.of("x", true)); - runTest(Activation.of("x", false)); + runTest(ImmutableMap.of("x", true)); + runTest(ImmutableMap.of("x", false)); source = "(1 / 0 == 0 && false) == (false && 1 / 0 == 0)"; - runTest(Activation.EMPTY); + runTest(); source = "(1 / 0 == 0 || true) == (true || 1 / 0 == 0)"; - runTest(Activation.EMPTY); + runTest(); declareVariable("y", CelTypes.INT64); source = "1 / y == 1 || true"; - runTest(Activation.of("y", 0L)); + runTest(ImmutableMap.of("y", 0L)); source = "1 / y == 1 || false"; - runTest(Activation.of("y", 0L)); + runTest(ImmutableMap.of("y", 0L)); source = "false || 1 / y == 1"; - runTest(Activation.of("y", 0L)); + runTest(ImmutableMap.of("y", 0L)); source = "1 / y == 1 && true"; - runTest(Activation.of("y", 0L)); + runTest(ImmutableMap.of("y", 0L)); source = "true && 1 / y == 1"; - runTest(Activation.of("y", 0L)); + runTest(ImmutableMap.of("y", 0L)); source = "1 / y == 1 && false"; - runTest(Activation.of("y", 0L)); + runTest(ImmutableMap.of("y", 0L)); source = "(true > false) == true"; - runTest(Activation.EMPTY); + runTest(); source = "(true > true) == false"; - runTest(Activation.EMPTY); + runTest(); source = "(false > true) == false"; - runTest(Activation.EMPTY); + runTest(); source = "(false > false) == false"; - runTest(Activation.EMPTY); + runTest(); source = "(true >= false) == true"; - runTest(Activation.EMPTY); + runTest(); source = "(true >= true) == true"; - runTest(Activation.EMPTY); + runTest(); source = "(false >= false) == true"; - runTest(Activation.EMPTY); + runTest(); source = "(false >= true) == false"; - runTest(Activation.EMPTY); + runTest(); source = "(false < true) == true"; - runTest(Activation.EMPTY); + runTest(); source = "(false < false) == false"; - runTest(Activation.EMPTY); + runTest(); source = "(true < false) == false"; - runTest(Activation.EMPTY); + runTest(); source = "(true < true) == false"; - runTest(Activation.EMPTY); + runTest(); source = "(false <= true) == true"; - runTest(Activation.EMPTY); + runTest(); source = "(false <= false) == true"; - runTest(Activation.EMPTY); + runTest(); source = "(true <= false) == false"; - runTest(Activation.EMPTY); + runTest(); source = "(true <= true) == true"; - runTest(Activation.EMPTY); + runTest(); } @Test public void strings() throws Exception { source = "'a' < 'b' && 'a' <= 'b' && 'b' > 'a' && 'a' >= 'a' && 'a' == 'a' && 'a' != 'b'"; - runTest(Activation.EMPTY); + runTest(); declareVariable("x", CelTypes.STRING); source = @@ -421,7 +460,7 @@ public void strings() throws Exception { + "x.startsWith('d') && " + "x.contains('de') && " + "!x.contains('abcdef')"; - runTest(Activation.of("x", "def")); + runTest(ImmutableMap.of("x", "def")); } @Test @@ -432,27 +471,27 @@ public void messages() throws Exception { .build(); declareVariable("x", CelTypes.createMessage(TestAllTypes.getDescriptor().getFullName())); source = "x.single_nested_message.bb == 43 && has(x.single_nested_message)"; - runTest(Activation.of("x", nestedMessage)); + runTest(ImmutableMap.of("x", nestedMessage)); declareVariable( "single_nested_message", CelTypes.createMessage(NestedMessage.getDescriptor().getFullName())); source = "single_nested_message.bb == 43"; - runTest(Activation.of("single_nested_message", nestedMessage.getSingleNestedMessage())); + runTest(ImmutableMap.of("single_nested_message", nestedMessage.getSingleNestedMessage())); source = "TestAllTypes{single_int64: 1, single_sfixed64: 2, single_int32: 2}.single_int32 == 2"; container = TestAllTypes.getDescriptor().getFile().getPackage(); - runTest(Activation.EMPTY); + runTest(); } @Test - public void messages_error() throws Exception { + public void messages_error() { source = "TestAllTypes{single_int32_wrapper: 12345678900}"; container = TestAllTypes.getDescriptor().getFile().getPackage(); - runTest(Activation.EMPTY); + runTest(); source = "TestAllTypes{}.map_string_string.a"; - runTest(Activation.EMPTY); + runTest(); } @Test @@ -478,7 +517,7 @@ public void has() throws Exception { + " && has(x.oneof_bool) && !has(x.oneof_type)" + " && has(x.map_int32_int64) && !has(x.map_string_string)" + " && has(x.single_nested_message) && !has(x.single_duration)"; - runTest(Activation.of("x", nestedMessage)); + runTest(ImmutableMap.of("x", nestedMessage)); } @Test @@ -491,32 +530,32 @@ public void duration() throws Exception { container = Type.getDescriptor().getFile().getPackage(); source = "d1 < d2"; - runTest(Activation.of("d1", d1010).extend(Activation.of("d2", d1009))); - runTest(Activation.of("d1", d1010).extend(Activation.of("d2", d0910))); - runTest(Activation.of("d1", d1010).extend(Activation.of("d2", d1010))); - runTest(Activation.of("d1", d1009).extend(Activation.of("d2", d1010))); - runTest(Activation.of("d1", d0910).extend(Activation.of("d2", d1010))); + runTest(extend(ImmutableMap.of("d1", d1010), ImmutableMap.of("d2", d1009))); + runTest(extend(ImmutableMap.of("d1", d1010), ImmutableMap.of("d2", d0910))); + runTest(extend(ImmutableMap.of("d1", d1010), ImmutableMap.of("d2", d1010))); + runTest(extend(ImmutableMap.of("d1", d1009), ImmutableMap.of("d2", d1010))); + runTest(extend(ImmutableMap.of("d1", d0910), ImmutableMap.of("d2", d1010))); source = "d1 <= d2"; - runTest(Activation.of("d1", d1010).extend(Activation.of("d2", d1009))); - runTest(Activation.of("d1", d1010).extend(Activation.of("d2", d0910))); - runTest(Activation.of("d1", d1010).extend(Activation.of("d2", d1010))); - runTest(Activation.of("d1", d1009).extend(Activation.of("d2", d1010))); - runTest(Activation.of("d1", d0910).extend(Activation.of("d2", d1010))); + runTest(extend(ImmutableMap.of("d1", d1010), ImmutableMap.of("d2", d1009))); + runTest(extend(ImmutableMap.of("d1", d1010), ImmutableMap.of("d2", d0910))); + runTest(extend(ImmutableMap.of("d1", d1010), ImmutableMap.of("d2", d1010))); + runTest(extend(ImmutableMap.of("d1", d1009), ImmutableMap.of("d2", d1010))); + runTest(extend(ImmutableMap.of("d1", d0910), ImmutableMap.of("d2", d1010))); source = "d1 > d2"; - runTest(Activation.of("d1", d1010).extend(Activation.of("d2", d1009))); - runTest(Activation.of("d1", d1010).extend(Activation.of("d2", d0910))); - runTest(Activation.of("d1", d1010).extend(Activation.of("d2", d1010))); - runTest(Activation.of("d1", d1009).extend(Activation.of("d2", d1010))); - runTest(Activation.of("d1", d0910).extend(Activation.of("d2", d1010))); + runTest(extend(ImmutableMap.of("d1", d1010), ImmutableMap.of("d2", d1009))); + runTest(extend(ImmutableMap.of("d1", d1010), ImmutableMap.of("d2", d0910))); + runTest(extend(ImmutableMap.of("d1", d1010), ImmutableMap.of("d2", d1010))); + runTest(extend(ImmutableMap.of("d1", d1009), ImmutableMap.of("d2", d1010))); + runTest(extend(ImmutableMap.of("d1", d0910), ImmutableMap.of("d2", d1010))); source = "d1 >= d2"; - runTest(Activation.of("d1", d1010).extend(Activation.of("d2", d1009))); - runTest(Activation.of("d1", d1010).extend(Activation.of("d2", d0910))); - runTest(Activation.of("d1", d1010).extend(Activation.of("d2", d1010))); - runTest(Activation.of("d1", d1009).extend(Activation.of("d2", d1010))); - runTest(Activation.of("d1", d0910).extend(Activation.of("d2", d1010))); + runTest(extend(ImmutableMap.of("d1", d1010), ImmutableMap.of("d2", d1009))); + runTest(extend(ImmutableMap.of("d1", d1010), ImmutableMap.of("d2", d0910))); + runTest(extend(ImmutableMap.of("d1", d1010), ImmutableMap.of("d2", d1010))); + runTest(extend(ImmutableMap.of("d1", d1009), ImmutableMap.of("d2", d1010))); + runTest(extend(ImmutableMap.of("d1", d0910), ImmutableMap.of("d2", d1010))); } @Test @@ -529,39 +568,38 @@ public void timestamp() throws Exception { container = Type.getDescriptor().getFile().getPackage(); source = "t1 < t2"; - runTest(Activation.of("t1", ts1010).extend(Activation.of("t2", ts1009))); - runTest(Activation.of("t1", ts1010).extend(Activation.of("t2", ts0910))); - runTest(Activation.of("t1", ts1010).extend(Activation.of("t2", ts1010))); - runTest(Activation.of("t1", ts1009).extend(Activation.of("t2", ts1010))); - runTest(Activation.of("t1", ts0910).extend(Activation.of("t2", ts1010))); + runTest(extend(ImmutableMap.of("t1", ts1010), ImmutableMap.of("t2", ts1009))); + runTest(extend(ImmutableMap.of("t1", ts1010), ImmutableMap.of("t2", ts0910))); + runTest(extend(ImmutableMap.of("t1", ts1010), ImmutableMap.of("t2", ts1010))); + runTest(extend(ImmutableMap.of("t1", ts1009), ImmutableMap.of("t2", ts1010))); + runTest(extend(ImmutableMap.of("t1", ts0910), ImmutableMap.of("t2", ts1010))); source = "t1 <= t2"; - runTest(Activation.of("t1", ts1010).extend(Activation.of("t2", ts1009))); - runTest(Activation.of("t1", ts1010).extend(Activation.of("t2", ts0910))); - runTest(Activation.of("t1", ts1010).extend(Activation.of("t2", ts1010))); - runTest(Activation.of("t1", ts1009).extend(Activation.of("t2", ts1010))); - runTest(Activation.of("t1", ts0910).extend(Activation.of("t2", ts1010))); + runTest(extend(ImmutableMap.of("t1", ts1010), ImmutableMap.of("t2", ts1009))); + runTest(extend(ImmutableMap.of("t1", ts1010), ImmutableMap.of("t2", ts0910))); + runTest(extend(ImmutableMap.of("t1", ts1010), ImmutableMap.of("t2", ts1010))); + runTest(extend(ImmutableMap.of("t1", ts1009), ImmutableMap.of("t2", ts1010))); + runTest(extend(ImmutableMap.of("t1", ts0910), ImmutableMap.of("t2", ts1010))); source = "t1 > t2"; - runTest(Activation.of("t1", ts1010).extend(Activation.of("t2", ts1009))); - runTest(Activation.of("t1", ts1010).extend(Activation.of("t2", ts0910))); - runTest(Activation.of("t1", ts1010).extend(Activation.of("t2", ts1010))); - runTest(Activation.of("t1", ts1009).extend(Activation.of("t2", ts1010))); - runTest(Activation.of("t1", ts0910).extend(Activation.of("t2", ts1010))); + runTest(extend(ImmutableMap.of("t1", ts1010), ImmutableMap.of("t2", ts1009))); + runTest(extend(ImmutableMap.of("t1", ts1010), ImmutableMap.of("t2", ts0910))); + runTest(extend(ImmutableMap.of("t1", ts1010), ImmutableMap.of("t2", ts1010))); + runTest(extend(ImmutableMap.of("t1", ts1009), ImmutableMap.of("t2", ts1010))); + runTest(extend(ImmutableMap.of("t1", ts0910), ImmutableMap.of("t2", ts1010))); source = "t1 >= t2"; - runTest(Activation.of("t1", ts1010).extend(Activation.of("t2", ts1009))); - runTest(Activation.of("t1", ts1010).extend(Activation.of("t2", ts0910))); - runTest(Activation.of("t1", ts1010).extend(Activation.of("t2", ts1010))); - runTest(Activation.of("t1", ts1009).extend(Activation.of("t2", ts1010))); - runTest(Activation.of("t1", ts0910).extend(Activation.of("t2", ts1010))); + runTest(extend(ImmutableMap.of("t1", ts1010), ImmutableMap.of("t2", ts1009))); + runTest(extend(ImmutableMap.of("t1", ts1010), ImmutableMap.of("t2", ts0910))); + runTest(extend(ImmutableMap.of("t1", ts1010), ImmutableMap.of("t2", ts1010))); + runTest(extend(ImmutableMap.of("t1", ts1009), ImmutableMap.of("t2", ts1010))); + runTest(extend(ImmutableMap.of("t1", ts0910), ImmutableMap.of("t2", ts1010))); } @Test - // TODO: Support JSON type pack/unpack google.protobuf.Any. - public void packUnpackAny() throws Exception { + public void packUnpackAny() { // The use of long values results in the incorrect type being serialized for a uint value. - if (!eval.celOptions().enableUnsignedLongs()) { + if (!celOptions.enableUnsignedLongs()) { skipBaselineVerification(); return; } @@ -576,62 +614,60 @@ public void packUnpackAny() throws Exception { // unpack any source = "any == d"; - runTest(Activation.of("any", any).extend(Activation.of("d", duration))); + runTest(extend(ImmutableMap.of("any", any), ImmutableMap.of("d", duration))); source = "any == message.single_any"; - runTest(Activation.of("any", any).extend(Activation.of("message", message))); + runTest(extend(ImmutableMap.of("any", any), ImmutableMap.of("message", message))); source = "d == message.single_any"; - runTest(Activation.of("d", duration).extend(Activation.of("message", message))); + runTest(extend(ImmutableMap.of("d", duration), ImmutableMap.of("message", message))); source = "any.single_int64 == 1"; - runTest(Activation.of("any", TestAllTypes.newBuilder().setSingleInt64(1).build())); + runTest(ImmutableMap.of("any", TestAllTypes.newBuilder().setSingleInt64(1).build())); source = "any == 1"; - runTest(Activation.of("any", Any.pack(Int64Value.of(1)))); + runTest(ImmutableMap.of("any", Any.pack(Int64Value.of(1)))); source = "list[0] == message"; - runTest( - Activation.copyOf( - ImmutableMap.of("list", ImmutableList.of(Any.pack(message)), "message", message))); + runTest(ImmutableMap.of("list", ImmutableList.of(Any.pack(message)), "message", message)); // pack any source = "TestAllTypes{single_any: d}"; - runTest(Activation.of("d", duration)); + runTest(ImmutableMap.of("d", duration)); source = "TestAllTypes{single_any: message.single_int64}"; - runTest(Activation.of("message", TestAllTypes.newBuilder().setSingleInt64(-1).build())); + runTest(ImmutableMap.of("message", TestAllTypes.newBuilder().setSingleInt64(-1).build())); source = "TestAllTypes{single_any: message.single_uint64}"; - runTest(Activation.of("message", TestAllTypes.newBuilder().setSingleUint64(1).build())); + runTest(ImmutableMap.of("message", TestAllTypes.newBuilder().setSingleUint64(1).build())); source = "TestAllTypes{single_any: 1.0}"; - runTest(Activation.EMPTY); + runTest(); source = "TestAllTypes{single_any: true}"; - runTest(Activation.EMPTY); + runTest(); source = "TestAllTypes{single_any: \"happy\"}"; - runTest(Activation.EMPTY); + runTest(); source = "TestAllTypes{single_any: message.single_bytes}"; runTest( - Activation.of( + ImmutableMap.of( "message", TestAllTypes.newBuilder().setSingleBytes(ByteString.copyFromUtf8("happy")).build())); } @Test - public void nestedEnums() throws Exception { + public void nestedEnums() { TestAllTypes nestedEnum = TestAllTypes.newBuilder().setSingleNestedEnum(NestedEnum.BAR).build(); declareVariable("x", CelTypes.createMessage(TestAllTypes.getDescriptor().getFullName())); container = TestAllTypes.getDescriptor().getFile().getPackage(); source = "x.single_nested_enum == TestAllTypes.NestedEnum.BAR"; - runTest(Activation.of("x", nestedEnum)); + runTest(ImmutableMap.of("x", nestedEnum)); declareVariable("single_nested_enum", CelTypes.INT64); source = "single_nested_enum == TestAllTypes.NestedEnum.BAR"; - runTest(Activation.of("single_nested_enum", nestedEnum.getSingleNestedEnumValue())); + runTest(ImmutableMap.of("single_nested_enum", nestedEnum.getSingleNestedEnumValue())); source = "TestAllTypes{single_nested_enum : TestAllTypes.NestedEnum.BAR}.single_nested_enum == 1"; - runTest(Activation.EMPTY); + runTest(); } @Test - public void globalEnums() throws Exception { + public void globalEnums() { declareVariable("x", CelTypes.INT64); source = "x == dev.cel.testing.testdata.proto3.StandaloneGlobalEnum.SGAR"; - runTest(Activation.of("x", StandaloneGlobalEnum.SGAR.getNumber())); + runTest(ImmutableMap.of("x", StandaloneGlobalEnum.SGAR.getNumber())); } @Test @@ -640,33 +676,33 @@ public void lists() throws Exception { declareVariable("y", CelTypes.INT64); container = TestAllTypes.getDescriptor().getFile().getPackage(); source = "([1, 2, 3] + x.repeated_int32)[3] == 4"; - runTest(Activation.of("x", TestAllTypes.newBuilder().addRepeatedInt32(4).build())); + runTest(ImmutableMap.of("x", TestAllTypes.newBuilder().addRepeatedInt32(4).build())); source = "!(y in [1, 2, 3]) && y in [4, 5, 6]"; - runTest(Activation.of("y", 4L)); + runTest(ImmutableMap.of("y", 4L)); source = "TestAllTypes{repeated_int32: [1,2]}.repeated_int32[1] == 2"; - runTest(Activation.EMPTY); + runTest(); source = "1 in TestAllTypes{repeated_int32: [1,2]}.repeated_int32"; - runTest(Activation.EMPTY); + runTest(); source = "!(4 in [1, 2, 3]) && 1 in [1, 2, 3]"; - runTest(Activation.EMPTY); + runTest(); declareVariable("list", CelTypes.createList(CelTypes.INT64)); source = "!(4 in list) && 1 in list"; - runTest(Activation.of("list", ImmutableList.of(1L, 2L, 3L))); + runTest(ImmutableMap.of("list", ImmutableList.of(1L, 2L, 3L))); source = "!(y in list)"; - runTest(Activation.copyOf(ImmutableMap.of("y", 4L, "list", ImmutableList.of(1L, 2L, 3L)))); + runTest(ImmutableMap.of("y", 4L, "list", ImmutableList.of(1L, 2L, 3L))); source = "y in list"; - runTest(Activation.copyOf(ImmutableMap.of("y", 1L, "list", ImmutableList.of(1L, 2L, 3L)))); + runTest(ImmutableMap.of("y", 1L, "list", ImmutableList.of(1L, 2L, 3L))); source = "list[3]"; - runTest(Activation.copyOf(ImmutableMap.of("y", 1L, "list", ImmutableList.of(1L, 2L, 3L)))); + runTest(ImmutableMap.of("y", 1L, "list", ImmutableList.of(1L, 2L, 3L))); } @Test @@ -674,68 +710,66 @@ public void maps() throws Exception { declareVariable("x", CelTypes.createMessage(TestAllTypes.getDescriptor().getFullName())); container = TestAllTypes.getDescriptor().getFile().getPackage(); source = "{1: 2, 3: 4}[3] == 4"; - runTest(Activation.EMPTY); + runTest(); // Constant key in constant map. source = "3 in {1: 2, 3: 4} && !(4 in {1: 2, 3: 4})"; - runTest(Activation.EMPTY); + runTest(); source = "x.map_int32_int64[22] == 23"; - runTest(Activation.of("x", TestAllTypes.newBuilder().putMapInt32Int64(22, 23).build())); + runTest(ImmutableMap.of("x", TestAllTypes.newBuilder().putMapInt32Int64(22, 23).build())); source = "TestAllTypes{map_int32_int64: {21: 22, 22: 23}}.map_int32_int64[22] == 23"; - runTest(Activation.EMPTY); + runTest(); source = "TestAllTypes{oneof_type: NestedTestAllTypes{payload: x}}" + ".oneof_type.payload.map_int32_int64[22] == 23"; - runTest(Activation.of("x", TestAllTypes.newBuilder().putMapInt32Int64(22, 23).build())); + runTest(ImmutableMap.of("x", TestAllTypes.newBuilder().putMapInt32Int64(22, 23).build())); declareVariable("y", CelTypes.INT64); declareVariable("map", CelTypes.createMap(CelTypes.INT64, CelTypes.INT64)); // Constant key in variable map. source = "!(4 in map) && 1 in map"; - runTest(Activation.of("map", ImmutableMap.of(1L, 4L, 2L, 3L, 3L, 2L))); + runTest(ImmutableMap.of("map", ImmutableMap.of(1L, 4L, 2L, 3L, 3L, 2L))); // Variable key in constant map. source = "!(y in {1: 4, 2: 3, 3: 2}) && y in {5: 3, 4: 2, 3: 3}"; - runTest(Activation.of("y", 4L)); + runTest(ImmutableMap.of("y", 4L)); // Variable key in variable map. source = "!(y in map) && (y + 3) in map"; - runTest( - Activation.copyOf( - ImmutableMap.of("y", 1L, "map", ImmutableMap.of(4L, 1L, 5L, 2L, 6L, 3L)))); + runTest(ImmutableMap.of("y", 1L, "map", ImmutableMap.of(4L, 1L, 5L, 2L, 6L, 3L))); // Message value in map source = "TestAllTypes{map_int64_nested_type:{42:NestedTestAllTypes{payload:TestAllTypes{}}}}"; - runTest(Activation.EMPTY); + runTest(); // Repeated key - constant source = "{true: 1, false: 2, true: 3}[true]"; - runTest(Activation.EMPTY); + runTest(); // Repeated key - expressions declareVariable("b", CelTypes.BOOL); source = "{b: 1, !b: 2, b: 3}[true]"; - runTest(Activation.of("b", true)); + runTest(ImmutableMap.of("b", true)); } @Test public void comprehension() throws Exception { source = "[0, 1, 2].map(x, x > 0, x + 1) == [2, 3]"; - runTest(Activation.EMPTY); + runTest(); source = "[0, 1, 2].exists(x, x > 0)"; - runTest(Activation.EMPTY); + runTest(); source = "[0, 1, 2].exists(x, x > 2)"; - runTest(Activation.EMPTY); + runTest(); } @Test - public void abstractType() throws Exception { + public void abstractType() { Type typeParam = CelTypes.createTypeParam("T"); Type abstractType = Type.newBuilder() @@ -750,14 +784,6 @@ public void abstractType() throws Exception { ImmutableList.of(CelTypes.createList(typeParam)), ImmutableList.of("T"), abstractType)); - eval.registrar() - .add( - "vector", - ImmutableList.of(List.class), - (Object[] args) -> { - List list = (List) args[0]; - return list.toArray(new Object[0]); - }); // Declare a function to access element of a vector. declareFunction( "at", @@ -766,24 +792,32 @@ public void abstractType() throws Exception { ImmutableList.of(abstractType, CelTypes.INT64), ImmutableList.of("T"), typeParam)); - eval.registrar() - .add( + // Add function bindings for above + addFunctionBinding( + CelFunctionBinding.from( + "vector", + ImmutableList.of(List.class), + (Object[] args) -> { + List list = (List) args[0]; + return list.toArray(new Object[0]); + }), + CelFunctionBinding.from( "at", ImmutableList.of(Object[].class, Long.class), (Object[] args) -> { Object[] array = (Object[]) args[0]; return array[(int) (long) args[1]]; - }); + })); source = "vector([1,2,3]).at(1) == 2"; - runTest(Activation.EMPTY); + runTest(); source = "vector([1,2,3]).at(1) + vector([7]).at(0)"; - runTest(Activation.EMPTY); + runTest(); } @Test - public void namespacedFunctions() throws Exception { + public void namespacedFunctions() { declareFunction( "ns.func", globalOverload("ns_func_overload", ImmutableList.of(CelTypes.STRING), CelTypes.INT64)); @@ -793,60 +827,61 @@ public void namespacedFunctions() throws Exception { "ns_member_overload", ImmutableList.of(CelTypes.INT64, CelTypes.INT64), CelTypes.INT64)); - eval.registrar().add("ns_func_overload", String.class, s -> (long) s.length()); - eval.registrar().add("ns_member_overload", Long.class, Long.class, Long::sum); + addFunctionBinding( + CelFunctionBinding.from("ns_func_overload", String.class, s -> (long) s.length()), + CelFunctionBinding.from("ns_member_overload", Long.class, Long.class, Long::sum)); source = "ns.func('hello')"; - runTest(Activation.EMPTY); + runTest(); source = "ns.func('hello').member(ns.func('test'))"; - runTest(Activation.EMPTY); + runTest(); source = "{ns.func('test'): 2}"; - runTest(Activation.EMPTY); + runTest(); source = "{2: ns.func('test')}"; - runTest(Activation.EMPTY); + runTest(); source = "[ns.func('test'), 2]"; - runTest(Activation.EMPTY); + runTest(); source = "[ns.func('test')].map(x, x * 2)"; - runTest(Activation.EMPTY); + runTest(); source = "[1, 2].map(x, x * ns.func('test'))"; - runTest(Activation.EMPTY); + runTest(); container = "ns"; // Call with the container set as the function's namespace source = "ns.func('hello')"; - runTest(Activation.EMPTY); + runTest(); source = "func('hello')"; - runTest(Activation.EMPTY); + runTest(); source = "func('hello').member(func('test'))"; - runTest(Activation.EMPTY); + runTest(); } @Test - public void namespacedVariables() throws Exception { + public void namespacedVariables() { container = "ns"; declareVariable("ns.x", CelTypes.INT64); source = "x"; - runTest(Activation.of("ns.x", 2)); + runTest(ImmutableMap.of("ns.x", 2)); container = "dev.cel.testing.testdata.proto3"; Type messageType = CelTypes.createMessage("google.api.expr.test.v1.proto3.TestAllTypes"); declareVariable("dev.cel.testing.testdata.proto3.msgVar", messageType); source = "msgVar.single_int32"; runTest( - Activation.of( + ImmutableMap.of( "dev.cel.testing.testdata.proto3.msgVar", TestAllTypes.newBuilder().setSingleInt32(5).build())); } @Test - public void durationFunctions() throws Exception { + public void durationFunctions() { declareVariable("d1", CelTypes.DURATION); Duration d1 = Duration.newBuilder().setSeconds(25 * 3600 + 59 * 60 + 1).setNanos(11000000).build(); @@ -855,196 +890,196 @@ public void durationFunctions() throws Exception { container = Type.getDescriptor().getFile().getPackage(); source = "d1.getHours()"; - runTest(Activation.of("d1", d1)); - runTest(Activation.of("d1", d2)); + runTest(ImmutableMap.of("d1", d1)); + runTest(ImmutableMap.of("d1", d2)); source = "d1.getMinutes()"; - runTest(Activation.of("d1", d1)); - runTest(Activation.of("d1", d2)); + runTest(ImmutableMap.of("d1", d1)); + runTest(ImmutableMap.of("d1", d2)); source = "d1.getSeconds()"; - runTest(Activation.of("d1", d1)); - runTest(Activation.of("d1", d2)); + runTest(ImmutableMap.of("d1", d1)); + runTest(ImmutableMap.of("d1", d2)); source = "d1.getMilliseconds()"; - runTest(Activation.of("d1", d1)); - runTest(Activation.of("d1", d2)); + runTest(ImmutableMap.of("d1", d1)); + runTest(ImmutableMap.of("d1", d2)); declareVariable("val", CelTypes.INT64); source = "d1.getHours() < val"; - runTest(Activation.of("d1", d1).extend(Activation.of("val", 30L))); + runTest(extend(ImmutableMap.of("d1", d1), ImmutableMap.of("val", 30L))); source = "d1.getMinutes() > val"; - runTest(Activation.of("d1", d1).extend(Activation.of("val", 30L))); + runTest(extend(ImmutableMap.of("d1", d1), ImmutableMap.of("val", 30L))); source = "d1.getSeconds() > val"; - runTest(Activation.of("d1", d1).extend(Activation.of("val", 30L))); + runTest(extend(ImmutableMap.of("d1", d1), ImmutableMap.of("val", 30L))); source = "d1.getMilliseconds() < val"; - runTest(Activation.of("d1", d1).extend(Activation.of("val", 30L))); + runTest(extend(ImmutableMap.of("d1", d1), ImmutableMap.of("val", 30L))); } @Test - public void timestampFunctions() throws Exception { + public void timestampFunctions() { declareVariable("ts1", CelTypes.TIMESTAMP); container = Type.getDescriptor().getFile().getPackage(); Timestamp ts1 = Timestamp.newBuilder().setSeconds(1).setNanos(11000000).build(); Timestamp ts2 = Timestamps.fromSeconds(-1); source = "ts1.getFullYear(\"America/Los_Angeles\")"; - runTest(Activation.of("ts1", ts1)); + runTest(ImmutableMap.of("ts1", ts1)); source = "ts1.getFullYear()"; - runTest(Activation.of("ts1", ts1)); - runTest(Activation.of("ts1", ts2)); + runTest(ImmutableMap.of("ts1", ts1)); + runTest(ImmutableMap.of("ts1", ts2)); source = "ts1.getFullYear(\"Indian/Cocos\")"; - runTest(Activation.of("ts1", ts1)); + runTest(ImmutableMap.of("ts1", ts1)); source = "ts1.getFullYear(\"2:00\")"; - runTest(Activation.of("ts1", ts1)); + runTest(ImmutableMap.of("ts1", ts1)); source = "ts1.getMonth(\"America/Los_Angeles\")"; - runTest(Activation.of("ts1", ts1)); + runTest(ImmutableMap.of("ts1", ts1)); source = "ts1.getMonth()"; - runTest(Activation.of("ts1", ts1)); - runTest(Activation.of("ts1", ts2)); + runTest(ImmutableMap.of("ts1", ts1)); + runTest(ImmutableMap.of("ts1", ts2)); source = "ts1.getMonth(\"Indian/Cocos\")"; - runTest(Activation.of("ts1", ts1)); + runTest(ImmutableMap.of("ts1", ts1)); source = "ts1.getMonth(\"-8:15\")"; - runTest(Activation.of("ts1", ts1)); + runTest(ImmutableMap.of("ts1", ts1)); source = "ts1.getDayOfYear(\"America/Los_Angeles\")"; - runTest(Activation.of("ts1", ts1)); + runTest(ImmutableMap.of("ts1", ts1)); source = "ts1.getDayOfYear()"; - runTest(Activation.of("ts1", ts1)); - runTest(Activation.of("ts1", ts2)); + runTest(ImmutableMap.of("ts1", ts1)); + runTest(ImmutableMap.of("ts1", ts2)); source = "ts1.getDayOfYear(\"Indian/Cocos\")"; - runTest(Activation.of("ts1", ts1)); + runTest(ImmutableMap.of("ts1", ts1)); source = "ts1.getDayOfYear(\"-9:00\")"; - runTest(Activation.of("ts1", ts1)); + runTest(ImmutableMap.of("ts1", ts1)); source = "ts1.getDayOfMonth(\"America/Los_Angeles\")"; - runTest(Activation.of("ts1", ts1)); + runTest(ImmutableMap.of("ts1", ts1)); source = "ts1.getDayOfMonth()"; - runTest(Activation.of("ts1", ts1)); - runTest(Activation.of("ts1", ts2)); + runTest(ImmutableMap.of("ts1", ts1)); + runTest(ImmutableMap.of("ts1", ts2)); source = "ts1.getDayOfMonth(\"Indian/Cocos\")"; - runTest(Activation.of("ts1", ts1)); + runTest(ImmutableMap.of("ts1", ts1)); source = "ts1.getDayOfMonth(\"8:00\")"; - runTest(Activation.of("ts1", ts1)); + runTest(ImmutableMap.of("ts1", ts1)); source = "ts1.getDate(\"America/Los_Angeles\")"; - runTest(Activation.of("ts1", ts1)); + runTest(ImmutableMap.of("ts1", ts1)); source = "ts1.getDate()"; - runTest(Activation.of("ts1", ts1)); - runTest(Activation.of("ts1", ts2)); + runTest(ImmutableMap.of("ts1", ts1)); + runTest(ImmutableMap.of("ts1", ts2)); source = "ts1.getDate(\"Indian/Cocos\")"; - runTest(Activation.of("ts1", ts1)); + runTest(ImmutableMap.of("ts1", ts1)); source = "ts1.getDate(\"9:30\")"; - runTest(Activation.of("ts1", ts1)); + runTest(ImmutableMap.of("ts1", ts1)); Timestamp tsSunday = Timestamps.fromSeconds(3 * 24 * 3600); source = "ts1.getDayOfWeek(\"America/Los_Angeles\")"; - runTest(Activation.of("ts1", tsSunday)); + runTest(ImmutableMap.of("ts1", tsSunday)); source = "ts1.getDayOfWeek()"; - runTest(Activation.of("ts1", tsSunday)); - runTest(Activation.of("ts1", ts2)); + runTest(ImmutableMap.of("ts1", tsSunday)); + runTest(ImmutableMap.of("ts1", ts2)); source = "ts1.getDayOfWeek(\"Indian/Cocos\")"; - runTest(Activation.of("ts1", tsSunday)); + runTest(ImmutableMap.of("ts1", tsSunday)); source = "ts1.getDayOfWeek(\"-9:30\")"; - runTest(Activation.of("ts1", tsSunday)); + runTest(ImmutableMap.of("ts1", tsSunday)); source = "ts1.getHours(\"America/Los_Angeles\")"; - runTest(Activation.of("ts1", ts1)); + runTest(ImmutableMap.of("ts1", ts1)); source = "ts1.getHours()"; - runTest(Activation.of("ts1", ts1)); - runTest(Activation.of("ts1", ts2)); + runTest(ImmutableMap.of("ts1", ts1)); + runTest(ImmutableMap.of("ts1", ts2)); source = "ts1.getHours(\"Indian/Cocos\")"; - runTest(Activation.of("ts1", ts1)); + runTest(ImmutableMap.of("ts1", ts1)); source = "ts1.getHours(\"6:30\")"; - runTest(Activation.of("ts1", ts1)); + runTest(ImmutableMap.of("ts1", ts1)); source = "ts1.getMinutes(\"America/Los_Angeles\")"; - runTest(Activation.of("ts1", ts1)); + runTest(ImmutableMap.of("ts1", ts1)); source = "ts1.getMinutes()"; - runTest(Activation.of("ts1", ts1)); - runTest(Activation.of("ts1", ts2)); + runTest(ImmutableMap.of("ts1", ts1)); + runTest(ImmutableMap.of("ts1", ts2)); source = "ts1.getMinutes(\"Indian/Cocos\")"; - runTest(Activation.of("ts1", ts1)); + runTest(ImmutableMap.of("ts1", ts1)); source = "ts1.getMinutes(\"-8:00\")"; - runTest(Activation.of("ts1", ts1)); + runTest(ImmutableMap.of("ts1", ts1)); source = "ts1.getSeconds(\"America/Los_Angeles\")"; - runTest(Activation.of("ts1", ts1)); + runTest(ImmutableMap.of("ts1", ts1)); source = "ts1.getSeconds()"; - runTest(Activation.of("ts1", ts1)); - runTest(Activation.of("ts1", ts2)); + runTest(ImmutableMap.of("ts1", ts1)); + runTest(ImmutableMap.of("ts1", ts2)); source = "ts1.getSeconds(\"Indian/Cocos\")"; - runTest(Activation.of("ts1", ts1)); + runTest(ImmutableMap.of("ts1", ts1)); source = "ts1.getSeconds(\"-8:00\")"; - runTest(Activation.of("ts1", ts1)); + runTest(ImmutableMap.of("ts1", ts1)); source = "ts1.getMilliseconds(\"America/Los_Angeles\")"; - runTest(Activation.of("ts1", ts1)); + runTest(ImmutableMap.of("ts1", ts1)); source = "ts1.getMilliseconds()"; - runTest(Activation.of("ts1", ts1)); + runTest(ImmutableMap.of("ts1", ts1)); source = "ts1.getMilliseconds(\"Indian/Cocos\")"; - runTest(Activation.of("ts1", ts1)); + runTest(ImmutableMap.of("ts1", ts1)); source = "ts1.getMilliseconds(\"-8:00\")"; - runTest(Activation.of("ts1", ts1)); + runTest(ImmutableMap.of("ts1", ts1)); declareVariable("val", CelTypes.INT64); source = "ts1.getFullYear() < val"; - runTest(Activation.of("ts1", ts1).extend(Activation.of("val", 2013L))); + runTest(extend(ImmutableMap.of("ts1", ts1), ImmutableMap.of("val", 2013L))); source = "ts1.getMonth() < val"; - runTest(Activation.of("ts1", ts1).extend(Activation.of("val", 12L))); + runTest(extend(ImmutableMap.of("ts1", ts1), ImmutableMap.of("val", 12L))); source = "ts1.getDayOfYear() < val"; - runTest(Activation.of("ts1", ts1).extend(Activation.of("val", 13L))); + runTest(extend(ImmutableMap.of("ts1", ts1), ImmutableMap.of("val", 13L))); source = "ts1.getDayOfMonth() < val"; - runTest(Activation.of("ts1", ts1).extend(Activation.of("val", 10L))); + runTest(extend(ImmutableMap.of("ts1", ts1), ImmutableMap.of("val", 10L))); source = "ts1.getDate() < val"; - runTest(Activation.of("ts1", ts1).extend(Activation.of("val", 15L))); + runTest(extend(ImmutableMap.of("ts1", ts1), ImmutableMap.of("val", 15L))); source = "ts1.getDayOfWeek() < val"; - runTest(Activation.of("ts1", ts1).extend(Activation.of("val", 15L))); + runTest(extend(ImmutableMap.of("ts1", ts1), ImmutableMap.of("val", 15L))); source = "ts1.getHours() < val"; - runTest(Activation.of("ts1", ts1).extend(Activation.of("val", 15L))); + runTest(extend(ImmutableMap.of("ts1", ts1), ImmutableMap.of("val", 15L))); source = "ts1.getMinutes() < val"; - runTest(Activation.of("ts1", ts1).extend(Activation.of("val", 15L))); + runTest(extend(ImmutableMap.of("ts1", ts1), ImmutableMap.of("val", 15L))); source = "ts1.getSeconds() < val"; - runTest(Activation.of("ts1", ts1).extend(Activation.of("val", 15L))); + runTest(extend(ImmutableMap.of("ts1", ts1), ImmutableMap.of("val", 15L))); source = "ts1.getMilliseconds() < val"; - runTest(Activation.of("ts1", ts1).extend(Activation.of("val", 15L))); + runTest(extend(ImmutableMap.of("ts1", ts1), ImmutableMap.of("val", 15L))); } @Test - public void unknownField() throws Exception { + public void unknownField() { container = TestAllTypes.getDescriptor().getFile().getPackage(); declareVariable("x", CelTypes.createMessage(TestAllTypes.getDescriptor().getFullName())); // Unknown field is accessed. source = "x.single_int32"; - runTest(Activation.EMPTY); + runTest(); source = "x.map_int32_int64[22]"; - runTest(Activation.EMPTY); + runTest(); source = "x.repeated_nested_message[1]"; - runTest(Activation.EMPTY); + runTest(); // Function call for an unknown field. source = "x.single_timestamp.getSeconds()"; - runTest(Activation.EMPTY); + runTest(); // Unknown field in a nested message source = "x.single_nested_message.bb"; - runTest(Activation.EMPTY); + runTest(); // Unknown field access in a map. source = "{1: x.single_int32}"; - runTest(Activation.EMPTY); + runTest(); // Unknown field access in a list. source = "[1, x.single_int32]"; - runTest(Activation.EMPTY); + runTest(); } @Test - public void unknownResultSet() throws Exception { + public void unknownResultSet() { container = TestAllTypes.getDescriptor().getFile().getPackage(); declareVariable("x", CelTypes.createMessage(TestAllTypes.getDescriptor().getFullName())); TestAllTypes message = @@ -1055,505 +1090,505 @@ public void unknownResultSet() throws Exception { // unknown && true ==> unknown source = "x.single_int32 == 1 && true"; - runTest(Activation.EMPTY); + runTest(); // unknown && false ==> false source = "x.single_int32 == 1 && false"; - runTest(Activation.EMPTY); + runTest(); // unknown && Unknown ==> UnknownSet source = "x.single_int32 == 1 && x.single_int64 == 1"; - runTest(Activation.EMPTY); + runTest(); // unknown && error ==> unknown source = "x.single_int32 == 1 && x.single_timestamp <= timestamp(\"bad timestamp string\")"; - runTest(Activation.EMPTY); + runTest(); // true && unknown ==> unknown source = "true && x.single_int32 == 1"; - runTest(Activation.EMPTY); + runTest(); // false && unknown ==> false source = "false && x.single_int32 == 1"; - runTest(Activation.EMPTY); + runTest(); // error && unknown ==> unknown source = "x.single_timestamp <= timestamp(\"bad timestamp string\") && x.single_int32 == 1"; - runTest(Activation.EMPTY); + runTest(); // error && error ==> error source = "x.single_timestamp <= timestamp(\"bad timestamp string\") " + "&& x.single_timestamp > timestamp(\"another bad timestamp string\")"; - runTest(Activation.EMPTY); + runTest(); // unknown || true ==> true source = "x.single_int32 == 1 || x.single_string == \"test\""; - runTest(Activation.EMPTY); + runTest(); // unknown || false ==> unknown source = "x.single_int32 == 1 || x.single_string != \"test\""; - runTest(Activation.EMPTY); + runTest(); // unknown || unknown ==> UnknownSet source = "x.single_int32 == 1 || x.single_int64 == 1"; - runTest(Activation.EMPTY); + runTest(); // unknown || error ==> unknown source = "x.single_int32 == 1 || x.single_timestamp <= timestamp(\"bad timestamp string\")"; - runTest(Activation.EMPTY); + runTest(); // true || unknown ==> true source = "true || x.single_int32 == 1"; - runTest(Activation.EMPTY); + runTest(); // false || unknown ==> unknown source = "false || x.single_int32 == 1"; - runTest(Activation.EMPTY); + runTest(); // error || unknown ==> unknown source = "x.single_timestamp <= timestamp(\"bad timestamp string\") || x.single_int32 == 1"; - runTest(Activation.EMPTY); + runTest(); // error || error ==> error source = "x.single_timestamp <= timestamp(\"bad timestamp string\") " + "|| x.single_timestamp > timestamp(\"another bad timestamp string\")"; - runTest(Activation.EMPTY); + runTest(); // dispatch test declareFunction( "f", memberOverload("f", Arrays.asList(CelTypes.INT64, CelTypes.INT64), CelTypes.BOOL)); - eval.registrar().add("f", Integer.class, Integer.class, Objects::equals); + addFunctionBinding(CelFunctionBinding.from("f", Integer.class, Integer.class, Objects::equals)); // dispatch: unknown.f(1) ==> unknown source = "x.single_int32.f(1)"; - runTest(Activation.EMPTY); + runTest(); // dispatch: 1.f(unknown) ==> unknown source = "1.f(x.single_int32)"; - runTest(Activation.EMPTY); + runTest(); // dispatch: unknown.f(unknown) ==> unknownSet source = "x.single_int64.f(x.single_int32)"; - runTest(Activation.EMPTY); + runTest(); // ident is null(x is unbound) ==> unknown source = "x"; - runTest(Activation.of("y", message)); + runTest(ImmutableMap.of("y", message)); // ident is unknown ==> unknown source = "x"; ExprValue unknownMessage = ExprValue.newBuilder().setUnknown(UnknownSet.getDefaultInstance()).build(); - runTest(Activation.of("x", unknownMessage)); + runTest(ImmutableMap.of("x", unknownMessage)); // comprehension test // iteRange is unknown => unknown source = "x.map_int32_int64.map(x, x > 0, x + 1)"; - runTest(Activation.EMPTY); + runTest(); // exists, loop condition encounters unknown => skip unknown and check other element source = "[0, 2, 4].exists(z, z == 2 || z == x.single_int32)"; - runTest(Activation.EMPTY); + runTest(); // exists, loop condition encounters unknown => skip unknown and check other element, no dupe id // in result source = "[0, 2, 4].exists(z, z == x.single_int32)"; - runTest(Activation.EMPTY); + runTest(); // exists_one, loop condition encounters unknown => collect all unknowns source = "[0, 2, 4].exists_one(z, z == 0 || (z == 2 && z == x.single_int32) " + "|| (z == 4 && z == x.single_int64))"; - runTest(Activation.EMPTY); + runTest(); // all, loop condition encounters unknown => skip unknown and check other element source = "[0, 2].all(z, z == 2 || z == x.single_int32)"; - runTest(Activation.EMPTY); + runTest(); // filter, loop condition encounters unknown => skip unknown and check other element source = "[0, 2, 4].filter(z, z == 0 || (z == 2 && z == x.single_int32) " + "|| (z == 4 && z == x.single_int64))"; - runTest(Activation.EMPTY); + runTest(); // map, loop condition encounters unknown => skip unknown and check other element source = "[0, 2, 4].map(z, z == 0 || (z == 2 && z == x.single_int32) " + "|| (z == 4 && z == x.single_int64))"; - runTest(Activation.EMPTY); + runTest(); // conditional test // unknown ? 1 : 2 ==> unknown source = "x.single_int32 == 1 ? 1 : 2"; - runTest(Activation.EMPTY); + runTest(); // true ? unknown : 2 ==> unknown source = "true ? x.single_int32 : 2"; - runTest(Activation.EMPTY); + runTest(); // true ? 1 : unknown ==> 1 source = "true ? 1 : x.single_int32"; - runTest(Activation.EMPTY); + runTest(); // false ? unknown : 2 ==> 2 source = "false ? x.single_int32 : 2"; - runTest(Activation.EMPTY); + runTest(); // false ? 1 : unknown ==> unknown source = "false ? 1 : x.single_int32"; - runTest(Activation.EMPTY); + runTest(); // unknown condition ? unknown : unknown ==> unknown condition source = "x.single_int64 == 1 ? x.single_int32 : x.single_int32"; - runTest(Activation.EMPTY); + runTest(); // map with unknown key => unknown source = "{x.single_int32: 2, 3: 4}"; - runTest(Activation.EMPTY); + runTest(); // map with unknown value => unknown source = "{1: x.single_int32, 3: 4}"; - runTest(Activation.EMPTY); + runTest(); // map with unknown key and value => unknownSet source = "{1: x.single_int32, x.single_int64: 4}"; - runTest(Activation.EMPTY); + runTest(); // list with unknown => unknown source = "[1, x.single_int32, 3, 4]"; - runTest(Activation.EMPTY); + runTest(); // list with multiple unknowns => unknownSet source = "[1, x.single_int32, x.single_int64, 4]"; - runTest(Activation.EMPTY); + runTest(); // message with unknown => unknown source = "TestAllTypes{single_int32: x.single_int32}.single_int32 == 2"; - runTest(Activation.EMPTY); + runTest(); // message with multiple unknowns => unknownSet source = "TestAllTypes{single_int32: x.single_int32, single_int64: x.single_int64}"; - runTest(Activation.EMPTY); + runTest(); } @Test - public void timeConversions() throws Exception { + public void timeConversions() { container = Type.getDescriptor().getFile().getPackage(); declareVariable("t1", CelTypes.TIMESTAMP); source = "timestamp(\"1972-01-01T10:00:20.021-05:00\")"; - runTest(Activation.EMPTY); + runTest(); source = "timestamp(123)"; - runTest(Activation.EMPTY); + runTest(); source = "duration(\"15.11s\")"; - runTest(Activation.EMPTY); + runTest(); source = "int(t1) == 100"; - runTest(Activation.of("t1", Timestamps.fromSeconds(100))); + runTest(ImmutableMap.of("t1", Timestamps.fromSeconds(100))); source = "duration(\"1h2m3.4s\")"; - runTest(Activation.EMPTY); + runTest(); // Not supported. source = "duration('inf')"; - runTest(Activation.EMPTY); + runTest(); source = "duration(duration('15.0s'))"; // Identity - runTest(Activation.EMPTY); + runTest(); source = "timestamp(timestamp(123))"; // Identity - runTest(Activation.EMPTY); + runTest(); } @Test - public void sizeTests() throws Exception { + public void sizeTests() { container = Type.getDescriptor().getFile().getPackage(); declareVariable("str", CelTypes.STRING); declareVariable("b", CelTypes.BYTES); source = "size(b) == 5 && b.size() == 5"; - runTest(Activation.of("b", ByteString.copyFromUtf8("happy"))); + runTest(ImmutableMap.of("b", ByteString.copyFromUtf8("happy"))); source = "size(str) == 5 && str.size() == 5"; - runTest(Activation.of("str", "happy")); - runTest(Activation.of("str", "happ\uDBFF\uDFFC")); + runTest(ImmutableMap.of("str", "happy")); + runTest(ImmutableMap.of("str", "happ\uDBFF\uDFFC")); source = "size({1:14, 2:15}) == 2 && {1:14, 2:15}.size() == 2"; - runTest(Activation.EMPTY); + runTest(); source = "size([1,2,3]) == 3 && [1,2,3].size() == 3"; - runTest(Activation.EMPTY); + runTest(); } @Test - public void nonstrictQuantifierTests() throws Exception { + public void nonstrictQuantifierTests() { // Plain tests. Everything is constant. source = "[0, 2, 4].exists(x, 4/x == 2 && 4/(4-x) == 2)"; - runTest(Activation.EMPTY); + runTest(); source = "![0, 2, 4].all(x, 4/x != 2 && 4/(4-x) != 2)"; - runTest(Activation.EMPTY); + runTest(); declareVariable("four", CelTypes.INT64); // Condition is dynamic. source = "[0, 2, 4].exists(x, four/x == 2 && four/(four-x) == 2)"; - runTest(Activation.of("four", 4L)); + runTest(ImmutableMap.of("four", 4L)); source = "![0, 2, 4].all(x, four/x != 2 && four/(four-x) != 2)"; - runTest(Activation.of("four", 4L)); + runTest(ImmutableMap.of("four", 4L)); // Both range and condition are dynamic. source = "[0, 2, four].exists(x, four/x == 2 && four/(four-x) == 2)"; - runTest(Activation.of("four", 4L)); + runTest(ImmutableMap.of("four", 4L)); source = "![0, 2, four].all(x, four/x != 2 && four/(four-x) != 2)"; - runTest(Activation.of("four", 4L)); + runTest(ImmutableMap.of("four", 4L)); } @Test - public void regexpMatchingTests() throws Exception { + public void regexpMatchingTests() { // Constant everything. source = "matches(\"alpha\", \"^al.*\") == true"; - runTest(Activation.EMPTY); + runTest(); source = "matches(\"alpha\", \"^.al.*\") == false"; - runTest(Activation.EMPTY); + runTest(); source = "matches(\"alpha\", \".*ha$\") == true"; - runTest(Activation.EMPTY); + runTest(); source = "matches(\"alpha\", \"^.*ha.$\") == false"; - runTest(Activation.EMPTY); + runTest(); source = "matches(\"alpha\", \"\") == true"; - runTest(Activation.EMPTY); + runTest(); source = "matches(\"alpha\", \"ph\") == true"; - runTest(Activation.EMPTY); + runTest(); source = "matches(\"alpha\", \"^ph\") == false"; - runTest(Activation.EMPTY); + runTest(); source = "matches(\"alpha\", \"ph$\") == false"; - runTest(Activation.EMPTY); + runTest(); // Constant everything, receiver-style. source = "\"alpha\".matches(\"^al.*\") == true"; - runTest(Activation.EMPTY); + runTest(); source = "\"alpha\".matches(\"^.al.*\") == false"; - runTest(Activation.EMPTY); + runTest(); source = "\"alpha\".matches(\".*ha$\") == true"; - runTest(Activation.EMPTY); + runTest(); source = "\"alpha\".matches(\".*ha.$\") == false"; - runTest(Activation.EMPTY); + runTest(); source = "\"alpha\".matches(\"\") == true"; - runTest(Activation.EMPTY); + runTest(); source = "\"alpha\".matches(\"ph\") == true"; - runTest(Activation.EMPTY); + runTest(); source = "\"alpha\".matches(\"^ph\") == false"; - runTest(Activation.EMPTY); + runTest(); source = "\"alpha\".matches(\"ph$\") == false"; - runTest(Activation.EMPTY); + runTest(); // Constant string. declareVariable("regexp", CelTypes.STRING); source = "matches(\"alpha\", regexp) == true"; - runTest(Activation.of("regexp", "^al.*")); + runTest(ImmutableMap.of("regexp", "^al.*")); source = "matches(\"alpha\", regexp) == false"; - runTest(Activation.of("regexp", "^.al.*")); + runTest(ImmutableMap.of("regexp", "^.al.*")); source = "matches(\"alpha\", regexp) == true"; - runTest(Activation.of("regexp", ".*ha$")); + runTest(ImmutableMap.of("regexp", ".*ha$")); source = "matches(\"alpha\", regexp) == false"; - runTest(Activation.of("regexp", ".*ha.$")); + runTest(ImmutableMap.of("regexp", ".*ha.$")); // Constant string, receiver-style. source = "\"alpha\".matches(regexp) == true"; - runTest(Activation.of("regexp", "^al.*")); + runTest(ImmutableMap.of("regexp", "^al.*")); source = "\"alpha\".matches(regexp) == false"; - runTest(Activation.of("regexp", "^.al.*")); + runTest(ImmutableMap.of("regexp", "^.al.*")); source = "\"alpha\".matches(regexp) == true"; - runTest(Activation.of("regexp", ".*ha$")); + runTest(ImmutableMap.of("regexp", ".*ha$")); source = "\"alpha\".matches(regexp) == false"; - runTest(Activation.of("regexp", ".*ha.$")); + runTest(ImmutableMap.of("regexp", ".*ha.$")); // Constant regexp. declareVariable("s", CelTypes.STRING); source = "matches(s, \"^al.*\") == true"; - runTest(Activation.of("s", "alpha")); + runTest(ImmutableMap.of("s", "alpha")); source = "matches(s, \"^.al.*\") == false"; - runTest(Activation.of("s", "alpha")); + runTest(ImmutableMap.of("s", "alpha")); source = "matches(s, \".*ha$\") == true"; - runTest(Activation.of("s", "alpha")); + runTest(ImmutableMap.of("s", "alpha")); source = "matches(s, \"^.*ha.$\") == false"; - runTest(Activation.of("s", "alpha")); + runTest(ImmutableMap.of("s", "alpha")); // Constant regexp, receiver-style. source = "s.matches(\"^al.*\") == true"; - runTest(Activation.of("s", "alpha")); + runTest(ImmutableMap.of("s", "alpha")); source = "s.matches(\"^.al.*\") == false"; - runTest(Activation.of("s", "alpha")); + runTest(ImmutableMap.of("s", "alpha")); source = "s.matches(\".*ha$\") == true"; - runTest(Activation.of("s", "alpha")); + runTest(ImmutableMap.of("s", "alpha")); source = "s.matches(\"^.*ha.$\") == false"; - runTest(Activation.of("s", "alpha")); + runTest(ImmutableMap.of("s", "alpha")); // No constants. source = "matches(s, regexp) == true"; - runTest(Activation.copyOf(ImmutableMap.of("s", "alpha", "regexp", "^al.*"))); - runTest(Activation.copyOf(ImmutableMap.of("s", "alpha", "regexp", ".*ha$"))); + runTest(ImmutableMap.of("s", "alpha", "regexp", "^al.*")); + runTest(ImmutableMap.of("s", "alpha", "regexp", ".*ha$")); source = "matches(s, regexp) == false"; - runTest(Activation.copyOf(ImmutableMap.of("s", "alpha", "regexp", "^.al.*"))); - runTest(Activation.copyOf(ImmutableMap.of("s", "alpha", "regexp", ".*ha.$"))); + runTest(ImmutableMap.of("s", "alpha", "regexp", "^.al.*")); + runTest(ImmutableMap.of("s", "alpha", "regexp", ".*ha.$")); // No constants, receiver-style. source = "s.matches(regexp) == true"; - runTest(Activation.copyOf(ImmutableMap.of("s", "alpha", "regexp", "^al.*"))); - runTest(Activation.copyOf(ImmutableMap.of("s", "alpha", "regexp", ".*ha$"))); + runTest(ImmutableMap.of("s", "alpha", "regexp", "^al.*")); + runTest(ImmutableMap.of("s", "alpha", "regexp", ".*ha$")); source = "s.matches(regexp) == false"; - runTest(Activation.copyOf(ImmutableMap.of("s", "alpha", "regexp", "^.al.*"))); - runTest(Activation.copyOf(ImmutableMap.of("s", "alpha", "regexp", ".*ha.$"))); + runTest(ImmutableMap.of("s", "alpha", "regexp", "^.al.*")); + runTest(ImmutableMap.of("s", "alpha", "regexp", ".*ha.$")); } @Test - public void regexpMatches_error() throws Exception { + public void regexpMatches_error() { source = "matches(\"alpha\", \"**\")"; - runTest(Activation.EMPTY); + runTest(); source = "\"alpha\".matches(\"**\")"; - runTest(Activation.EMPTY); + runTest(); } @Test - public void int64Conversions() throws Exception { + public void int64Conversions() { source = "int('-1')"; // string converts to -1 - runTest(Activation.EMPTY); + runTest(); source = "int(2.1)"; // double converts to 2 - runTest(Activation.EMPTY); + runTest(); source = "int(18446744073709551615u)"; // 2^64-1 should error - runTest(Activation.EMPTY); + runTest(); source = "int(1e99)"; // out of range should error - runTest(Activation.EMPTY); + runTest(); source = "int(42u)"; // converts to 42 - runTest(Activation.EMPTY); + runTest(); } @Test - public void uint64Conversions() throws Exception { + public void uint64Conversions() { // The test case `uint(1e19)` succeeds with unsigned longs and fails with longs in a way that // cannot be easily tested. - if (!eval.celOptions().enableUnsignedLongs()) { + if (!celOptions.enableUnsignedLongs()) { skipBaselineVerification(); return; } source = "uint('1')"; // string converts to 1u - runTest(Activation.EMPTY); + runTest(); source = "uint(2.1)"; // double converts to 2u - runTest(Activation.EMPTY); + runTest(); source = "uint(-1)"; // should error - runTest(Activation.EMPTY); + runTest(); source = "uint(1e19)"; // valid uint but outside of int range - runTest(Activation.EMPTY); + runTest(); source = "uint(6.022e23)"; // outside uint range - runTest(Activation.EMPTY); + runTest(); source = "uint(42)"; // int converts to 42u - runTest(Activation.EMPTY); + runTest(); source = "uint('f1')"; // should error - runTest(Activation.EMPTY); + runTest(); source = "uint(1u)"; // identity - runTest(Activation.EMPTY); + runTest(); source = "uint(dyn(1u))"; // identity, check dynamic dispatch - runTest(Activation.EMPTY); + runTest(); } @Test - public void doubleConversions() throws Exception { + public void doubleConversions() { source = "double('1.1')"; // string converts to 1.1 - runTest(Activation.EMPTY); + runTest(); source = "double(2u)"; // uint converts to 2.0 - runTest(Activation.EMPTY); + runTest(); source = "double(-1)"; // int converts to -1.0 - runTest(Activation.EMPTY); + runTest(); source = "double('bad')"; - runTest(Activation.EMPTY); + runTest(); source = "double(1.5)"; // Identity - runTest(Activation.EMPTY); + runTest(); } @Test - public void stringConversions() throws Exception { + public void stringConversions() { source = "string(1.1)"; // double converts to '1.1' - runTest(Activation.EMPTY); + runTest(); source = "string(2u)"; // uint converts to '2' - runTest(Activation.EMPTY); + runTest(); source = "string(-1)"; // int converts to '-1' - runTest(Activation.EMPTY); + runTest(); // Byte literals in Google SQL only take the leading byte of an escape character. // This means that to translate a byte literal to a UTF-8 encoded string, all bytes must be // encoded in the literal as they would be laid out in memory for UTF-8, hence the extra octal // escape to achieve parity with the bidi test below. source = "string(b'abc\\303\\203')"; - runTest(Activation.EMPTY); // bytes convert to 'abcÃ' + runTest(); // bytes convert to 'abcÃ' // Bi-di conversion for strings and bytes for 'abcÃ', note the difference between the string // and byte literal values. source = "string(bytes('abc\\303'))"; - runTest(Activation.EMPTY); + runTest(); source = "string(timestamp('2009-02-13T23:31:30Z'))"; - runTest(Activation.EMPTY); + runTest(); source = "string(duration('1000000s'))"; - runTest(Activation.EMPTY); + runTest(); source = "string('hello')"; // Identity - runTest(Activation.EMPTY); + runTest(); } @Test @@ -1561,68 +1596,62 @@ public void bytes() throws Exception { source = "b'a' < b'b' && b'a' <= b'b' && b'b' > b'a' && b'a' >= b'a' && b'a' == b'a' && b'a' !=" + " b'b'"; - runTest(Activation.EMPTY); + runTest(); } @Test - public void boolConversions() throws Exception { + public void boolConversions() { source = "bool(true)"; - runTest(Activation.EMPTY); // Identity + runTest(); // Identity source = "bool('true') && bool('TRUE') && bool('True') && bool('t') && bool('1')"; - runTest(Activation.EMPTY); // result is true + runTest(); // result is true source = "bool('false') || bool('FALSE') || bool('False') || bool('f') || bool('0')"; - runTest(Activation.EMPTY); // result is false + runTest(); // result is false source = "bool('TrUe')"; - runTest(Activation.EMPTY); // exception + runTest(); // exception source = "bool('FaLsE')"; - runTest(Activation.EMPTY); // exception + runTest(); // exception } @Test - public void bytesConversions() throws Exception { + public void bytesConversions() { source = "bytes('abc\\303')"; - runTest(Activation.EMPTY); // string converts to abcà in bytes form. + runTest(); // string converts to abcà in bytes form. source = "bytes(bytes('abc\\303'))"; // Identity - runTest(Activation.EMPTY); + runTest(); } @Test - public void dynConversions() throws Exception { + public void dynConversions() { source = "dyn(42)"; - runTest(Activation.EMPTY); + runTest(); source = "dyn({'a':1, 'b':2})"; - runTest(Activation.EMPTY); + runTest(); } @Test - public void dyn_error() throws Exception { + public void dyn_error() { source = "dyn('hello').invalid"; - runTest(Activation.EMPTY); + runTest(); source = "has(dyn('hello').invalid)"; - runTest(Activation.EMPTY); + runTest(); source = "dyn([]).invalid"; - runTest(Activation.EMPTY); + runTest(); source = "has(dyn([]).invalid)"; - runTest(Activation.EMPTY); + runTest(); } - // This lambda implements @Immutable interface 'Function', but 'InterpreterTest' has field 'eval' - // of type 'com.google.api.expr.cel.testing.Eval', the declaration of - // type - // 'com.google.api.expr.cel.testing.Eval' is not annotated with - // @com.google.errorprone.annotations.Immutable - @SuppressWarnings("Immutable") @Test - public void jsonValueTypes() throws Exception { + public void jsonValueTypes() { container = TestAllTypes.getDescriptor().getFile().getPackage(); declareVariable("x", CelTypes.createMessage(TestAllTypes.getDescriptor().getFullName())); @@ -1630,19 +1659,19 @@ public void jsonValueTypes() throws Exception { TestAllTypes xBool = TestAllTypes.newBuilder().setSingleValue(Value.newBuilder().setBoolValue(true)).build(); source = "x.single_value"; - runTest(Activation.of("x", xBool)); + runTest(ImmutableMap.of("x", xBool)); // JSON number selection with int comparison. TestAllTypes xInt = TestAllTypes.newBuilder().setSingleValue(Value.newBuilder().setNumberValue(1)).build(); source = "x.single_value == double(1)"; - runTest(Activation.of("x", xInt)); + runTest(ImmutableMap.of("x", xInt)); // JSON number selection with float comparison. TestAllTypes xFloat = TestAllTypes.newBuilder().setSingleValue(Value.newBuilder().setNumberValue(1.1)).build(); source = "x.single_value == 1.1"; - runTest(Activation.of("x", xFloat)); + runTest(ImmutableMap.of("x", xFloat)); // JSON null selection. TestAllTypes xNull = @@ -1650,7 +1679,7 @@ public void jsonValueTypes() throws Exception { .setSingleValue(Value.newBuilder().setNullValue(NullValue.NULL_VALUE)) .build(); source = "x.single_value == null"; - runTest(Activation.of("x", xNull)); + runTest(ImmutableMap.of("x", xNull)); // JSON string selection. TestAllTypes xString = @@ -1658,7 +1687,7 @@ public void jsonValueTypes() throws Exception { .setSingleValue(Value.newBuilder().setStringValue("hello")) .build(); source = "x.single_value == 'hello'"; - runTest(Activation.of("x", xString)); + runTest(ImmutableMap.of("x", xString)); // JSON list equality. TestAllTypes xList = @@ -1675,7 +1704,7 @@ public void jsonValueTypes() throws Exception { .addValues(Value.newBuilder().setNumberValue(-1.1)))) .build(); source = "x.single_value[0] == [['hello'], -1.1][0]"; - runTest(Activation.of("x", xList)); + runTest(ImmutableMap.of("x", xList)); // JSON struct equality. TestAllTypes xStruct = @@ -1692,7 +1721,7 @@ public void jsonValueTypes() throws Exception { .putFields("num", Value.newBuilder().setNumberValue(-1.1).build())) .build(); source = "x.single_struct.num == {'str': ['hello'], 'num': -1.1}['num']"; - runTest(Activation.of("x", xStruct)); + runTest(ImmutableMap.of("x", xStruct)); // Build a proto message using a dynamically constructed map and assign the map to a struct // value. @@ -1701,42 +1730,39 @@ public void jsonValueTypes() throws Exception { + "single_struct: " + "TestAllTypes{single_value: {'str': ['hello']}}.single_value" + "}"; - runTest(Activation.EMPTY); + runTest(); // Ensure that types are being wrapped and unwrapped on function dispatch. declareFunction( "pair", globalOverload("pair", ImmutableList.of(CelTypes.STRING, CelTypes.STRING), CelTypes.DYN)); - eval.registrar() - .add( + addFunctionBinding( + CelFunctionBinding.from( "pair", ImmutableList.of(String.class, String.class), (Object[] args) -> { String key = (String) args[0]; String val = (String) args[1]; - return eval.adapt( - Value.newBuilder() - .setStructValue( - Struct.newBuilder() - .putFields(key, Value.newBuilder().setStringValue(val).build())) - .build()); - }); + return Value.newBuilder() + .setStructValue( + Struct.newBuilder() + .putFields(key, Value.newBuilder().setStringValue(val).build())) + .build(); + })); source = "pair(x.single_struct.str[0], 'val')"; - runTest(Activation.of("x", xStruct)); + runTest(ImmutableMap.of("x", xStruct)); } @Test - public void jsonConversions() throws Exception { + public void jsonConversions() { declareVariable("ts", CelTypes.TIMESTAMP); declareVariable("du", CelTypes.DURATION); source = "google.protobuf.Struct { fields: {'timestamp': ts, 'duration': du } }"; - runTest( - Activation.copyOf( - ImmutableMap.of("ts", Timestamps.fromSeconds(100), "du", Durations.fromMillis(200)))); + runTest(ImmutableMap.of("ts", Timestamps.fromSeconds(100), "du", Durations.fromMillis(200))); } @Test - public void typeComparisons() throws Exception { + public void typeComparisons() { container = TestAllTypes.getDescriptor().getFile().getPackage(); // Test numeric types. @@ -1745,23 +1771,23 @@ public void typeComparisons() throws Exception { + "type(1u) != int && type(1) != uint && " + "type(uint(1.1)) == uint && " + "type(1.1) == double"; - runTest(Activation.EMPTY); + runTest(); // Test string and bytes types. source = "type('hello') == string && type(b'\277') == bytes"; - runTest(Activation.EMPTY); + runTest(); // Test list and map types. source = "type([1, 2, 3]) == list && type({'a': 1, 'b': 2}) == map"; - runTest(Activation.EMPTY); + runTest(); // Test bool types. source = "type(true) == bool && type(false) == bool"; - runTest(Activation.EMPTY); + runTest(); // Test well-known proto-based types. source = "type(duration('10s')) == google.protobuf.Duration"; - runTest(Activation.EMPTY); + runTest(); // Test external proto-based types with container resolution. source = @@ -1775,19 +1801,19 @@ public void typeComparisons() throws Exception { + "type(.google.api.expr.test.v1.proto3.TestAllTypes{}) == proto3.TestAllTypes && " + "type(.google.api.expr.test.v1.proto3.TestAllTypes{}) == " + ".google.api.expr.test.v1.proto3.TestAllTypes"; - runTest(Activation.EMPTY); + runTest(); // Test whether a type name is recognized as a type. source = "type(TestAllTypes) == type"; - runTest(Activation.EMPTY); + runTest(); // Test whether the type resolution of a proto object is recognized as the message's type. source = "type(TestAllTypes{}) == TestAllTypes"; - runTest(Activation.EMPTY); + runTest(); // Test whether null resolves to null_type. source = "type(null) == null_type"; - runTest(Activation.EMPTY); + runTest(); } @Test @@ -1815,7 +1841,7 @@ public void wrappers() throws Exception { + "x.single_string_wrapper == 'hello' && " + "x.single_uint32_wrapper == 12u && " + "x.single_uint64_wrapper == 34u"; - runTest(Activation.of("x", wrapperBindings)); + runTest(ImmutableMap.of("x", wrapperBindings)); source = "x.single_bool_wrapper == google.protobuf.BoolValue{} && " @@ -1828,7 +1854,7 @@ public void wrappers() throws Exception { + "x.single_uint32_wrapper == google.protobuf.UInt32Value{value: 12u} && " + "x.single_uint64_wrapper == google.protobuf.UInt64Value{value: 34u}"; runTest( - Activation.of( + ImmutableMap.of( "x", wrapperBindings .setSingleBoolWrapper(BoolValue.getDefaultInstance()) @@ -1844,13 +1870,13 @@ public void wrappers() throws Exception { + "x.single_string_wrapper == null && " + "x.single_uint32_wrapper == null && " + "x.single_uint64_wrapper == null"; - runTest(Activation.of("x", TestAllTypes.getDefaultInstance())); + runTest(ImmutableMap.of("x", TestAllTypes.getDefaultInstance())); } @Test - public void longComprehension() throws Exception { + public void longComprehension() { ImmutableList l = LongStream.range(0L, 1000L).boxed().collect(toImmutableList()); - eval.registrar().add("constantLongList", ImmutableList.of(), args -> l); + addFunctionBinding(CelFunctionBinding.from("constantLongList", ImmutableList.of(), args -> l)); // Comprehension over compile-time constant long list. declareFunction( @@ -1858,19 +1884,20 @@ public void longComprehension() throws Exception { globalOverload( "constantLongList", ImmutableList.of(), CelTypes.createList(CelTypes.INT64))); source = "size(constantLongList().map(x, x+1)) == 1000"; - runTest(Activation.EMPTY); + runTest(); // Comprehension over long list that is not compile-time constant. declareVariable("longlist", CelTypes.createList(CelTypes.INT64)); source = "size(longlist.map(x, x+1)) == 1000"; - runTest(Activation.of("longlist", l)); + runTest(ImmutableMap.of("longlist", l)); // Comprehension over long list where the computation is very slow. // (This is here pro-forma only since in the synchronous interpreter there // is no notion of a computation being slow so that another computation can // build up a stack while waiting.) - eval.registrar().add("f_slow_inc", Long.class, n -> n + 1L); - eval.registrar().add("f_unleash", Object.class, x -> x); + addFunctionBinding( + CelFunctionBinding.from("f_slow_inc", Long.class, n -> n + 1L), + CelFunctionBinding.from("f_unleash", Object.class, x -> x)); declareFunction( "f_slow_inc", globalOverload("f_slow_inc", ImmutableList.of(CelTypes.INT64), CelTypes.INT64)); @@ -1882,15 +1909,11 @@ public void longComprehension() throws Exception { ImmutableList.of("A"), CelTypes.createTypeParam("A"))); source = "f_unleash(longlist.map(x, f_slow_inc(x)))[0] == 1"; - runTest(Activation.of("longlist", l)); + runTest(ImmutableMap.of("longlist", l)); } @Test - public void maxComprehension() throws Exception { - if (eval.celOptions().comprehensionMaxIterations() < 0) { - skipBaselineVerification(); - return; - } + public void maxComprehension() { // Comprehension over long list that is not compile-time constant. declareVariable("longlist", CelTypes.createList(CelTypes.INT64)); source = "size(longlist.map(x, x+1)) == 1000"; @@ -1898,31 +1921,31 @@ public void maxComprehension() throws Exception { // Comprehension which exceeds the configured iteration limit. ImmutableList tooLongList = LongStream.range(0L, COMPREHENSION_MAX_ITERATIONS + 1).boxed().collect(toImmutableList()); - runTest(Activation.of("longlist", tooLongList)); + runTest(ImmutableMap.of("longlist", tooLongList)); // Sequential iterations within the collective limit of 1000. source = "longlist.filter(i, i % 2 == 0).map(i, i * 2).map(i, i / 2).size() == 250"; ImmutableList l = LongStream.range(0L, COMPREHENSION_MAX_ITERATIONS / 2).boxed().collect(toImmutableList()); - runTest(Activation.of("longlist", l)); + runTest(ImmutableMap.of("longlist", l)); // Sequential iterations outside the limit of 1000. source = "(longlist + [0]).filter(i, i % 2 == 0).map(i, i * 2).map(i, i / 2).size() == 251"; - runTest(Activation.of("longlist", l)); + runTest(ImmutableMap.of("longlist", l)); // Nested iteration within the iteration limit. // Note, there is some double-counting of the inner-loops which causes the iteration limit to // get tripped sooner than one might expect for the nested case. source = "longlist.map(i, longlist.map(j, longlist.map(k, [i, j, k]))).size() == 9"; l = LongStream.range(0L, 9).boxed().collect(toImmutableList()); - runTest(Activation.of("longlist", l)); + runTest(ImmutableMap.of("longlist", l)); // Nested iteration which exceeds the iteration limit. This result may be surprising, but the // limit is tripped precisely because each complete iteration of an inner-loop counts as inner- // loop + 1 as there's not a clean way to deduct an iteration and only count the inner most // loop. l = LongStream.range(0L, 10).boxed().collect(toImmutableList()); - runTest(Activation.of("longlist", l)); + runTest(ImmutableMap.of("longlist", l)); } @Test @@ -1948,8 +1971,8 @@ public void dynamicMessage_adapted() throws Exception { ListValue.newBuilder().addValues(Value.newBuilder().setStringValue("d")).build()) .build(); - Activation activation = - Activation.of( + ImmutableMap input = + ImmutableMap.of( "msg", DynamicMessage.parseFrom( TestAllTypes.getDescriptor(), @@ -1959,51 +1982,51 @@ public void dynamicMessage_adapted() throws Exception { declareVariable("msg", CelTypes.createMessage(TestAllTypes.getDescriptor().getFullName())); source = "msg.single_any"; - assertThat(runTest(activation)).isInstanceOf(NestedMessage.class); + assertThat(runTest(input)).isInstanceOf(NestedMessage.class); source = "msg.single_bool_wrapper"; - assertThat(runTest(activation)).isInstanceOf(Boolean.class); + assertThat(runTest(input)).isInstanceOf(Boolean.class); source = "msg.single_bytes_wrapper"; - assertThat(runTest(activation)).isInstanceOf(String.class); + assertThat(runTest(input)).isInstanceOf(String.class); source = "msg.single_double_wrapper"; - assertThat(runTest(activation)).isInstanceOf(Double.class); + assertThat(runTest(input)).isInstanceOf(Double.class); source = "msg.single_float_wrapper"; - assertThat(runTest(activation)).isInstanceOf(Double.class); + assertThat(runTest(input)).isInstanceOf(Double.class); source = "msg.single_int32_wrapper"; - assertThat(runTest(activation)).isInstanceOf(Long.class); + assertThat(runTest(input)).isInstanceOf(Long.class); source = "msg.single_int64_wrapper"; - assertThat(runTest(activation)).isInstanceOf(Long.class); + assertThat(runTest(input)).isInstanceOf(Long.class); source = "msg.single_string_wrapper"; - assertThat(runTest(activation)).isInstanceOf(String.class); + assertThat(runTest(input)).isInstanceOf(String.class); source = "msg.single_uint32_wrapper"; - assertThat(runTest(activation)) - .isInstanceOf(eval.celOptions().enableUnsignedLongs() ? UnsignedLong.class : Long.class); + assertThat(runTest(input)) + .isInstanceOf(celOptions.enableUnsignedLongs() ? UnsignedLong.class : Long.class); source = "msg.single_uint64_wrapper"; - assertThat(runTest(activation)) - .isInstanceOf(eval.celOptions().enableUnsignedLongs() ? UnsignedLong.class : Long.class); + assertThat(runTest(input)) + .isInstanceOf(celOptions.enableUnsignedLongs() ? UnsignedLong.class : Long.class); source = "msg.single_duration"; - assertThat(runTest(activation)).isInstanceOf(Duration.class); + assertThat(runTest(input)).isInstanceOf(Duration.class); source = "msg.single_timestamp"; - assertThat(runTest(activation)).isInstanceOf(Timestamp.class); + assertThat(runTest(input)).isInstanceOf(Timestamp.class); source = "msg.single_value"; - assertThat(runTest(activation)).isInstanceOf(String.class); + assertThat(runTest(input)).isInstanceOf(String.class); source = "msg.single_struct"; - assertThat(runTest(activation)).isInstanceOf(Map.class); + assertThat(runTest(input)).isInstanceOf(Map.class); source = "msg.list_value"; - assertThat(runTest(activation)).isInstanceOf(List.class); + assertThat(runTest(input)).isInstanceOf(List.class); } @Test @@ -2011,65 +2034,65 @@ public void dynamicMessage_dynamicDescriptor() throws Exception { container = "dev.cel.testing.testdata.serialized.proto3"; source = "TestAllTypes {}"; - assertThat(runTest(Activation.EMPTY)).isInstanceOf(DynamicMessage.class); + assertThat(runTest()).isInstanceOf(DynamicMessage.class); source = "TestAllTypes { single_int32: 1, single_int64: 2, single_string: 'hello'}"; - assertThat(runTest(Activation.EMPTY)).isInstanceOf(DynamicMessage.class); + assertThat(runTest()).isInstanceOf(DynamicMessage.class); source = "TestAllTypes { single_int32: 1, single_int64: 2, single_string: 'hello'}.single_string"; - assertThat(runTest(Activation.EMPTY)).isInstanceOf(String.class); + assertThat(runTest()).isInstanceOf(String.class); // Test wrappers source = "TestAllTypes { single_int32_wrapper: 3 }.single_int32_wrapper"; - assertThat(runTest(Activation.EMPTY)).isInstanceOf(Long.class); + assertThat(runTest()).isInstanceOf(Long.class); source = "TestAllTypes { single_int64_wrapper: 3 }.single_int64_wrapper"; - assertThat(runTest(Activation.EMPTY)).isInstanceOf(Long.class); + assertThat(runTest()).isInstanceOf(Long.class); source = "TestAllTypes { single_bool_wrapper: true }.single_bool_wrapper"; - assertThat(runTest(Activation.EMPTY)).isInstanceOf(Boolean.class); + assertThat(runTest()).isInstanceOf(Boolean.class); source = "TestAllTypes { single_bytes_wrapper: b'abc' }.single_bytes_wrapper"; - assertThat(runTest(Activation.EMPTY)).isInstanceOf(String.class); + assertThat(runTest()).isInstanceOf(String.class); source = "TestAllTypes { single_float_wrapper: 1.1 }.single_float_wrapper"; - assertThat(runTest(Activation.EMPTY)).isInstanceOf(Double.class); + assertThat(runTest()).isInstanceOf(Double.class); source = "TestAllTypes { single_double_wrapper: 1.1 }.single_double_wrapper"; - assertThat(runTest(Activation.EMPTY)).isInstanceOf(Double.class); + assertThat(runTest()).isInstanceOf(Double.class); source = "TestAllTypes { single_uint32_wrapper: 2u}.single_uint32_wrapper"; - assertThat(runTest(Activation.EMPTY)) - .isInstanceOf(eval.celOptions().enableUnsignedLongs() ? UnsignedLong.class : Long.class); + assertThat(runTest()) + .isInstanceOf(celOptions.enableUnsignedLongs() ? UnsignedLong.class : Long.class); source = "TestAllTypes { single_uint64_wrapper: 2u}.single_uint64_wrapper"; - assertThat(runTest(Activation.EMPTY)) - .isInstanceOf(eval.celOptions().enableUnsignedLongs() ? UnsignedLong.class : Long.class); + assertThat(runTest()) + .isInstanceOf(celOptions.enableUnsignedLongs() ? UnsignedLong.class : Long.class); source = "TestAllTypes { single_list_value: ['a', 1.5, true] }.single_list_value"; - assertThat(runTest(Activation.EMPTY)).isInstanceOf(List.class); + assertThat(runTest()).isInstanceOf(List.class); // Test nested messages source = "TestAllTypes { standalone_message: TestAllTypes.NestedMessage { } }.standalone_message"; - assertThat(runTest(Activation.EMPTY)).isInstanceOf(DynamicMessage.class); + assertThat(runTest()).isInstanceOf(DynamicMessage.class); source = "TestAllTypes { standalone_message: TestAllTypes.NestedMessage { bb: 5}" + " }.standalone_message.bb"; - assertThat(runTest(Activation.EMPTY)).isInstanceOf(Long.class); + assertThat(runTest()).isInstanceOf(Long.class); source = "TestAllTypes { standalone_enum: TestAllTypes.NestedEnum.BAR }.standalone_enum"; - assertThat(runTest(Activation.EMPTY)).isInstanceOf(Long.class); + assertThat(runTest()).isInstanceOf(Long.class); source = "TestAllTypes { map_string_string: {'key': 'value'}}"; - assertThat(runTest(Activation.EMPTY)).isInstanceOf(DynamicMessage.class); + assertThat(runTest()).isInstanceOf(DynamicMessage.class); source = "TestAllTypes { map_string_string: {'key': 'value'}}.map_string_string"; - assertThat(runTest(Activation.EMPTY)).isInstanceOf(Map.class); + assertThat(runTest()).isInstanceOf(Map.class); source = "TestAllTypes { map_string_string: {'key': 'value'}}.map_string_string['key']"; - assertThat(runTest(Activation.EMPTY)).isInstanceOf(String.class); + assertThat(runTest()).isInstanceOf(String.class); // Test any unpacking // With well-known type Any anyDuration = Any.pack(Durations.fromSeconds(100)); declareVariable("dur", CelTypes.TIMESTAMP); source = "TestAllTypes { single_any: dur }.single_any"; - assertThat(runTest(Activation.of("dur", anyDuration))).isInstanceOf(Duration.class); + assertThat(runTest(ImmutableMap.of("dur", anyDuration))).isInstanceOf(Duration.class); // with custom message clearAllDeclarations(); Any anyTestMsg = Any.pack(TestAllTypes.newBuilder().setSingleString("hello").build()); declareVariable( "any_packed_test_msg", CelTypes.createMessage(TestAllTypes.getDescriptor().getFullName())); source = "TestAllTypes { single_any: any_packed_test_msg }.single_any"; - assertThat(runTest(Activation.of("any_packed_test_msg", anyTestMsg))) + assertThat(runTest(ImmutableMap.of("any_packed_test_msg", anyTestMsg))) .isInstanceOf(TestAllTypes.class); // Test JSON map behavior @@ -2079,14 +2102,15 @@ public void dynamicMessage_dynamicDescriptor() throws Exception { DynamicMessage.Builder dynamicMessageBuilder = DynamicMessage.newBuilder(TEST_ALL_TYPE_DYNAMIC_DESCRIPTOR); JsonFormat.parser().merge("{ 'map_string_string' : { 'foo' : 'bar' } }", dynamicMessageBuilder); - Activation activation = Activation.of("dynamic_msg", dynamicMessageBuilder.build()); + ImmutableMap input = + ImmutableMap.of("dynamic_msg", dynamicMessageBuilder.build()); source = "dynamic_msg"; - assertThat(runTest(activation)).isInstanceOf(DynamicMessage.class); + assertThat(runTest(input)).isInstanceOf(DynamicMessage.class); source = "dynamic_msg.map_string_string"; - assertThat(runTest(activation)).isInstanceOf(Map.class); + assertThat(runTest(input)).isInstanceOf(Map.class); source = "dynamic_msg.map_string_string['foo']"; - assertThat(runTest(activation)).isInstanceOf(String.class); + assertThat(runTest(input)).isInstanceOf(String.class); // Test function dispatch declareFunction( @@ -2100,21 +2124,135 @@ public void dynamicMessage_dynamicDescriptor() throws Exception { ImmutableList.of( CelTypes.createMessage(TEST_ALL_TYPE_DYNAMIC_DESCRIPTOR.getFullName())), CelTypes.BOOL)); - eval.registrar().add("f_msg_generated", TestAllTypes.class, x -> true); - eval.registrar().add("f_msg_dynamic", DynamicMessage.class, x -> true); - activation = - Activation.copyOf( - ImmutableMap.of( - "dynamic_msg", dynamicMessageBuilder.build(), - "test_msg", TestAllTypes.newBuilder().setSingleInt64(10L).build())); + addFunctionBinding( + CelFunctionBinding.from("f_msg_generated", TestAllTypes.class, x -> true), + CelFunctionBinding.from("f_msg_dynamic", DynamicMessage.class, x -> true)); + input = + ImmutableMap.of( + "dynamic_msg", dynamicMessageBuilder.build(), + "test_msg", TestAllTypes.newBuilder().setSingleInt64(10L).build()); source = "f_msg(dynamic_msg)"; - assertThat(runTest(activation)).isInstanceOf(Boolean.class); + assertThat(runTest(input)).isInstanceOf(Boolean.class); source = "f_msg(test_msg)"; - assertThat(runTest(activation)).isInstanceOf(Boolean.class); + assertThat(runTest(input)).isInstanceOf(Boolean.class); + } + + /** + * Checks that the CheckedExpr produced by CelCompiler is equal to the one reproduced by the + * native CelAbstractSyntaxTree + */ + private static void assertAstRoundTrip(CelAbstractSyntaxTree ast) { + CheckedExpr checkedExpr = CelProtoAbstractSyntaxTree.fromCelAst(ast).toCheckedExpr(); + CelProtoAbstractSyntaxTree protoAst = CelProtoAbstractSyntaxTree.fromCelAst(ast); + assertThat(checkedExpr).isEqualTo(protoAst.toCheckedExpr()); } private static String readResourceContent(String path) throws IOException { return Resources.toString(Resources.getResource(Ascii.toLowerCase(path)), UTF_8); } + + @SuppressWarnings("unchecked") + private void printBinding(Object input) { + if (input instanceof Map) { + Map inputMap = (Map) input; + if (inputMap.isEmpty()) { + println("bindings: {}"); + return; + } + + boolean first = true; + StringBuilder sb = new StringBuilder().append("{"); + for (Map.Entry entry : ((Map) input).entrySet()) { + if (!first) { + sb.append(", "); + } + first = false; + sb.append(entry.getKey()); + sb.append("="); + Object value = entry.getValue(); + if (value instanceof ByteString) { + sb.append(getHumanReadableString((ByteString) value)); + } else { + sb.append(entry.getValue()); + } + } + sb.append("}"); + println("bindings: " + sb); + } else { + println("bindings: " + input); + } + } + + private static String getHumanReadableString(ByteString byteString) { + // Very unfortunate we have to do this at all + StringBuilder sb = new StringBuilder(); + sb.append("["); + for (ByteIterator i = byteString.iterator(); i.hasNext(); ) { + byte b = i.nextByte(); + sb.append(b); + if (i.hasNext()) { + sb.append(", "); + } + } + sb.append("]"); + return sb.toString(); + } + + private static final class TestOnlyVariableResolver implements CelVariableResolver { + private final Map map; + + private static TestOnlyVariableResolver newInstance(Map map) { + return new TestOnlyVariableResolver(map); + } + + @Override + public Optional find(String name) { + return Optional.ofNullable(RuntimeHelpers.maybeAdaptPrimitive(map.get(name))); + } + + @Override + public String toString() { + return map.toString(); + } + + private TestOnlyVariableResolver(Map map) { + this.map = map; + } + } + + private static CelVariableResolver extend(Map primary, Map secondary) { + return hierarchicalVariableResolver( + TestOnlyVariableResolver.newInstance(primary), + TestOnlyVariableResolver.newInstance(secondary)); + } + + private static CelVariableResolver extend(CelVariableResolver primary, Map secondary) { + return hierarchicalVariableResolver(primary, TestOnlyVariableResolver.newInstance(secondary)); + } + + private void addFunctionBinding(CelRuntime.CelFunctionBinding... functionBindings) { + celRuntime = celRuntime.toRuntimeBuilder().addFunctionBindings(functionBindings).build(); + } + + private static Descriptor getDeserializedTestAllTypeDescriptor() { + try { + String fdsContent = readResourceContent("testdata/proto3/test_all_types.fds"); + FileDescriptorSet fds = TextFormat.parse(fdsContent, FileDescriptorSet.class); + ImmutableSet fileDescriptors = FileDescriptorSetConverter.convert(fds); + + return fileDescriptors.stream() + .flatMap(f -> f.getMessageTypes().stream()) + .filter( + x -> + x.getFullName().equals("dev.cel.testing.testdata.serialized.proto3.TestAllTypes")) + .findAny() + .orElseThrow( + () -> + new IllegalStateException( + "Could not find deserialized TestAllTypes descriptor.")); + } catch (IOException e) { + throw new RuntimeException("Error loading TestAllTypes descriptor", e); + } + } } diff --git a/testing/src/main/java/dev/cel/testing/BaselineTestCase.java b/testing/src/main/java/dev/cel/testing/BaselineTestCase.java index aa4215030..493106451 100644 --- a/testing/src/main/java/dev/cel/testing/BaselineTestCase.java +++ b/testing/src/main/java/dev/cel/testing/BaselineTestCase.java @@ -99,6 +99,10 @@ protected PrintWriter testOutput() { return writer; } + protected void println(String text) { + writer.println(text); + } + /** * A test watcher which calls baseline verification if the test succeeded. This is like @After, * but verification is only done if there haven't been other errors. diff --git a/testing/src/main/java/dev/cel/testing/Eval.java b/testing/src/main/java/dev/cel/testing/Eval.java deleted file mode 100644 index 2a2b4f5e8..000000000 --- a/testing/src/main/java/dev/cel/testing/Eval.java +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2022 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.testing; - -import com.google.common.collect.ImmutableList; -import com.google.errorprone.annotations.CheckReturnValue; -import com.google.protobuf.Descriptors.FileDescriptor; -import dev.cel.common.CelAbstractSyntaxTree; -import dev.cel.common.CelOptions; -import dev.cel.runtime.Activation; -import dev.cel.runtime.InterpreterException; -import dev.cel.runtime.Registrar; - -/** - * The {@code Eval} interface is used to model the core concerns of CEL evaluation during testing. - */ -@CheckReturnValue -public interface Eval { - /** Returns the set of file descriptors configured for evaluation. */ - ImmutableList fileDescriptors(); - - /** Returns the function / type registrar used during evaluation. */ - Registrar registrar(); - - CelOptions celOptions(); - - /** Adapts a Java POJO to a CEL value. */ - Object adapt(Object value) throws InterpreterException; - - /** Evaluates an {@code ast} against a set of inputs represented by the {@code Activation}. */ - Object eval(CelAbstractSyntaxTree ast, Activation activation) throws Exception; -} diff --git a/testing/src/main/java/dev/cel/testing/EvalCelValueSync.java b/testing/src/main/java/dev/cel/testing/EvalCelValueSync.java deleted file mode 100644 index 5b6a69bfa..000000000 --- a/testing/src/main/java/dev/cel/testing/EvalCelValueSync.java +++ /dev/null @@ -1,95 +0,0 @@ -// 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.testing; - -import com.google.common.collect.ImmutableList; -import com.google.protobuf.Descriptors.FileDescriptor; -import dev.cel.common.CelAbstractSyntaxTree; -import dev.cel.common.CelDescriptorUtil; -import dev.cel.common.CelDescriptors; -import dev.cel.common.CelOptions; -import dev.cel.common.internal.DefaultDescriptorPool; -import dev.cel.common.internal.DefaultMessageFactory; -import dev.cel.common.internal.DynamicProto; -import dev.cel.common.internal.ProtoMessageFactory; -import dev.cel.common.values.CelValueProvider; -import dev.cel.common.values.ProtoMessageValueProvider; -import dev.cel.runtime.Activation; -import dev.cel.runtime.DefaultDispatcher; -import dev.cel.runtime.DefaultInterpreter; -import dev.cel.runtime.Interpreter; -import dev.cel.runtime.InterpreterException; -import dev.cel.runtime.Registrar; -import dev.cel.runtime.RuntimeTypeProvider; -import dev.cel.runtime.RuntimeTypeProviderLegacyImpl; - -/** - * The {@link EvalSync} class represents common concerns for synchronous evaluation using {@code - * CelValue}. - */ -public final class EvalCelValueSync implements Eval { - - private final ImmutableList fileDescriptors; - private final DefaultDispatcher dispatcher; - private final Interpreter interpreter; - private final RuntimeTypeProvider typeProvider; - private final CelOptions celOptions; - - public EvalCelValueSync(ImmutableList fileDescriptors, CelOptions celOptions) { - this.fileDescriptors = fileDescriptors; - this.dispatcher = DefaultDispatcher.create(celOptions); - this.celOptions = celOptions; - this.typeProvider = newTypeProvider(fileDescriptors); - this.interpreter = new DefaultInterpreter(typeProvider, dispatcher, celOptions); - } - - private RuntimeTypeProvider newTypeProvider(ImmutableList fileDescriptors) { - CelDescriptors celDescriptors = - CelDescriptorUtil.getAllDescriptorsFromFileDescriptor(fileDescriptors); - DefaultDescriptorPool celDescriptorPool = DefaultDescriptorPool.create(celDescriptors); - ProtoMessageFactory messageFactory = DefaultMessageFactory.create(celDescriptorPool); - DynamicProto dynamicProto = DynamicProto.create(messageFactory); - CelValueProvider messageValueProvider = - ProtoMessageValueProvider.newInstance(dynamicProto, celOptions); - - return new RuntimeTypeProviderLegacyImpl( - celOptions, messageValueProvider, celDescriptorPool, dynamicProto); - } - - @Override - public ImmutableList fileDescriptors() { - return fileDescriptors; - } - - @Override - public Registrar registrar() { - return dispatcher; - } - - @Override - public CelOptions celOptions() { - return celOptions; - } - - @Override - public Object adapt(Object value) throws InterpreterException { - return typeProvider.adapt(value); - } - - @Override - public Object eval(CelAbstractSyntaxTree ast, Activation activation) throws Exception { - return interpreter.createInterpretable(ast).eval(activation); - } -} diff --git a/testing/src/main/java/dev/cel/testing/EvalSync.java b/testing/src/main/java/dev/cel/testing/EvalSync.java deleted file mode 100644 index 562043ce6..000000000 --- a/testing/src/main/java/dev/cel/testing/EvalSync.java +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2022 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.testing; - -import com.google.common.collect.ImmutableList; -import com.google.protobuf.Descriptors.FileDescriptor; -import dev.cel.common.CelAbstractSyntaxTree; -import dev.cel.common.CelDescriptorUtil; -import dev.cel.common.CelDescriptors; -import dev.cel.common.CelOptions; -import dev.cel.common.internal.DefaultDescriptorPool; -import dev.cel.common.internal.DefaultMessageFactory; -import dev.cel.runtime.Activation; -import dev.cel.runtime.DefaultDispatcher; -import dev.cel.runtime.DefaultInterpreter; -import dev.cel.runtime.DescriptorMessageProvider; -import dev.cel.runtime.Interpreter; -import dev.cel.runtime.InterpreterException; -import dev.cel.runtime.Registrar; -import dev.cel.runtime.RuntimeTypeProvider; - -/** The {@code EvalSync} class represents common concerns for synchronous evaluation. */ -public final class EvalSync implements Eval { - - private final ImmutableList fileDescriptors; - private final DefaultDispatcher dispatcher; - private final Interpreter interpreter; - private final RuntimeTypeProvider typeProvider; - private final CelOptions celOptions; - - public EvalSync(ImmutableList fileDescriptors, CelOptions celOptions) { - this.fileDescriptors = fileDescriptors; - this.dispatcher = DefaultDispatcher.create(celOptions); - CelDescriptors celDescriptors = - CelDescriptorUtil.getAllDescriptorsFromFileDescriptor(fileDescriptors); - this.typeProvider = - new DescriptorMessageProvider( - DefaultMessageFactory.create(DefaultDescriptorPool.create(celDescriptors)), celOptions); - this.interpreter = new DefaultInterpreter(typeProvider, dispatcher, celOptions); - this.celOptions = celOptions; - } - - @Override - public ImmutableList fileDescriptors() { - return fileDescriptors; - } - - @Override - public Registrar registrar() { - return dispatcher; - } - - @Override - public CelOptions celOptions() { - return celOptions; - } - - @Override - public Object adapt(Object value) throws InterpreterException { - return typeProvider.adapt(value); - } - - @Override - public Object eval(CelAbstractSyntaxTree ast, Activation activation) throws Exception { - return interpreter.createInterpretable(ast).eval(activation); - } -} diff --git a/testing/src/test/java/dev/cel/testing/BUILD.bazel b/testing/src/test/java/dev/cel/testing/BUILD.bazel index 6e4980c8a..90cf73e3a 100644 --- a/testing/src/test/java/dev/cel/testing/BUILD.bazel +++ b/testing/src/test/java/dev/cel/testing/BUILD.bazel @@ -10,19 +10,7 @@ java_library( srcs = glob(["*.java"]), deps = [ "//:java_truth", - "//common", - "//common:options", - "//common/types", - "//common/types:type_providers", - "//compiler", - "//compiler:compiler_builder", - "//parser:macro", - "//runtime:base", - "//runtime:interpreter", "//testing:line_differ", - "//testing:sync", - "@@protobuf~//java/core", - "@com_google_googleapis//google/type:type_java_proto", "@maven//:com_google_guava_guava", "@maven//:junit_junit", ], diff --git a/testing/src/test/java/dev/cel/testing/EvalSyncTest.java b/testing/src/test/java/dev/cel/testing/EvalSyncTest.java deleted file mode 100644 index 438ba0c43..000000000 --- a/testing/src/test/java/dev/cel/testing/EvalSyncTest.java +++ /dev/null @@ -1,185 +0,0 @@ -// Copyright 2022 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.testing; - -import static com.google.common.truth.Truth.assertThat; - -import com.google.common.collect.ImmutableList; -import com.google.common.primitives.UnsignedLong; -import com.google.protobuf.Any; -import com.google.protobuf.BoolValue; -import com.google.protobuf.ByteString; -import com.google.protobuf.BytesValue; -import com.google.protobuf.Descriptors.FileDescriptor; -import com.google.protobuf.DoubleValue; -import com.google.protobuf.FloatValue; -import com.google.protobuf.Int32Value; -import com.google.protobuf.Int64Value; -import com.google.protobuf.Message; -import com.google.protobuf.StringValue; -import com.google.protobuf.UInt32Value; -import com.google.protobuf.UInt64Value; -import com.google.type.Expr; -import dev.cel.common.CelAbstractSyntaxTree; -import dev.cel.common.CelOptions; -import dev.cel.common.types.CelType; -import dev.cel.common.types.SimpleType; -import dev.cel.compiler.CelCompiler; -import dev.cel.compiler.CelCompilerFactory; -import dev.cel.parser.CelStandardMacro; -import dev.cel.runtime.Activation; -import dev.cel.runtime.InterpreterException; -import java.util.Arrays; -import java.util.List; -import org.junit.Test; -import org.junit.experimental.runners.Enclosed; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; - -@RunWith(Enclosed.class) -public final class EvalSyncTest { - private static final ImmutableList TEST_FILE_DESCRIPTOR = - ImmutableList.of(Expr.getDescriptor().getFile()); - - private static final CelOptions TEST_OPTIONS = CelOptions.current().build(); - - private static final EvalSync EVAL = new EvalSync(TEST_FILE_DESCRIPTOR, TEST_OPTIONS); - - @RunWith(JUnit4.class) - public static class EvalSyncApiTests { - @Test - public void fileDescriptorsTest() { - assertThat(EVAL.fileDescriptors()).isEqualTo(TEST_FILE_DESCRIPTOR); - } - } - - @RunWith(Parameterized.class) - public static class ProtoTypeAdapterTests { - - @Parameters - public static List data() { - return Arrays.asList( - new Object[][] { - {BoolValue.of(true), true}, - {BoolValue.of(false), false}, - {DoubleValue.of(1.5D), 1.5D}, - {FloatValue.of(1.5f), 1.5D}, - {StringValue.of("test"), "test"}, - {Int32Value.of(1), 1L}, - {Int64Value.of(1), 1L}, - {UInt32Value.of(1), UnsignedLong.valueOf(1L)}, - {UInt64Value.of(1), UnsignedLong.valueOf(1L)}, - {BytesValue.of(ByteString.copyFromUtf8("test")), ByteString.copyFromUtf8("test")}, - }); - } - - private final Message protoMessage; - private final Object nativeValue; - - public ProtoTypeAdapterTests(Message protoMessage, Object nativeValue) { - this.protoMessage = protoMessage; - this.nativeValue = nativeValue; - } - - @Test - public void protoMessageAdapt_convertsToNativeValues() throws InterpreterException { - assertThat(EVAL.adapt(protoMessage)).isEqualTo(nativeValue); - assertThat(EVAL.adapt(Any.pack(protoMessage))).isEqualTo(nativeValue); - } - - @Test - public void nativeValueAdapt_doesNothing() throws InterpreterException { - assertThat(EVAL.adapt(nativeValue)).isEqualTo(nativeValue); - } - } - - /** - * Test cases to show that basic evaluation is working as intended. A comprehensive set of tests - * can be found in {@code BaseInterpreterTest}. - */ - @RunWith(Parameterized.class) - public static class EvalWithoutActivationTests { - private final String expr; - private final Object evaluatedResult; - - private static final CelCompiler COMPILER = - CelCompilerFactory.standardCelCompilerBuilder() - .setOptions(TEST_OPTIONS) - .setStandardMacros(CelStandardMacro.STANDARD_MACROS) - .build(); - - @Parameters - public static List data() { - return Arrays.asList( - new Object[][] { - {"1 < 2", true}, - {"1 + 2 + 3", 6L}, - {"1.9 + 2.0", 3.9}, - {"true == true", true}, - }); - } - - public EvalWithoutActivationTests(String expr, Object evaluatedResult) { - this.expr = expr; - this.evaluatedResult = evaluatedResult; - } - - @Test - public void evaluateExpr_returnsExpectedResult() throws Exception { - CelAbstractSyntaxTree ast = COMPILER.compile(expr).getAst(); - assertThat(EVAL.eval(ast, Activation.EMPTY)).isEqualTo(evaluatedResult); - } - } - - @RunWith(Parameterized.class) - public static class EvalWithActivationTests { - private final String expr; - private final Object paramValue; - private final Object evaluatedResult; - private final CelCompiler compiler; - - @Parameters - public static List data() { - return Arrays.asList( - new Object[][] { - {"x < 2", 1, SimpleType.INT, true}, - {"x + 2 + 3", 1, SimpleType.INT, 6L}, - {"x + 2.0", 1.9, SimpleType.DOUBLE, 3.9}, - {"x == true", true, SimpleType.BOOL, true}, - }); - } - - public EvalWithActivationTests( - String expr, Object paramValue, CelType paramType, Object evaluatedResult) { - this.expr = expr; - this.paramValue = paramValue; - this.evaluatedResult = evaluatedResult; - this.compiler = - CelCompilerFactory.standardCelCompilerBuilder() - .setOptions(TEST_OPTIONS) - .setStandardMacros(CelStandardMacro.STANDARD_MACROS) - .addVar("x", paramType) - .build(); - } - - @Test - public void expr_returnsExpectedResult() throws Exception { - CelAbstractSyntaxTree ast = compiler.compile(expr).getAst(); - assertThat(EVAL.eval(ast, Activation.of("x", paramValue))).isEqualTo(evaluatedResult); - } - } -} From 7398767f80578ae0b23f25d7484dde699b023544 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Fri, 30 Aug 2024 09:11:23 -0700 Subject: [PATCH 189/486] Provide an overload to accept a depth level in flatten function PiperOrigin-RevId: 669346696 --- .../cel/extensions/CelListsExtensions.java | 28 ++++++++++------- .../main/java/dev/cel/extensions/README.md | 22 +++++++++++--- .../extensions/CelListsExtensionsTest.java | 30 +++++++++++++++++++ 3 files changed, 66 insertions(+), 14 deletions(-) diff --git a/extensions/src/main/java/dev/cel/extensions/CelListsExtensions.java b/extensions/src/main/java/dev/cel/extensions/CelListsExtensions.java index 06eccd16b..55b5c723e 100644 --- a/extensions/src/main/java/dev/cel/extensions/CelListsExtensions.java +++ b/extensions/src/main/java/dev/cel/extensions/CelListsExtensions.java @@ -21,6 +21,7 @@ import dev.cel.common.CelFunctionDecl; import dev.cel.common.CelOverloadDecl; import dev.cel.common.types.ListType; +import dev.cel.common.types.SimpleType; import dev.cel.common.types.TypeParamType; import dev.cel.compiler.CelCompilerLibrary; import dev.cel.runtime.CelRuntime; @@ -44,11 +45,18 @@ public enum Function { "list_flatten", "Flattens a list by a single level", ListType.create(LIST_PARAM_TYPE), - ListType.create(ListType.create(LIST_PARAM_TYPE)))), - // TODO: add list_flatten_list_int + ListType.create(ListType.create(LIST_PARAM_TYPE))), + CelOverloadDecl.newMemberOverload( + "list_flatten_list_int", + "Flattens a list to the specified level. A negative depth value flattens the list" + + " recursively to its deepest level.", + ListType.create(SimpleType.DYN), + ListType.create(SimpleType.DYN), + SimpleType.INT)), + CelRuntime.CelFunctionBinding.from( + "list_flatten", Collection.class, list -> flatten(list, 1)), CelRuntime.CelFunctionBinding.from( - "list_flatten", Collection.class, list -> flatten(list, 1))), - ; + "list_flatten_list_int", Collection.class, Long.class, CelListsExtensions::flatten)); private final CelFunctionDecl functionDecl; private final ImmutableSet functionBindings; @@ -84,15 +92,15 @@ public void setRuntimeOptions(CelRuntimeBuilder runtimeBuilder) { } @SuppressWarnings("unchecked") - private static ImmutableList flatten(Collection list, int level) { - Preconditions.checkArgument(level == 1, "recursive flatten is not supported yet."); + private static ImmutableList flatten(Collection list, long depth) { + Preconditions.checkArgument(depth >= 0, "Level must be non-negative"); ImmutableList.Builder builder = ImmutableList.builder(); for (Object element : list) { - if (element instanceof Collection) { - Collection listItem = (Collection) element; - builder.addAll(listItem); - } else { + if (!(element instanceof Collection) || depth == 0) { builder.add(element); + } else { + Collection listItem = (Collection) element; + builder.addAll(flatten(listItem, depth - 1)); } } diff --git a/extensions/src/main/java/dev/cel/extensions/README.md b/extensions/src/main/java/dev/cel/extensions/README.md index e99e6a93f..f240c2a21 100644 --- a/extensions/src/main/java/dev/cel/extensions/README.md +++ b/extensions/src/main/java/dev/cel/extensions/README.md @@ -413,24 +413,38 @@ zero-based. ### Flatten -Flattens a list by one level. Support for flattening to a specified level -will be provided in the future. +Flattens a list by one level, or to the specified level. Providing a negative level will error. Examples: ``` +// Single-level flatten: + [].flatten() // [] [1,[2,3],[4]].flatten() // [1, 2, 3, 4] [1,[2,[3,4]]].flatten() // [1, 2, [3, 4]] [1,2,[],[],[3,4]].flatten() // [1, 2, 3, 4] + +// Recursive flatten +[1,[2,[3,[4]]]].flatten(2) // return [1, 2, 3, [4]] +[1,[2,[3,[4]]]].flatten(3) // return [1, 2, 3, 4] + +// Error +[1,[2,[3,[4]]]].flatten(-1) ``` Note that due to the current limitations of type-checker, a compilation error -will occur if an already flat list is populated. For time being, you must wrap -the list in dyn if you anticipate having to deal with a flat list: +will occur if an already flat list is populated to the argument-less flatten +function. + +For time being, you must explicitly provide 1 as the depth level, or wrap the +list in dyn if you anticipate having to deal with a flat list: ``` [1,2,3].flatten() // error + +// But the following will work: +[1,2,3].flatten(1) // [1,2,3] dyn([1,2,3]).flatten() // [1,2,3] ``` diff --git a/extensions/src/test/java/dev/cel/extensions/CelListsExtensionsTest.java b/extensions/src/test/java/dev/cel/extensions/CelListsExtensionsTest.java index cee8de5b7..da947d879 100644 --- a/extensions/src/test/java/dev/cel/extensions/CelListsExtensionsTest.java +++ b/extensions/src/test/java/dev/cel/extensions/CelListsExtensionsTest.java @@ -22,6 +22,7 @@ import dev.cel.bundle.CelFactory; import dev.cel.common.CelValidationException; import dev.cel.parser.CelStandardMacro; +import dev.cel.runtime.CelEvaluationException; import org.junit.Test; import org.junit.runner.RunWith; @@ -50,6 +51,35 @@ public void flattenSingleLevel_success(String expression) throws Exception { assertThat(result).isTrue(); } + @Test + @TestParameters("{expression: '[1,2,3,4].flatten(1) == [1,2,3,4]'}") + @TestParameters("{expression: '[1,[2,[3,[4]]]].flatten(0) == [1,[2,[3,[4]]]]'}") + @TestParameters("{expression: '[1,[2,[3,[4]]]].flatten(2) == [1,2,3,[4]]'}") + @TestParameters("{expression: '[1,[2,[3,4]]].flatten(2) == [1,2,3,4]'}") + @TestParameters("{expression: '[[], [[]], [[[]]]].flatten(2) == [[]]'}") + @TestParameters("{expression: '[[], [[]], [[[]]]].flatten(3) == []'}") + @TestParameters("{expression: '[[], [[]], [[[]]]].flatten(4) == []'}") + // The overload with the depth accepts and returns a List(dyn), so the following is permitted. + @TestParameters("{expression: '[1].flatten(1) == [1]'}") + public void flatten_withDepthValue_success(String expression) throws Exception { + boolean result = (boolean) CEL.createProgram(CEL.compile(expression).getAst()).eval(); + + assertThat(result).isTrue(); + } + + @Test + public void flatten_negativeDepth_throws() { + CelEvaluationException e = + assertThrows( + CelEvaluationException.class, + () -> CEL.createProgram(CEL.compile("[1,2,3,4].flatten(-1)").getAst()).eval()); + + assertThat(e) + .hasMessageThat() + .contains("evaluation error: Function 'list_flatten_list_int' failed"); + assertThat(e).hasCauseThat().hasMessageThat().isEqualTo("Level must be non-negative"); + } + @Test @TestParameters("{expression: '[1].flatten()'}") @TestParameters("{expression: '[{1: 2}].flatten()'}") From 70ae9983389514ac2749eeaebe0c32225d852f02 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Fri, 30 Aug 2024 09:28:54 -0700 Subject: [PATCH 190/486] Release 0.7.0 PiperOrigin-RevId: 669351240 --- README.md | 4 ++-- WORKSPACE | 16 ++++++++-------- publish/cel_version.bzl | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index b61d940f9..ab11e96e8 100644 --- a/README.md +++ b/README.md @@ -55,14 +55,14 @@ CEL-Java is available in Maven Central Repository. [Download the JARs here][8] o dev.cel cel - 0.6.0 + 0.7.0 ``` **Gradle** ```gradle -implementation 'dev.cel:cel:0.6.0' +implementation 'dev.cel:cel:0.7.0' ``` Then run this example: diff --git a/WORKSPACE b/WORKSPACE index 37c7cd2de..f4cf32ce1 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -64,18 +64,18 @@ load("@rules_jvm_external//:setup.bzl", "rules_jvm_external_setup") rules_jvm_external_setup() -ANTLR4_VERSION = "4.13.1" +ANTLR4_VERSION = "4.13.2" # Important: there can only be one maven_install rule. Add new maven deps here. maven_install( # keep sorted artifacts = [ - "com.google.auto.value:auto-value:1.10.4", - "com.google.auto.value:auto-value-annotations:1.10.4", + "com.google.auto.value:auto-value:1.11.0", + "com.google.auto.value:auto-value-annotations:1.11.0", "com.google.code.findbugs:annotations:3.0.1", - "com.google.errorprone:error_prone_annotations:2.26.1", - "com.google.guava:guava:33.1.0-jre", - "com.google.guava:guava-testlib:33.1.0-jre", + "com.google.errorprone:error_prone_annotations:2.30.0", + "com.google.guava:guava:33.3.0-jre", + "com.google.guava:guava-testlib:33.3.0-jre", "com.google.protobuf:protobuf-java-util:4.27.3", "com.google.re2j:re2j:1.7", "com.google.testparameterinjector:test-parameter-injector:1.15", @@ -83,7 +83,7 @@ maven_install( "com.google.truth.extensions:truth-proto-extension:1.4.2", "com.google.truth:truth:1.4.2", "org.antlr:antlr4-runtime:" + ANTLR4_VERSION, - "org.jspecify:jspecify:0.3.0", + "org.jspecify:jspecify:1.0.0", "org.threeten:threeten-extra:1.8.0", "org.yaml:snakeyaml:2.2", ], @@ -168,7 +168,7 @@ http_archive( http_jar( name = "antlr4_jar", - sha256 = "bc13a9c57a8dd7d5196888211e5ede657cb64a3ce968608697e4f668251a8487", + sha256 = "eae2dfa119a64327444672aff63e9ec35a20180dc5b8090b7a6ab85125df4d76", urls = ["https://www.antlr.org/download/antlr-" + ANTLR4_VERSION + "-complete.jar"], ) diff --git a/publish/cel_version.bzl b/publish/cel_version.bzl index 96be40f81..bbea9ca1c 100644 --- a/publish/cel_version.bzl +++ b/publish/cel_version.bzl @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. """Maven artifact version for CEL.""" -CEL_VERSION = "0.6.0" +CEL_VERSION = "0.7.0" From bbb46c3b1e3fc3f52fec03183d4fdeee78272801 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Fri, 30 Aug 2024 10:46:25 -0700 Subject: [PATCH 191/486] Update protobuf version to 4.28.0 PiperOrigin-RevId: 669376433 --- WORKSPACE | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/WORKSPACE b/WORKSPACE index f4cf32ce1..4dc16ce61 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -76,7 +76,8 @@ maven_install( "com.google.errorprone:error_prone_annotations:2.30.0", "com.google.guava:guava:33.3.0-jre", "com.google.guava:guava-testlib:33.3.0-jre", - "com.google.protobuf:protobuf-java-util:4.27.3", + "com.google.protobuf:protobuf-java:4.28.0", + "com.google.protobuf:protobuf-java-util:4.28.0", "com.google.re2j:re2j:1.7", "com.google.testparameterinjector:test-parameter-injector:1.15", "com.google.truth.extensions:truth-java8-extension:1.4.2", @@ -95,9 +96,9 @@ maven_install( http_archive( name = "com_google_protobuf", - sha256 = "1535151efbc7893f38b0578e83cac584f2819974f065698976989ec71c1af84a", - strip_prefix = "protobuf-27.3", - urls = ["https://github.com/protocolbuffers/protobuf/archive/v27.3.tar.gz"], + sha256 = "13e7749c30bc24af6ee93e092422f9dc08491c7097efa69461f88eb5f61805ce", + strip_prefix = "protobuf-28.0", + urls = ["https://github.com/protocolbuffers/protobuf/archive/v28.0.tar.gz"], ) # Required by com_google_protobuf From f4292b5c0e4878d34c7ed6b370c47bd9e06d9760 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Fri, 30 Aug 2024 10:58:00 -0700 Subject: [PATCH 192/486] Release 0.7.1 PiperOrigin-RevId: 669380204 --- README.md | 4 ++-- publish/cel_version.bzl | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index ab11e96e8..7d673e4db 100644 --- a/README.md +++ b/README.md @@ -55,14 +55,14 @@ CEL-Java is available in Maven Central Repository. [Download the JARs here][8] o dev.cel cel - 0.7.0 + 0.7.1 ``` **Gradle** ```gradle -implementation 'dev.cel:cel:0.7.0' +implementation 'dev.cel:cel:0.7.1' ``` Then run this example: diff --git a/publish/cel_version.bzl b/publish/cel_version.bzl index bbea9ca1c..c232b03b8 100644 --- a/publish/cel_version.bzl +++ b/publish/cel_version.bzl @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. """Maven artifact version for CEL.""" -CEL_VERSION = "0.7.0" +CEL_VERSION = "0.7.1" From 12c7d4c6b169c809fae8bd02062593ae82b93afb Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Tue, 3 Sep 2024 10:12:50 -0700 Subject: [PATCH 193/486] Add optional.unwrap PiperOrigin-RevId: 670606059 --- .../cel/extensions/CelOptionalLibrary.java | 13 +++++++++ runtime/src/test/resources/optional.baseline | 12 +++++++++ .../test/resources/optional_errors.baseline | 5 ++++ .../src/main/java/dev/cel/testing/BUILD.bazel | 2 ++ .../dev/cel/testing/BaseInterpreterTest.java | 27 +++++++++++++++++++ 5 files changed, 59 insertions(+) create mode 100644 runtime/src/test/resources/optional.baseline create mode 100644 runtime/src/test/resources/optional_errors.baseline diff --git a/extensions/src/main/java/dev/cel/extensions/CelOptionalLibrary.java b/extensions/src/main/java/dev/cel/extensions/CelOptionalLibrary.java index dad6e0a97..6398f9965 100644 --- a/extensions/src/main/java/dev/cel/extensions/CelOptionalLibrary.java +++ b/extensions/src/main/java/dev/cel/extensions/CelOptionalLibrary.java @@ -16,6 +16,7 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.collect.ImmutableList.toImmutableList; import com.google.common.collect.ImmutableList; import com.google.common.primitives.UnsignedLong; @@ -58,6 +59,7 @@ public enum Function { HAS_VALUE("hasValue"), OPTIONAL_NONE("optional.none"), OPTIONAL_OF("optional.of"), + OPTIONAL_UNWRAP("optional.unwrap"), OPTIONAL_OF_NON_ZERO_VALUE("optional.ofNonZeroValue"), OR("or"), OR_VALUE("orValue"); @@ -117,6 +119,10 @@ public void setCheckerOptions(CelCheckerBuilder checkerBuilder) { CelFunctionDecl.newFunctionDeclaration( Function.HAS_VALUE.getFunction(), CelOverloadDecl.newMemberOverload("optional_hasValue", SimpleType.BOOL, optionalTypeV)), + CelFunctionDecl.newFunctionDeclaration( + Function.OPTIONAL_UNWRAP.getFunction(), + CelOverloadDecl.newGlobalOverload( + "optional_unwrap_list", listTypeV, ListType.create(optionalTypeV))), // Note: Implementation of "or" and "orValue" are special-cased inside the interpreter. // Hence, their bindings are not provided here. CelFunctionDecl.newFunctionDeclaration( @@ -165,6 +171,7 @@ public void setCheckerOptions(CelCheckerBuilder checkerBuilder) { } @Override + @SuppressWarnings("unchecked") public void setRuntimeOptions(CelRuntimeBuilder runtimeBuilder) { runtimeBuilder.addFunctionBindings( CelRuntime.CelFunctionBinding.from("optional_of", Object.class, Optional::of), @@ -177,6 +184,8 @@ public void setRuntimeOptions(CelRuntimeBuilder runtimeBuilder) { } return Optional.of(val); }), + CelRuntime.CelFunctionBinding.from( + "optional_unwrap_list", Collection.class, CelOptionalLibrary::elideOptionalCollection), CelRuntime.CelFunctionBinding.from( "optional_none", ImmutableList.of(), val -> Optional.empty()), CelRuntime.CelFunctionBinding.from( @@ -185,6 +194,10 @@ public void setRuntimeOptions(CelRuntimeBuilder runtimeBuilder) { "optional_hasValue", Object.class, val -> ((Optional) val).isPresent())); } + private static ImmutableList elideOptionalCollection(Collection> list) { + return list.stream().filter(Optional::isPresent).map(Optional::get).collect(toImmutableList()); + } + // TODO: This will need to be adapted to handle an intermediate CelValue instead, // akin to Zeroer interface in Go. Currently, it is unable to handle zero-values for a // user-defined custom type. diff --git a/runtime/src/test/resources/optional.baseline b/runtime/src/test/resources/optional.baseline new file mode 100644 index 000000000..1e32c2696 --- /dev/null +++ b/runtime/src/test/resources/optional.baseline @@ -0,0 +1,12 @@ +Source: optional.unwrap([]) +=====> +bindings: {} +result: [] + +Source: optional.unwrap([optional.none(), optional.of(1), optional.of(str)]) +declare str { + value string +} +=====> +bindings: {str=foo} +result: [1, foo] diff --git a/runtime/src/test/resources/optional_errors.baseline b/runtime/src/test/resources/optional_errors.baseline new file mode 100644 index 000000000..819cc0c1e --- /dev/null +++ b/runtime/src/test/resources/optional_errors.baseline @@ -0,0 +1,5 @@ +Source: optional.unwrap([dyn(1)]) +=====> +bindings: {} +error: evaluation error: Function 'optional_unwrap_list' failed with arg(s) '[1]' +error_code: INTERNAL_ERROR diff --git a/testing/src/main/java/dev/cel/testing/BUILD.bazel b/testing/src/main/java/dev/cel/testing/BUILD.bazel index 5594c37be..37f264809 100644 --- a/testing/src/main/java/dev/cel/testing/BUILD.bazel +++ b/testing/src/main/java/dev/cel/testing/BUILD.bazel @@ -100,6 +100,8 @@ java_library( "//common/internal:file_descriptor_converter", "//common/resources/testdata/proto3:standalone_global_enum_java_proto", "//common/types:cel_types", + "//common/types:type_providers", + "//extensions:optional_library", "//runtime", "//runtime:runtime_helper", "@@protobuf~//java/core", diff --git a/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java b/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java index edcf5a260..68f343a19 100644 --- a/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java +++ b/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java @@ -65,7 +65,9 @@ import dev.cel.common.CelProtoAbstractSyntaxTree; import dev.cel.common.internal.DefaultDescriptorPool; import dev.cel.common.internal.FileDescriptorSetConverter; +import dev.cel.common.types.CelTypeProvider; import dev.cel.common.types.CelTypes; +import dev.cel.extensions.CelOptionalLibrary; import dev.cel.runtime.CelEvaluationException; import dev.cel.runtime.CelRuntime; import dev.cel.runtime.CelRuntime.CelFunctionBinding; @@ -127,11 +129,19 @@ public BaseInterpreterTest(CelOptions celOptions, boolean useNativeCelType) { this.celOptions = celOptions; this.celRuntime = CelRuntimeFactory.standardCelRuntimeBuilder() + .addLibraries(CelOptionalLibrary.INSTANCE) .addFileTypes(TEST_FILE_DESCRIPTORS) .setOptions(celOptions) .build(); } + @Override + protected void prepareCompiler(CelTypeProvider typeProvider) { + super.prepareCompiler(typeProvider); + this.celCompiler = + celCompiler.toCompilerBuilder().addLibraries(CelOptionalLibrary.INSTANCE).build(); + } + private CelAbstractSyntaxTree compileTestCase() { CelAbstractSyntaxTree ast = prepareTest(TEST_FILE_DESCRIPTORS); if (ast == null) { @@ -494,6 +504,23 @@ public void messages_error() { runTest(); } + @Test + public void optional() { + // TODO: Move existing optional tests here to also test CelValue runtime + source = "optional.unwrap([])"; + runTest(); + + declareVariable("str", CelTypes.STRING); + source = "optional.unwrap([optional.none(), optional.of(1), optional.of(str)])"; + runTest(ImmutableMap.of("str", "foo")); + } + + @Test + public void optional_errors() { + source = "optional.unwrap([dyn(1)])"; + runTest(); + } + @Test public void has() throws Exception { TestAllTypes nestedMessage = From 0c37f935c1a43173b9e34b4171a25758580867c2 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Tue, 3 Sep 2024 11:02:19 -0700 Subject: [PATCH 194/486] No public description PiperOrigin-RevId: 670627244 --- checker/src/main/java/dev/cel/checker/BUILD.bazel | 1 + common/src/test/java/dev/cel/common/BUILD.bazel | 1 + parser/src/main/java/dev/cel/parser/BUILD.bazel | 2 ++ parser/src/test/java/dev/cel/parser/BUILD.bazel | 1 + policy/src/main/java/dev/cel/policy/BUILD.bazel | 2 ++ validator/src/main/java/dev/cel/validator/BUILD.bazel | 1 + 6 files changed, 8 insertions(+) diff --git a/checker/src/main/java/dev/cel/checker/BUILD.bazel b/checker/src/main/java/dev/cel/checker/BUILD.bazel index 039eb7f6c..a6ea9153b 100644 --- a/checker/src/main/java/dev/cel/checker/BUILD.bazel +++ b/checker/src/main/java/dev/cel/checker/BUILD.bazel @@ -73,6 +73,7 @@ java_library( "//common", "//common:compiler_common", "//common:options", + "//common:source_location", "//common/annotations", "//common/ast:expr_converter", "//common/internal:env_visitor", diff --git a/common/src/test/java/dev/cel/common/BUILD.bazel b/common/src/test/java/dev/cel/common/BUILD.bazel index f5c08b3b4..ad71d2862 100644 --- a/common/src/test/java/dev/cel/common/BUILD.bazel +++ b/common/src/test/java/dev/cel/common/BUILD.bazel @@ -16,6 +16,7 @@ java_library( "//common:options", "//common:proto_json_adapter", "//common:proto_v1alpha1_ast", + "//common:source_location", "//common/ast", "//common/internal", "//common/types", diff --git a/parser/src/main/java/dev/cel/parser/BUILD.bazel b/parser/src/main/java/dev/cel/parser/BUILD.bazel index e3d13b92b..53f7e5fa8 100644 --- a/parser/src/main/java/dev/cel/parser/BUILD.bazel +++ b/parser/src/main/java/dev/cel/parser/BUILD.bazel @@ -48,6 +48,7 @@ java_library( "//common", "//common:compiler_common", "//common:options", + "//common:source_location", "//common/annotations", "//common/ast", "//common/internal", @@ -82,6 +83,7 @@ java_library( "//:auto_value", "//common", "//common:compiler_common", + "//common:source_location", "//common/ast", "//common/ast:expr_factory", "@maven//:com_google_errorprone_error_prone_annotations", diff --git a/parser/src/test/java/dev/cel/parser/BUILD.bazel b/parser/src/test/java/dev/cel/parser/BUILD.bazel index fe29d5d43..2ae7e5b8b 100644 --- a/parser/src/test/java/dev/cel/parser/BUILD.bazel +++ b/parser/src/test/java/dev/cel/parser/BUILD.bazel @@ -15,6 +15,7 @@ java_library( "//common", "//common:compiler_common", "//common:options", + "//common:source_location", "//common/ast", "//common/internal", "//extensions:optional_library", diff --git a/policy/src/main/java/dev/cel/policy/BUILD.bazel b/policy/src/main/java/dev/cel/policy/BUILD.bazel index bdb651d0d..2b65da2e2 100644 --- a/policy/src/main/java/dev/cel/policy/BUILD.bazel +++ b/policy/src/main/java/dev/cel/policy/BUILD.bazel @@ -251,6 +251,7 @@ java_library( "//bundle:cel", "//common", "//common:compiler_common", + "//common:source_location", "//common/ast", "//common/types", "//common/types:type_providers", @@ -332,6 +333,7 @@ java_library( ":value_string", "//common", "//common:compiler_common", + "//common:source_location", "@maven//:com_google_guava_guava", "@maven//:org_yaml_snakeyaml", ], diff --git a/validator/src/main/java/dev/cel/validator/BUILD.bazel b/validator/src/main/java/dev/cel/validator/BUILD.bazel index a3d92d75d..ed4ecc570 100644 --- a/validator/src/main/java/dev/cel/validator/BUILD.bazel +++ b/validator/src/main/java/dev/cel/validator/BUILD.bazel @@ -68,6 +68,7 @@ java_library( "//bundle:cel", "//common", "//common:compiler_common", + "//common:source_location", "//common/navigation", "@maven//:com_google_guava_guava", ], From cd376a1589f16da9f1fd62c7cf95ede6eca01e99 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Tue, 3 Sep 2024 13:12:31 -0700 Subject: [PATCH 195/486] No public description PiperOrigin-RevId: 670678229 --- bundle/src/test/java/dev/cel/bundle/BUILD.bazel | 1 - checker/src/main/java/dev/cel/checker/BUILD.bazel | 2 +- checker/src/test/java/dev/cel/checker/BUILD.bazel | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/bundle/src/test/java/dev/cel/bundle/BUILD.bazel b/bundle/src/test/java/dev/cel/bundle/BUILD.bazel index 3ca1dd570..a324daf1d 100644 --- a/bundle/src/test/java/dev/cel/bundle/BUILD.bazel +++ b/bundle/src/test/java/dev/cel/bundle/BUILD.bazel @@ -18,7 +18,6 @@ java_library( "//common", "//common:compiler_common", "//common:options", - "//common:proto_ast", "//common/ast", "//common/resources/testdata/proto3:standalone_global_enum_java_proto", "//common/testing", diff --git a/checker/src/main/java/dev/cel/checker/BUILD.bazel b/checker/src/main/java/dev/cel/checker/BUILD.bazel index a6ea9153b..bdede0fb6 100644 --- a/checker/src/main/java/dev/cel/checker/BUILD.bazel +++ b/checker/src/main/java/dev/cel/checker/BUILD.bazel @@ -167,10 +167,10 @@ java_library( deps = [ ":cel_ident_decl", "//:auto_value", + "//common", "//common:compiler_common", "//common:features", "//common:options", - "//common:proto_ast", "//common/annotations", "//common/ast", "//common/ast:expr_converter", diff --git a/checker/src/test/java/dev/cel/checker/BUILD.bazel b/checker/src/test/java/dev/cel/checker/BUILD.bazel index ff4b87a34..96497c836 100644 --- a/checker/src/test/java/dev/cel/checker/BUILD.bazel +++ b/checker/src/test/java/dev/cel/checker/BUILD.bazel @@ -23,7 +23,6 @@ java_library( "//checker:type_provider_legacy_impl", "//common", "//common:compiler_common", - "//common:proto_ast", "//common/ast", "//common/internal:env_visitor", "//common/internal:errors", From e5a091d14eef637ee420dd12934a4dfaec826467 Mon Sep 17 00:00:00 2001 From: Tristan Swadell Date: Tue, 3 Sep 2024 14:02:34 -0700 Subject: [PATCH 196/486] Refactor CEL Policy build targets to support extension PiperOrigin-RevId: 670697589 --- policy/BUILD.bazel | 5 +++ .../src/main/java/dev/cel/policy/BUILD.bazel | 19 +++++++++- .../main/java/dev/cel/policy/ValueString.java | 14 +++++-- .../main/java/dev/cel/policy/YamlHelper.java | 37 ++++++++++--------- 4 files changed, 52 insertions(+), 23 deletions(-) diff --git a/policy/BUILD.bazel b/policy/BUILD.bazel index 4773984b4..4c18f3b7d 100644 --- a/policy/BUILD.bazel +++ b/policy/BUILD.bazel @@ -72,3 +72,8 @@ java_library( name = "compiler_builder", exports = ["//policy/src/main/java/dev/cel/policy:compiler_builder"], ) + +java_library( + name = "yaml_helper", + exports = ["//policy/src/main/java/dev/cel/policy:yaml_helper"], +) diff --git a/policy/src/main/java/dev/cel/policy/BUILD.bazel b/policy/src/main/java/dev/cel/policy/BUILD.bazel index 2b65da2e2..7176ece6a 100644 --- a/policy/src/main/java/dev/cel/policy/BUILD.bazel +++ b/policy/src/main/java/dev/cel/policy/BUILD.bazel @@ -113,6 +113,7 @@ java_library( ":source", ":validation_exception", ":value_string", + ":yaml_helper", "//common:compiler_common", "//common/internal", "@maven//:com_google_guava_guava", @@ -292,6 +293,7 @@ java_library( ":parser_context", ":source", ":validation_exception", + ":yaml_helper", "//common:compiler_common", "//common/internal", "@maven//:com_google_guava_guava", @@ -323,7 +325,6 @@ java_library( java_library( name = "common_internal", srcs = [ - "YamlHelper.java", "YamlParserContextImpl.java", ], visibility = ["//visibility:private"], @@ -331,9 +332,23 @@ java_library( ":parser_context", ":source", ":value_string", + ":yaml_helper", "//common", "//common:compiler_common", - "//common:source_location", + "@maven//:com_google_guava_guava", + "@maven//:org_yaml_snakeyaml", + ], +) + +java_library( + name = "yaml_helper", + srcs = [ + "YamlHelper.java", + ], + tags = [ + ], + deps = [ + ":parser_context", "@maven//:com_google_guava_guava", "@maven//:org_yaml_snakeyaml", ], diff --git a/policy/src/main/java/dev/cel/policy/ValueString.java b/policy/src/main/java/dev/cel/policy/ValueString.java index 24c56f4ee..f3039513f 100644 --- a/policy/src/main/java/dev/cel/policy/ValueString.java +++ b/policy/src/main/java/dev/cel/policy/ValueString.java @@ -23,18 +23,24 @@ public abstract class ValueString { /** A unique identifier. This is populated by the parser. */ public abstract long id(); + /** String value of the {@code ValueString} */ public abstract String value(); + /** Builder for {@link ValueString}. */ @AutoValue.Builder - abstract static class Builder { + public abstract static class Builder { - abstract Builder setId(long id); + /** Set the identifier for the string to associate it back to collected source metadata. */ + public abstract Builder setId(long id); - abstract Builder setValue(String value); + /** Set the string value. */ + public abstract Builder setValue(String value); - abstract ValueString build(); + /** Build the {@code ValueString}. */ + public abstract ValueString build(); } + /** Convert the {@code ValueString} to a {@code Builder}. */ public abstract Builder toBuilder(); /** Builder for {@link ValueString}. */ diff --git a/policy/src/main/java/dev/cel/policy/YamlHelper.java b/policy/src/main/java/dev/cel/policy/YamlHelper.java index 276c09be4..c289c73f6 100644 --- a/policy/src/main/java/dev/cel/policy/YamlHelper.java +++ b/policy/src/main/java/dev/cel/policy/YamlHelper.java @@ -26,10 +26,12 @@ import org.yaml.snakeyaml.nodes.Node; import org.yaml.snakeyaml.nodes.ScalarNode; -final class YamlHelper { +/** Helper class for parsing YAML. */ +public final class YamlHelper { static final String ERROR = "*error*"; - enum YamlNodeType { + /** Enum for YAML node types. */ + public enum YamlNodeType { MAP("tag:yaml.org,2002:map"), STRING("tag:yaml.org,2002:str"), BOOLEAN("tag:yaml.org,2002:bool"), @@ -50,6 +52,22 @@ String tag() { } } + /** Assert that a given YAML node matches one of the provided {@code YamlNodeType} values. */ + public static boolean assertYamlType( + ParserContext ctx, long id, Node node, YamlNodeType... expectedNodeTypes) { + if (validateYamlType(node, expectedNodeTypes)) { + return true; + } + String nodeTag = node.getTag().getValue(); + + ctx.reportError( + id, + String.format( + "Got yaml node type %s, wanted type(s) [%s]", + nodeTag, stream(expectedNodeTypes).map(YamlNodeType::tag).collect(joining(" ")))); + return false; + } + static Node parseYamlSource(String policyContent) { Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions())); @@ -79,21 +97,6 @@ static boolean validateYamlType(Node node, YamlNodeType... expectedNodeTypes) { return false; } - static boolean assertYamlType( - ParserContext ctx, long id, Node node, YamlNodeType... expectedNodeTypes) { - if (validateYamlType(node, expectedNodeTypes)) { - return true; - } - String nodeTag = node.getTag().getValue(); - - ctx.reportError( - id, - String.format( - "Got yaml node type %s, wanted type(s) [%s]", - nodeTag, stream(expectedNodeTypes).map(YamlNodeType::tag).collect(joining(" ")))); - return false; - } - static Integer newInteger(ParserContext ctx, Node node) { long id = ctx.collectMetadata(node); if (!assertYamlType(ctx, id, node, YamlNodeType.INTEGER)) { From f6274539e9bbf2b31f7cf12cf7f221e13345c267 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Wed, 4 Sep 2024 10:23:06 -0700 Subject: [PATCH 197/486] Internal Changes PiperOrigin-RevId: 671016096 --- common/src/main/java/dev/cel/common/BUILD.bazel | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/common/src/main/java/dev/cel/common/BUILD.bazel b/common/src/main/java/dev/cel/common/BUILD.bazel index 4706fb93d..2cc373fc2 100644 --- a/common/src/main/java/dev/cel/common/BUILD.bazel +++ b/common/src/main/java/dev/cel/common/BUILD.bazel @@ -108,7 +108,17 @@ java_library( java_library( name = "proto_ast", - exports = [":common"], # TODO Split target after migrating callers + srcs = ["CelProtoAbstractSyntaxTree.java"], + tags = [ + ], + deps = [ + "//common", + "//common/ast:expr_converter", + "//common/types:cel_types", + "@cel_spec//proto/cel/expr:expr_java_proto", + "@maven//:com_google_errorprone_error_prone_annotations", + "@maven//:com_google_guava_guava", + ], ) java_library( From 31e4f652b891fb5e909c2e82093828526c824010 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Wed, 4 Sep 2024 12:46:16 -0700 Subject: [PATCH 198/486] Internal Changes PiperOrigin-RevId: 671066199 --- common/BUILD.bazel | 5 +---- policy/src/main/java/dev/cel/policy/BUILD.bazel | 2 ++ 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/common/BUILD.bazel b/common/BUILD.bazel index 3af0c0c66..43d94e552 100644 --- a/common/BUILD.bazel +++ b/common/BUILD.bazel @@ -5,10 +5,7 @@ package( java_library( name = "common", - exports = [ - "//common/src/main/java/dev/cel/common", - "//common/src/main/java/dev/cel/common:source_location", # TODO: Split callers - ], + exports = ["//common/src/main/java/dev/cel/common"], ) java_library( diff --git a/policy/src/main/java/dev/cel/policy/BUILD.bazel b/policy/src/main/java/dev/cel/policy/BUILD.bazel index 7176ece6a..e515acaf6 100644 --- a/policy/src/main/java/dev/cel/policy/BUILD.bazel +++ b/policy/src/main/java/dev/cel/policy/BUILD.bazel @@ -115,6 +115,7 @@ java_library( ":value_string", ":yaml_helper", "//common:compiler_common", + "//common:source_location", "//common/internal", "@maven//:com_google_guava_guava", "@maven//:org_yaml_snakeyaml", @@ -335,6 +336,7 @@ java_library( ":yaml_helper", "//common", "//common:compiler_common", + "//common:source_location", "@maven//:com_google_guava_guava", "@maven//:org_yaml_snakeyaml", ], From a377c1695ba0465fbf2daa40ec734ca16ad82b1f Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Wed, 4 Sep 2024 17:40:47 -0700 Subject: [PATCH 199/486] No public description PiperOrigin-RevId: 671160923 --- bundle/src/test/java/dev/cel/bundle/BUILD.bazel | 1 + checker/src/main/java/dev/cel/checker/BUILD.bazel | 2 ++ checker/src/test/java/dev/cel/checker/BUILD.bazel | 1 + common/src/test/java/dev/cel/common/BUILD.bazel | 1 + parser/src/test/java/dev/cel/parser/BUILD.bazel | 1 + runtime/src/main/java/dev/cel/runtime/BUILD.bazel | 3 +++ testing/src/main/java/dev/cel/testing/BUILD.bazel | 1 + .../src/test/java/dev/cel/validator/validators/BUILD.bazel | 1 + 8 files changed, 11 insertions(+) diff --git a/bundle/src/test/java/dev/cel/bundle/BUILD.bazel b/bundle/src/test/java/dev/cel/bundle/BUILD.bazel index a324daf1d..3ca1dd570 100644 --- a/bundle/src/test/java/dev/cel/bundle/BUILD.bazel +++ b/bundle/src/test/java/dev/cel/bundle/BUILD.bazel @@ -18,6 +18,7 @@ java_library( "//common", "//common:compiler_common", "//common:options", + "//common:proto_ast", "//common/ast", "//common/resources/testdata/proto3:standalone_global_enum_java_proto", "//common/testing", diff --git a/checker/src/main/java/dev/cel/checker/BUILD.bazel b/checker/src/main/java/dev/cel/checker/BUILD.bazel index bdede0fb6..96cbd5981 100644 --- a/checker/src/main/java/dev/cel/checker/BUILD.bazel +++ b/checker/src/main/java/dev/cel/checker/BUILD.bazel @@ -171,6 +171,7 @@ java_library( "//common:compiler_common", "//common:features", "//common:options", + "//common:proto_ast", "//common/annotations", "//common/ast", "//common/ast:expr_converter", @@ -213,5 +214,6 @@ java_library( deps = [ ":checker_legacy_environment", "//common", + "//common:proto_ast", ], ) diff --git a/checker/src/test/java/dev/cel/checker/BUILD.bazel b/checker/src/test/java/dev/cel/checker/BUILD.bazel index 96497c836..ff4b87a34 100644 --- a/checker/src/test/java/dev/cel/checker/BUILD.bazel +++ b/checker/src/test/java/dev/cel/checker/BUILD.bazel @@ -23,6 +23,7 @@ java_library( "//checker:type_provider_legacy_impl", "//common", "//common:compiler_common", + "//common:proto_ast", "//common/ast", "//common/internal:env_visitor", "//common/internal:errors", diff --git a/common/src/test/java/dev/cel/common/BUILD.bazel b/common/src/test/java/dev/cel/common/BUILD.bazel index ad71d2862..311583690 100644 --- a/common/src/test/java/dev/cel/common/BUILD.bazel +++ b/common/src/test/java/dev/cel/common/BUILD.bazel @@ -14,6 +14,7 @@ java_library( "//common:compiler_common", "//common:features", "//common:options", + "//common:proto_ast", "//common:proto_json_adapter", "//common:proto_v1alpha1_ast", "//common:source_location", diff --git a/parser/src/test/java/dev/cel/parser/BUILD.bazel b/parser/src/test/java/dev/cel/parser/BUILD.bazel index 2ae7e5b8b..54510a2bf 100644 --- a/parser/src/test/java/dev/cel/parser/BUILD.bazel +++ b/parser/src/test/java/dev/cel/parser/BUILD.bazel @@ -15,6 +15,7 @@ java_library( "//common", "//common:compiler_common", "//common:options", + "//common:proto_ast", "//common:source_location", "//common/ast", "//common/internal", diff --git a/runtime/src/main/java/dev/cel/runtime/BUILD.bazel b/runtime/src/main/java/dev/cel/runtime/BUILD.bazel index 109e13d97..da45a5ea0 100644 --- a/runtime/src/main/java/dev/cel/runtime/BUILD.bazel +++ b/runtime/src/main/java/dev/cel/runtime/BUILD.bazel @@ -46,6 +46,7 @@ java_library( "//common", "//common:error_codes", "//common:options", + "//common:proto_ast", "//common:runtime_exception", "//common/annotations", "//common/internal:comparison_functions", @@ -81,6 +82,7 @@ java_library( "//common:error_codes", "//common:features", "//common:options", + "//common:proto_ast", "//common:runtime_exception", "//common/annotations", "//common/ast", @@ -191,6 +193,7 @@ java_library( ":unknown_attributes", "//common", "//common:compiler_common", + "//common:proto_ast", "//parser", "//parser:operator", "//parser:parser_builder", diff --git a/testing/src/main/java/dev/cel/testing/BUILD.bazel b/testing/src/main/java/dev/cel/testing/BUILD.bazel index 37f264809..f4054402b 100644 --- a/testing/src/main/java/dev/cel/testing/BUILD.bazel +++ b/testing/src/main/java/dev/cel/testing/BUILD.bazel @@ -96,6 +96,7 @@ java_library( "//:java_truth", "//common", "//common:options", + "//common:proto_ast", "//common/internal:cel_descriptor_pools", "//common/internal:file_descriptor_converter", "//common/resources/testdata/proto3:standalone_global_enum_java_proto", diff --git a/validator/src/test/java/dev/cel/validator/validators/BUILD.bazel b/validator/src/test/java/dev/cel/validator/validators/BUILD.bazel index a04ee6d1e..2383801bc 100644 --- a/validator/src/test/java/dev/cel/validator/validators/BUILD.bazel +++ b/validator/src/test/java/dev/cel/validator/validators/BUILD.bazel @@ -12,6 +12,7 @@ java_library( "//common", "//common:compiler_common", "//common:options", + "//common:proto_ast", "//common/types", "//extensions:optional_library", "//runtime", From 10bb524bddc7c32a55101f6b4967eb52cd14fb18 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Fri, 6 Sep 2024 16:26:53 -0700 Subject: [PATCH 200/486] Internal Changes PiperOrigin-RevId: 671926094 --- common/src/main/java/dev/cel/common/BUILD.bazel | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/common/src/main/java/dev/cel/common/BUILD.bazel b/common/src/main/java/dev/cel/common/BUILD.bazel index 2cc373fc2..fb74c9d66 100644 --- a/common/src/main/java/dev/cel/common/BUILD.bazel +++ b/common/src/main/java/dev/cel/common/BUILD.bazel @@ -12,7 +12,6 @@ COMMON_SOURCES = [ "CelDescriptorUtil.java", "CelDescriptors.java", "CelException.java", - "CelProtoAbstractSyntaxTree.java", # TODO Split target after migrating callers "CelSource.java", ] @@ -32,6 +31,11 @@ SOURCE_SOURCES = [ "Source.java", ] +# keep sorted +PROTO_AST_SOURCE = [ + "CelProtoAbstractSyntaxTree.java", +] + # keep sorted PROTO_V1ALPHA1_AST_SOURCE = [ "CelProtoV1Alpha1AbstractSyntaxTree.java", @@ -49,7 +53,6 @@ java_library( "//:auto_value", "//common/annotations", "//common/ast", - "//common/ast:expr_converter", "//common/internal", "//common/internal:file_descriptor_converter", "//common/types", @@ -108,7 +111,7 @@ java_library( java_library( name = "proto_ast", - srcs = ["CelProtoAbstractSyntaxTree.java"], + srcs = PROTO_AST_SOURCE, tags = [ ], deps = [ From 1a2a396b3cb2f5fb268d8201fc276814b8373afe Mon Sep 17 00:00:00 2001 From: Tristan Swadell Date: Wed, 11 Sep 2024 15:15:52 -0700 Subject: [PATCH 201/486] Expose CelPolicyValidationException constructors PiperOrigin-RevId: 673555726 --- .../java/dev/cel/policy/CelPolicyValidationException.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/policy/src/main/java/dev/cel/policy/CelPolicyValidationException.java b/policy/src/main/java/dev/cel/policy/CelPolicyValidationException.java index 1f7dc6ac2..4d52fcc1d 100644 --- a/policy/src/main/java/dev/cel/policy/CelPolicyValidationException.java +++ b/policy/src/main/java/dev/cel/policy/CelPolicyValidationException.java @@ -20,11 +20,11 @@ */ public final class CelPolicyValidationException extends Exception { - CelPolicyValidationException(String message) { + public CelPolicyValidationException(String message) { super(message); } - CelPolicyValidationException(String message, Throwable cause) { + public CelPolicyValidationException(String message, Throwable cause) { super(message, cause); } } From d98e0b1f7a78f381b887c7b22736157eba7c5510 Mon Sep 17 00:00:00 2001 From: CEL Dev Team Date: Mon, 23 Sep 2024 23:37:08 -0700 Subject: [PATCH 202/486] Load the builtin Bazel java rules from @rules_java PiperOrigin-RevId: 678098294 --- bundle/BUILD.bazel | 2 ++ bundle/src/main/java/dev/cel/bundle/BUILD.bazel | 2 ++ bundle/src/test/java/dev/cel/bundle/BUILD.bazel | 1 + checker/BUILD.bazel | 2 ++ checker/src/main/java/dev/cel/checker/BUILD.bazel | 2 ++ checker/src/test/java/dev/cel/checker/BUILD.bazel | 1 + codelab/BUILD.bazel | 2 ++ codelab/src/main/codelab/BUILD.bazel | 2 ++ codelab/src/main/codelab/solutions/BUILD.bazel | 2 ++ codelab/src/test/codelab/BUILD.bazel | 2 ++ codelab/src/test/codelab/solutions/BUILD.bazel | 2 ++ common/BUILD.bazel | 2 ++ common/annotations/BUILD.bazel | 2 ++ common/ast/BUILD.bazel | 2 ++ common/internal/BUILD.bazel | 2 ++ common/navigation/BUILD.bazel | 2 ++ common/src/main/java/dev/cel/common/BUILD.bazel | 2 ++ common/src/main/java/dev/cel/common/annotations/BUILD.bazel | 2 ++ common/src/main/java/dev/cel/common/ast/BUILD.bazel | 2 ++ common/src/main/java/dev/cel/common/internal/BUILD.bazel | 2 ++ common/src/main/java/dev/cel/common/navigation/BUILD.bazel | 2 ++ common/src/main/java/dev/cel/common/testing/BUILD.bazel | 2 ++ common/src/main/java/dev/cel/common/types/BUILD.bazel | 2 ++ common/src/main/java/dev/cel/common/values/BUILD.bazel | 2 ++ 24 files changed, 46 insertions(+) diff --git a/bundle/BUILD.bazel b/bundle/BUILD.bazel index e562cff00..91336cdf5 100644 --- a/bundle/BUILD.bazel +++ b/bundle/BUILD.bazel @@ -1,3 +1,5 @@ +load("@rules_java//java:defs.bzl", "java_library") + package( default_applicable_licenses = ["//:license"], default_visibility = ["//visibility:public"], diff --git a/bundle/src/main/java/dev/cel/bundle/BUILD.bazel b/bundle/src/main/java/dev/cel/bundle/BUILD.bazel index 70744129c..5ef5123c1 100644 --- a/bundle/src/main/java/dev/cel/bundle/BUILD.bazel +++ b/bundle/src/main/java/dev/cel/bundle/BUILD.bazel @@ -1,3 +1,5 @@ +load("@rules_java//java:defs.bzl", "java_library") + package( default_applicable_licenses = ["//:license"], default_visibility = [ diff --git a/bundle/src/test/java/dev/cel/bundle/BUILD.bazel b/bundle/src/test/java/dev/cel/bundle/BUILD.bazel index 3ca1dd570..8b191c25a 100644 --- a/bundle/src/test/java/dev/cel/bundle/BUILD.bazel +++ b/bundle/src/test/java/dev/cel/bundle/BUILD.bazel @@ -1,3 +1,4 @@ +load("@rules_java//java:defs.bzl", "java_library") load("//:testing.bzl", "junit4_test_suites") package(default_applicable_licenses = [ diff --git a/checker/BUILD.bazel b/checker/BUILD.bazel index 25fc8d739..8add14f59 100644 --- a/checker/BUILD.bazel +++ b/checker/BUILD.bazel @@ -1,3 +1,5 @@ +load("@rules_java//java:defs.bzl", "java_library") + package( default_applicable_licenses = ["//:license"], default_visibility = ["//visibility:public"], diff --git a/checker/src/main/java/dev/cel/checker/BUILD.bazel b/checker/src/main/java/dev/cel/checker/BUILD.bazel index 96cbd5981..3d209db4e 100644 --- a/checker/src/main/java/dev/cel/checker/BUILD.bazel +++ b/checker/src/main/java/dev/cel/checker/BUILD.bazel @@ -1,3 +1,5 @@ +load("@rules_java//java:defs.bzl", "java_library") + package( default_applicable_licenses = [ "//:license", diff --git a/checker/src/test/java/dev/cel/checker/BUILD.bazel b/checker/src/test/java/dev/cel/checker/BUILD.bazel index ff4b87a34..096207cc5 100644 --- a/checker/src/test/java/dev/cel/checker/BUILD.bazel +++ b/checker/src/test/java/dev/cel/checker/BUILD.bazel @@ -1,3 +1,4 @@ +load("@rules_java//java:defs.bzl", "java_library") load("//:testing.bzl", "junit4_test_suites") package(default_applicable_licenses = [ diff --git a/codelab/BUILD.bazel b/codelab/BUILD.bazel index eea160dc4..95bb127b6 100644 --- a/codelab/BUILD.bazel +++ b/codelab/BUILD.bazel @@ -1,3 +1,5 @@ +load("@rules_java//java:defs.bzl", "java_library") + package( default_applicable_licenses = ["//:license"], default_visibility = ["//codelab:__subpackages__"], diff --git a/codelab/src/main/codelab/BUILD.bazel b/codelab/src/main/codelab/BUILD.bazel index 7b3065e47..2b3eb0247 100644 --- a/codelab/src/main/codelab/BUILD.bazel +++ b/codelab/src/main/codelab/BUILD.bazel @@ -1,3 +1,5 @@ +load("@rules_java//java:defs.bzl", "java_library") + package( default_applicable_licenses = [ "//:license", diff --git a/codelab/src/main/codelab/solutions/BUILD.bazel b/codelab/src/main/codelab/solutions/BUILD.bazel index 42820a846..2060e3e8c 100644 --- a/codelab/src/main/codelab/solutions/BUILD.bazel +++ b/codelab/src/main/codelab/solutions/BUILD.bazel @@ -1,3 +1,5 @@ +load("@rules_java//java:defs.bzl", "java_library") + package( default_applicable_licenses = [ "//:license", diff --git a/codelab/src/test/codelab/BUILD.bazel b/codelab/src/test/codelab/BUILD.bazel index 84363646a..1b39618d0 100644 --- a/codelab/src/test/codelab/BUILD.bazel +++ b/codelab/src/test/codelab/BUILD.bazel @@ -1,3 +1,5 @@ +load("@rules_java//java:defs.bzl", "java_test") + package(default_applicable_licenses = [ "//:license", ]) diff --git a/codelab/src/test/codelab/solutions/BUILD.bazel b/codelab/src/test/codelab/solutions/BUILD.bazel index be146d8f9..6438f8ee2 100644 --- a/codelab/src/test/codelab/solutions/BUILD.bazel +++ b/codelab/src/test/codelab/solutions/BUILD.bazel @@ -1,3 +1,5 @@ +load("@rules_java//java:defs.bzl", "java_test") + package(default_applicable_licenses = [ "//:license", ]) diff --git a/common/BUILD.bazel b/common/BUILD.bazel index 43d94e552..af0bf8abb 100644 --- a/common/BUILD.bazel +++ b/common/BUILD.bazel @@ -1,3 +1,5 @@ +load("@rules_java//java:defs.bzl", "java_library") + package( default_applicable_licenses = ["//:license"], default_visibility = ["//visibility:public"], diff --git a/common/annotations/BUILD.bazel b/common/annotations/BUILD.bazel index 62a6ccfd9..046955e82 100644 --- a/common/annotations/BUILD.bazel +++ b/common/annotations/BUILD.bazel @@ -1,3 +1,5 @@ +load("@rules_java//java:defs.bzl", "java_library") + package( default_applicable_licenses = ["//:license"], default_visibility = ["//visibility:public"], diff --git a/common/ast/BUILD.bazel b/common/ast/BUILD.bazel index 5400e6a8e..0a27ae0bc 100644 --- a/common/ast/BUILD.bazel +++ b/common/ast/BUILD.bazel @@ -1,3 +1,5 @@ +load("@rules_java//java:defs.bzl", "java_library") + package( default_applicable_licenses = ["//:license"], default_visibility = ["//visibility:public"], diff --git a/common/internal/BUILD.bazel b/common/internal/BUILD.bazel index 6293804f2..63c8bcbf0 100644 --- a/common/internal/BUILD.bazel +++ b/common/internal/BUILD.bazel @@ -1,3 +1,5 @@ +load("@rules_java//java:defs.bzl", "java_library") + package( default_applicable_licenses = ["//:license"], default_visibility = ["//visibility:public"], diff --git a/common/navigation/BUILD.bazel b/common/navigation/BUILD.bazel index df3447513..1dba25b8e 100644 --- a/common/navigation/BUILD.bazel +++ b/common/navigation/BUILD.bazel @@ -1,3 +1,5 @@ +load("@rules_java//java:defs.bzl", "java_library") + package( default_applicable_licenses = ["//:license"], default_visibility = ["//visibility:public"], diff --git a/common/src/main/java/dev/cel/common/BUILD.bazel b/common/src/main/java/dev/cel/common/BUILD.bazel index fb74c9d66..e254ffbdd 100644 --- a/common/src/main/java/dev/cel/common/BUILD.bazel +++ b/common/src/main/java/dev/cel/common/BUILD.bazel @@ -1,3 +1,5 @@ +load("@rules_java//java:defs.bzl", "java_library") + package( default_applicable_licenses = ["//:license"], default_visibility = [ diff --git a/common/src/main/java/dev/cel/common/annotations/BUILD.bazel b/common/src/main/java/dev/cel/common/annotations/BUILD.bazel index 434eede90..cdfa32938 100644 --- a/common/src/main/java/dev/cel/common/annotations/BUILD.bazel +++ b/common/src/main/java/dev/cel/common/annotations/BUILD.bazel @@ -1,3 +1,5 @@ +load("@rules_java//java:defs.bzl", "java_library") + package( default_applicable_licenses = [ "//:license", diff --git a/common/src/main/java/dev/cel/common/ast/BUILD.bazel b/common/src/main/java/dev/cel/common/ast/BUILD.bazel index 6c1709f1a..8cc9be997 100644 --- a/common/src/main/java/dev/cel/common/ast/BUILD.bazel +++ b/common/src/main/java/dev/cel/common/ast/BUILD.bazel @@ -1,3 +1,5 @@ +load("@rules_java//java:defs.bzl", "java_library") + package( default_applicable_licenses = [ "//:license", diff --git a/common/src/main/java/dev/cel/common/internal/BUILD.bazel b/common/src/main/java/dev/cel/common/internal/BUILD.bazel index 70a91fc8c..a86c9aa79 100644 --- a/common/src/main/java/dev/cel/common/internal/BUILD.bazel +++ b/common/src/main/java/dev/cel/common/internal/BUILD.bazel @@ -1,3 +1,5 @@ +load("@rules_java//java:defs.bzl", "java_library") + package( default_applicable_licenses = [ "//:license", diff --git a/common/src/main/java/dev/cel/common/navigation/BUILD.bazel b/common/src/main/java/dev/cel/common/navigation/BUILD.bazel index b3bccf67b..2c5a80fe7 100644 --- a/common/src/main/java/dev/cel/common/navigation/BUILD.bazel +++ b/common/src/main/java/dev/cel/common/navigation/BUILD.bazel @@ -1,3 +1,5 @@ +load("@rules_java//java:defs.bzl", "java_library") + package( default_applicable_licenses = [ "//:license", diff --git a/common/src/main/java/dev/cel/common/testing/BUILD.bazel b/common/src/main/java/dev/cel/common/testing/BUILD.bazel index a5b967b16..574638e35 100644 --- a/common/src/main/java/dev/cel/common/testing/BUILD.bazel +++ b/common/src/main/java/dev/cel/common/testing/BUILD.bazel @@ -1,3 +1,5 @@ +load("@rules_java//java:defs.bzl", "java_library") + package( default_applicable_licenses = [ "//:license", diff --git a/common/src/main/java/dev/cel/common/types/BUILD.bazel b/common/src/main/java/dev/cel/common/types/BUILD.bazel index 19c741e0f..a1f1a68d4 100644 --- a/common/src/main/java/dev/cel/common/types/BUILD.bazel +++ b/common/src/main/java/dev/cel/common/types/BUILD.bazel @@ -1,3 +1,5 @@ +load("@rules_java//java:defs.bzl", "java_library") + package( default_applicable_licenses = [ "//:license", diff --git a/common/src/main/java/dev/cel/common/values/BUILD.bazel b/common/src/main/java/dev/cel/common/values/BUILD.bazel index fcb1269fa..8f1aa06c2 100644 --- a/common/src/main/java/dev/cel/common/values/BUILD.bazel +++ b/common/src/main/java/dev/cel/common/values/BUILD.bazel @@ -1,3 +1,5 @@ +load("@rules_java//java:defs.bzl", "java_library") + package( default_applicable_licenses = [ "//:license", From 1fdbc4fbe0c652655686f761595c89d86c33071e Mon Sep 17 00:00:00 2001 From: CEL Dev Team Date: Mon, 23 Sep 2024 23:37:12 -0700 Subject: [PATCH 203/486] Load the builtin Bazel java rules from @rules_java PiperOrigin-RevId: 678098303 --- common/src/test/java/dev/cel/common/BUILD.bazel | 1 + common/src/test/java/dev/cel/common/ast/BUILD.bazel | 1 + common/src/test/java/dev/cel/common/internal/BUILD.bazel | 1 + common/src/test/java/dev/cel/common/navigation/BUILD.bazel | 1 + common/src/test/java/dev/cel/common/types/BUILD.bazel | 1 + common/src/test/java/dev/cel/common/values/BUILD.bazel | 1 + common/testing/BUILD.bazel | 2 ++ common/types/BUILD.bazel | 2 ++ common/values/BUILD.bazel | 2 ++ compiler/BUILD.bazel | 2 ++ compiler/src/main/java/dev/cel/compiler/BUILD.bazel | 2 ++ conformance/src/test/java/dev/cel/conformance/BUILD.bazel | 1 + extensions/BUILD.bazel | 2 ++ extensions/src/main/java/dev/cel/extensions/BUILD.bazel | 2 ++ extensions/src/test/java/dev/cel/extensions/BUILD.bazel | 1 + optimizer/BUILD.bazel | 2 ++ optimizer/optimizers/BUILD.bazel | 2 ++ optimizer/src/main/java/dev/cel/optimizer/BUILD.bazel | 2 ++ .../src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel | 2 ++ optimizer/src/test/java/dev/cel/optimizer/BUILD.bazel | 1 + .../src/test/java/dev/cel/optimizer/optimizers/BUILD.bazel | 1 + parser/BUILD.bazel | 2 ++ parser/src/main/java/dev/cel/parser/BUILD.bazel | 2 ++ parser/src/main/java/dev/cel/parser/gen/BUILD.bazel | 1 + parser/src/test/java/dev/cel/parser/BUILD.bazel | 1 + 25 files changed, 38 insertions(+) diff --git a/common/src/test/java/dev/cel/common/BUILD.bazel b/common/src/test/java/dev/cel/common/BUILD.bazel index 311583690..0f201e480 100644 --- a/common/src/test/java/dev/cel/common/BUILD.bazel +++ b/common/src/test/java/dev/cel/common/BUILD.bazel @@ -1,3 +1,4 @@ +load("@rules_java//java:defs.bzl", "java_library") load("//:testing.bzl", "junit4_test_suites") package(default_applicable_licenses = [ diff --git a/common/src/test/java/dev/cel/common/ast/BUILD.bazel b/common/src/test/java/dev/cel/common/ast/BUILD.bazel index 2097a25f7..5cfc4eb63 100644 --- a/common/src/test/java/dev/cel/common/ast/BUILD.bazel +++ b/common/src/test/java/dev/cel/common/ast/BUILD.bazel @@ -1,3 +1,4 @@ +load("@rules_java//java:defs.bzl", "java_library") load("//:testing.bzl", "junit4_test_suites") package(default_applicable_licenses = [ diff --git a/common/src/test/java/dev/cel/common/internal/BUILD.bazel b/common/src/test/java/dev/cel/common/internal/BUILD.bazel index fa46ced6d..9a033b00a 100644 --- a/common/src/test/java/dev/cel/common/internal/BUILD.bazel +++ b/common/src/test/java/dev/cel/common/internal/BUILD.bazel @@ -1,3 +1,4 @@ +load("@rules_java//java:defs.bzl", "java_library") load("//:testing.bzl", "junit4_test_suites") package(default_applicable_licenses = [ diff --git a/common/src/test/java/dev/cel/common/navigation/BUILD.bazel b/common/src/test/java/dev/cel/common/navigation/BUILD.bazel index c754e80df..f269a0ce3 100644 --- a/common/src/test/java/dev/cel/common/navigation/BUILD.bazel +++ b/common/src/test/java/dev/cel/common/navigation/BUILD.bazel @@ -1,3 +1,4 @@ +load("@rules_java//java:defs.bzl", "java_library") load("//:testing.bzl", "junit4_test_suites") package(default_applicable_licenses = ["//:license"]) diff --git a/common/src/test/java/dev/cel/common/types/BUILD.bazel b/common/src/test/java/dev/cel/common/types/BUILD.bazel index 432ff1570..a084efd62 100644 --- a/common/src/test/java/dev/cel/common/types/BUILD.bazel +++ b/common/src/test/java/dev/cel/common/types/BUILD.bazel @@ -1,3 +1,4 @@ +load("@rules_java//java:defs.bzl", "java_library") load("//:testing.bzl", "junit4_test_suites") package(default_applicable_licenses = ["//:license"]) diff --git a/common/src/test/java/dev/cel/common/values/BUILD.bazel b/common/src/test/java/dev/cel/common/values/BUILD.bazel index 92b71c6db..00800a01c 100644 --- a/common/src/test/java/dev/cel/common/values/BUILD.bazel +++ b/common/src/test/java/dev/cel/common/values/BUILD.bazel @@ -1,3 +1,4 @@ +load("@rules_java//java:defs.bzl", "java_library") load("//:testing.bzl", "junit4_test_suites") package(default_applicable_licenses = ["//:license"]) diff --git a/common/testing/BUILD.bazel b/common/testing/BUILD.bazel index b98bc4c68..a88ccf4f9 100644 --- a/common/testing/BUILD.bazel +++ b/common/testing/BUILD.bazel @@ -1,3 +1,5 @@ +load("@rules_java//java:defs.bzl", "java_library") + package( default_applicable_licenses = ["//:license"], default_testonly = True, diff --git a/common/types/BUILD.bazel b/common/types/BUILD.bazel index af81a975b..76904d76b 100644 --- a/common/types/BUILD.bazel +++ b/common/types/BUILD.bazel @@ -1,3 +1,5 @@ +load("@rules_java//java:defs.bzl", "java_library") + package( default_applicable_licenses = ["//:license"], default_visibility = ["//visibility:public"], diff --git a/common/values/BUILD.bazel b/common/values/BUILD.bazel index 931999b4c..c7efe7dee 100644 --- a/common/values/BUILD.bazel +++ b/common/values/BUILD.bazel @@ -1,3 +1,5 @@ +load("@rules_java//java:defs.bzl", "java_library") + package( default_applicable_licenses = ["//:license"], default_visibility = ["//visibility:public"], # TODO: Expose to public when ready diff --git a/compiler/BUILD.bazel b/compiler/BUILD.bazel index e5e41e0a5..5bb7d7129 100644 --- a/compiler/BUILD.bazel +++ b/compiler/BUILD.bazel @@ -1,3 +1,5 @@ +load("@rules_java//java:defs.bzl", "java_library") + package( default_applicable_licenses = ["//:license"], default_visibility = ["//visibility:public"], diff --git a/compiler/src/main/java/dev/cel/compiler/BUILD.bazel b/compiler/src/main/java/dev/cel/compiler/BUILD.bazel index 1f58aafe9..63a9cd4e6 100644 --- a/compiler/src/main/java/dev/cel/compiler/BUILD.bazel +++ b/compiler/src/main/java/dev/cel/compiler/BUILD.bazel @@ -1,3 +1,5 @@ +load("@rules_java//java:defs.bzl", "java_library") + package( default_applicable_licenses = [ "//:license", diff --git a/conformance/src/test/java/dev/cel/conformance/BUILD.bazel b/conformance/src/test/java/dev/cel/conformance/BUILD.bazel index 6b60d77d4..f3014aca5 100644 --- a/conformance/src/test/java/dev/cel/conformance/BUILD.bazel +++ b/conformance/src/test/java/dev/cel/conformance/BUILD.bazel @@ -1,3 +1,4 @@ +load("@rules_java//java:defs.bzl", "java_library") load("//conformance/src/test/java/dev/cel/conformance:conformance_test.bzl", "conformance_test") package(default_applicable_licenses = [ diff --git a/extensions/BUILD.bazel b/extensions/BUILD.bazel index 70956e336..5f520c418 100644 --- a/extensions/BUILD.bazel +++ b/extensions/BUILD.bazel @@ -1,3 +1,5 @@ +load("@rules_java//java:defs.bzl", "java_library") + package( default_applicable_licenses = ["//:license"], default_visibility = ["//visibility:public"], diff --git a/extensions/src/main/java/dev/cel/extensions/BUILD.bazel b/extensions/src/main/java/dev/cel/extensions/BUILD.bazel index 7f6652666..a3256ecca 100644 --- a/extensions/src/main/java/dev/cel/extensions/BUILD.bazel +++ b/extensions/src/main/java/dev/cel/extensions/BUILD.bazel @@ -1,3 +1,5 @@ +load("@rules_java//java:defs.bzl", "java_library") + package( default_applicable_licenses = [ "//:license", diff --git a/extensions/src/test/java/dev/cel/extensions/BUILD.bazel b/extensions/src/test/java/dev/cel/extensions/BUILD.bazel index 13411adb0..4ed844381 100644 --- a/extensions/src/test/java/dev/cel/extensions/BUILD.bazel +++ b/extensions/src/test/java/dev/cel/extensions/BUILD.bazel @@ -1,3 +1,4 @@ +load("@rules_java//java:defs.bzl", "java_library") load("//:testing.bzl", "junit4_test_suites") package(default_applicable_licenses = ["//:license"]) diff --git a/optimizer/BUILD.bazel b/optimizer/BUILD.bazel index 1dd584b4e..9468b01a9 100644 --- a/optimizer/BUILD.bazel +++ b/optimizer/BUILD.bazel @@ -1,3 +1,5 @@ +load("@rules_java//java:defs.bzl", "java_library") + package( default_applicable_licenses = ["//:license"], default_visibility = ["//visibility:public"], diff --git a/optimizer/optimizers/BUILD.bazel b/optimizer/optimizers/BUILD.bazel index 5debf13bc..21241241f 100644 --- a/optimizer/optimizers/BUILD.bazel +++ b/optimizer/optimizers/BUILD.bazel @@ -1,3 +1,5 @@ +load("@rules_java//java:defs.bzl", "java_library") + package( default_applicable_licenses = ["//:license"], default_visibility = ["//visibility:public"], diff --git a/optimizer/src/main/java/dev/cel/optimizer/BUILD.bazel b/optimizer/src/main/java/dev/cel/optimizer/BUILD.bazel index fcd85ce72..af01d1a1c 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/BUILD.bazel +++ b/optimizer/src/main/java/dev/cel/optimizer/BUILD.bazel @@ -1,3 +1,5 @@ +load("@rules_java//java:defs.bzl", "java_library") + package( default_applicable_licenses = ["//:license"], default_visibility = [ diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel b/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel index 9b679d9bd..396925ef7 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel @@ -1,3 +1,5 @@ +load("@rules_java//java:defs.bzl", "java_library") + package( default_applicable_licenses = ["//:license"], default_visibility = [ diff --git a/optimizer/src/test/java/dev/cel/optimizer/BUILD.bazel b/optimizer/src/test/java/dev/cel/optimizer/BUILD.bazel index 322b642a7..9dd7d616d 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/BUILD.bazel +++ b/optimizer/src/test/java/dev/cel/optimizer/BUILD.bazel @@ -1,3 +1,4 @@ +load("@rules_java//java:defs.bzl", "java_library") load("//:testing.bzl", "junit4_test_suites") package(default_applicable_licenses = ["//:license"]) diff --git a/optimizer/src/test/java/dev/cel/optimizer/optimizers/BUILD.bazel b/optimizer/src/test/java/dev/cel/optimizer/optimizers/BUILD.bazel index d988c4e56..92ef80377 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/optimizers/BUILD.bazel +++ b/optimizer/src/test/java/dev/cel/optimizer/optimizers/BUILD.bazel @@ -1,3 +1,4 @@ +load("@rules_java//java:defs.bzl", "java_library") load("//:testing.bzl", "junit4_test_suites") package(default_applicable_licenses = ["//:license"]) diff --git a/parser/BUILD.bazel b/parser/BUILD.bazel index ba31cd46a..89bfed336 100644 --- a/parser/BUILD.bazel +++ b/parser/BUILD.bazel @@ -1,3 +1,5 @@ +load("@rules_java//java:defs.bzl", "java_library") + package( default_applicable_licenses = ["//:license"], default_visibility = ["//visibility:public"], diff --git a/parser/src/main/java/dev/cel/parser/BUILD.bazel b/parser/src/main/java/dev/cel/parser/BUILD.bazel index 53f7e5fa8..d86b48668 100644 --- a/parser/src/main/java/dev/cel/parser/BUILD.bazel +++ b/parser/src/main/java/dev/cel/parser/BUILD.bazel @@ -1,3 +1,5 @@ +load("@rules_java//java:defs.bzl", "java_library") + package( default_applicable_licenses = ["//:license"], default_visibility = [ diff --git a/parser/src/main/java/dev/cel/parser/gen/BUILD.bazel b/parser/src/main/java/dev/cel/parser/gen/BUILD.bazel index 5eee82579..8b912168c 100644 --- a/parser/src/main/java/dev/cel/parser/gen/BUILD.bazel +++ b/parser/src/main/java/dev/cel/parser/gen/BUILD.bazel @@ -4,6 +4,7 @@ to avoid a path conflict with parser/src/main/java/dev/cel/parser/CelParser.java that causes build failures on filesystems with case-insensitive paths (e.g. macOS). """ +load("@rules_java//java:defs.bzl", "java_library") load("//:antlr.bzl", "antlr4_java_combined") package( diff --git a/parser/src/test/java/dev/cel/parser/BUILD.bazel b/parser/src/test/java/dev/cel/parser/BUILD.bazel index 54510a2bf..8697baad6 100644 --- a/parser/src/test/java/dev/cel/parser/BUILD.bazel +++ b/parser/src/test/java/dev/cel/parser/BUILD.bazel @@ -1,3 +1,4 @@ +load("@rules_java//java:defs.bzl", "java_library") load("//:testing.bzl", "junit4_test_suites") package(default_applicable_licenses = [ From a9e8c8264687ade06834faee491a18a0cd2314e7 Mon Sep 17 00:00:00 2001 From: CEL Dev Team Date: Wed, 25 Sep 2024 09:27:55 -0700 Subject: [PATCH 204/486] Load the builtin Bazel java rules from @rules_java PiperOrigin-RevId: 678732015 --- policy/BUILD.bazel | 2 ++ policy/src/main/java/dev/cel/policy/BUILD.bazel | 2 ++ policy/src/test/java/dev/cel/policy/BUILD.bazel | 1 + runtime/BUILD.bazel | 2 ++ runtime/async/BUILD.bazel | 2 ++ runtime/src/main/java/dev/cel/runtime/BUILD.bazel | 2 ++ runtime/src/main/java/dev/cel/runtime/async/BUILD.bazel | 2 ++ runtime/src/test/java/dev/cel/runtime/BUILD.bazel | 1 + runtime/src/test/java/dev/cel/runtime/async/BUILD.bazel | 1 + testing/BUILD.bazel | 2 ++ testing/src/main/java/dev/cel/testing/BUILD.bazel | 2 ++ testing/src/test/java/dev/cel/testing/BUILD.bazel | 1 + validator/BUILD.bazel | 2 ++ validator/src/main/java/dev/cel/validator/BUILD.bazel | 2 ++ .../src/main/java/dev/cel/validator/validators/BUILD.bazel | 2 ++ validator/src/test/java/dev/cel/validator/BUILD.bazel | 1 + .../src/test/java/dev/cel/validator/validators/BUILD.bazel | 1 + validator/validators/BUILD.bazel | 2 ++ 18 files changed, 30 insertions(+) diff --git a/policy/BUILD.bazel b/policy/BUILD.bazel index 4c18f3b7d..e0a3a9d5d 100644 --- a/policy/BUILD.bazel +++ b/policy/BUILD.bazel @@ -1,3 +1,5 @@ +load("@rules_java//java:defs.bzl", "java_library") + package( default_applicable_licenses = ["//:license"], default_visibility = ["//visibility:public"], diff --git a/policy/src/main/java/dev/cel/policy/BUILD.bazel b/policy/src/main/java/dev/cel/policy/BUILD.bazel index e515acaf6..546853bb8 100644 --- a/policy/src/main/java/dev/cel/policy/BUILD.bazel +++ b/policy/src/main/java/dev/cel/policy/BUILD.bazel @@ -1,3 +1,5 @@ +load("@rules_java//java:defs.bzl", "java_library") + package( default_applicable_licenses = ["//:license"], default_visibility = [ diff --git a/policy/src/test/java/dev/cel/policy/BUILD.bazel b/policy/src/test/java/dev/cel/policy/BUILD.bazel index dff3e974d..09a1a98c2 100644 --- a/policy/src/test/java/dev/cel/policy/BUILD.bazel +++ b/policy/src/test/java/dev/cel/policy/BUILD.bazel @@ -1,3 +1,4 @@ +load("@rules_java//java:defs.bzl", "java_library") load("//:testing.bzl", "junit4_test_suites") package(default_applicable_licenses = ["//:license"]) diff --git a/runtime/BUILD.bazel b/runtime/BUILD.bazel index b08b341f8..8c0c72a6a 100644 --- a/runtime/BUILD.bazel +++ b/runtime/BUILD.bazel @@ -1,3 +1,5 @@ +load("@rules_java//java:defs.bzl", "java_library") + package( default_applicable_licenses = ["//:license"], default_visibility = ["//visibility:public"], diff --git a/runtime/async/BUILD.bazel b/runtime/async/BUILD.bazel index 8b87567df..137f5e274 100644 --- a/runtime/async/BUILD.bazel +++ b/runtime/async/BUILD.bazel @@ -1,5 +1,7 @@ # Reference implementation for an Async evaluator for the CEL runtime. +load("@rules_java//java:defs.bzl", "java_library") + package( default_applicable_licenses = ["//:license"], default_visibility = ["//visibility:public"], diff --git a/runtime/src/main/java/dev/cel/runtime/BUILD.bazel b/runtime/src/main/java/dev/cel/runtime/BUILD.bazel index da45a5ea0..6a8c1cea0 100644 --- a/runtime/src/main/java/dev/cel/runtime/BUILD.bazel +++ b/runtime/src/main/java/dev/cel/runtime/BUILD.bazel @@ -1,3 +1,5 @@ +load("@rules_java//java:defs.bzl", "java_library") + package( default_applicable_licenses = ["//:license"], default_visibility = [ diff --git a/runtime/src/main/java/dev/cel/runtime/async/BUILD.bazel b/runtime/src/main/java/dev/cel/runtime/async/BUILD.bazel index 8e2042bc9..4e481b963 100644 --- a/runtime/src/main/java/dev/cel/runtime/async/BUILD.bazel +++ b/runtime/src/main/java/dev/cel/runtime/async/BUILD.bazel @@ -1,5 +1,7 @@ # Reference implementation for an Async evaluator for the CEL runtime. +load("@rules_java//java:defs.bzl", "java_library") + package( default_applicable_licenses = [ "//:license", diff --git a/runtime/src/test/java/dev/cel/runtime/BUILD.bazel b/runtime/src/test/java/dev/cel/runtime/BUILD.bazel index 0cafcda6b..6a80864c2 100644 --- a/runtime/src/test/java/dev/cel/runtime/BUILD.bazel +++ b/runtime/src/test/java/dev/cel/runtime/BUILD.bazel @@ -1,3 +1,4 @@ +load("@rules_java//java:defs.bzl", "java_library") load("//:testing.bzl", "junit4_test_suites") package(default_applicable_licenses = ["//:license"]) diff --git a/runtime/src/test/java/dev/cel/runtime/async/BUILD.bazel b/runtime/src/test/java/dev/cel/runtime/async/BUILD.bazel index 98a575c2e..cbbf32e04 100644 --- a/runtime/src/test/java/dev/cel/runtime/async/BUILD.bazel +++ b/runtime/src/test/java/dev/cel/runtime/async/BUILD.bazel @@ -1,3 +1,4 @@ +load("@rules_java//java:defs.bzl", "java_library") load("//:testing.bzl", "junit4_test_suites") package(default_applicable_licenses = [ diff --git a/testing/BUILD.bazel b/testing/BUILD.bazel index 1370356ba..ac39753b3 100644 --- a/testing/BUILD.bazel +++ b/testing/BUILD.bazel @@ -1,3 +1,5 @@ +load("@rules_java//java:defs.bzl", "java_library") + package( default_applicable_licenses = ["//:license"], default_testonly = True, diff --git a/testing/src/main/java/dev/cel/testing/BUILD.bazel b/testing/src/main/java/dev/cel/testing/BUILD.bazel index f4054402b..bbe1ab489 100644 --- a/testing/src/main/java/dev/cel/testing/BUILD.bazel +++ b/testing/src/main/java/dev/cel/testing/BUILD.bazel @@ -1,3 +1,5 @@ +load("@rules_java//java:defs.bzl", "java_library") + package( default_applicable_licenses = ["//:license"], default_testonly = True, diff --git a/testing/src/test/java/dev/cel/testing/BUILD.bazel b/testing/src/test/java/dev/cel/testing/BUILD.bazel index 90cf73e3a..8fe831bb2 100644 --- a/testing/src/test/java/dev/cel/testing/BUILD.bazel +++ b/testing/src/test/java/dev/cel/testing/BUILD.bazel @@ -1,3 +1,4 @@ +load("@rules_java//java:defs.bzl", "java_library") load("//:testing.bzl", "junit4_test_suites") package(default_applicable_licenses = [ diff --git a/validator/BUILD.bazel b/validator/BUILD.bazel index a5afcbd23..fe40153fc 100644 --- a/validator/BUILD.bazel +++ b/validator/BUILD.bazel @@ -1,3 +1,5 @@ +load("@rules_java//java:defs.bzl", "java_library") + package( default_applicable_licenses = ["//:license"], default_visibility = ["//visibility:public"], diff --git a/validator/src/main/java/dev/cel/validator/BUILD.bazel b/validator/src/main/java/dev/cel/validator/BUILD.bazel index ed4ecc570..c6cad795b 100644 --- a/validator/src/main/java/dev/cel/validator/BUILD.bazel +++ b/validator/src/main/java/dev/cel/validator/BUILD.bazel @@ -1,3 +1,5 @@ +load("@rules_java//java:defs.bzl", "java_library") + package( default_applicable_licenses = ["//:license"], default_visibility = [ diff --git a/validator/src/main/java/dev/cel/validator/validators/BUILD.bazel b/validator/src/main/java/dev/cel/validator/validators/BUILD.bazel index 3362f14be..d166cfa76 100644 --- a/validator/src/main/java/dev/cel/validator/validators/BUILD.bazel +++ b/validator/src/main/java/dev/cel/validator/validators/BUILD.bazel @@ -1,3 +1,5 @@ +load("@rules_java//java:defs.bzl", "java_library") + package( default_applicable_licenses = ["//:license"], default_visibility = [ diff --git a/validator/src/test/java/dev/cel/validator/BUILD.bazel b/validator/src/test/java/dev/cel/validator/BUILD.bazel index f6f94f625..36991a863 100644 --- a/validator/src/test/java/dev/cel/validator/BUILD.bazel +++ b/validator/src/test/java/dev/cel/validator/BUILD.bazel @@ -1,3 +1,4 @@ +load("@rules_java//java:defs.bzl", "java_library") load("//:testing.bzl", "junit4_test_suites") package(default_applicable_licenses = ["//:license"]) diff --git a/validator/src/test/java/dev/cel/validator/validators/BUILD.bazel b/validator/src/test/java/dev/cel/validator/validators/BUILD.bazel index 2383801bc..76f4de78a 100644 --- a/validator/src/test/java/dev/cel/validator/validators/BUILD.bazel +++ b/validator/src/test/java/dev/cel/validator/validators/BUILD.bazel @@ -1,3 +1,4 @@ +load("@rules_java//java:defs.bzl", "java_library") load("//:testing.bzl", "junit4_test_suites") package(default_applicable_licenses = ["//:license"]) diff --git a/validator/validators/BUILD.bazel b/validator/validators/BUILD.bazel index a34f03049..b5498d682 100644 --- a/validator/validators/BUILD.bazel +++ b/validator/validators/BUILD.bazel @@ -1,3 +1,5 @@ +load("@rules_java//java:defs.bzl", "java_library") + package( default_applicable_licenses = ["//:license"], default_visibility = ["//visibility:public"], From d80531c2a9d17876a16b433807f9f1c549d7b813 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Sun, 29 Sep 2024 23:42:11 -0700 Subject: [PATCH 205/486] Make CelAbstractSyntaxTree and its dependents an AutoValue class to allow for equality checks PiperOrigin-RevId: 680437295 --- .../dev/cel/common/CelAbstractSyntaxTree.java | 51 +++++-------- .../main/java/dev/cel/common/CelSource.java | 75 +++++++++---------- .../common/internal/BasicCodePointArray.java | 45 +++++------ .../common/internal/CelCodePointArray.java | 9 ++- .../common/internal/Latin1CodePointArray.java | 44 +++++------ .../internal/SupplementalCodePointArray.java | 45 +++++------ .../src/test/java/dev/cel/common/BUILD.bazel | 4 + .../cel/common/CelAbstractSyntaxTreeTest.java | 28 +++++++ 8 files changed, 146 insertions(+), 155 deletions(-) diff --git a/common/src/main/java/dev/cel/common/CelAbstractSyntaxTree.java b/common/src/main/java/dev/cel/common/CelAbstractSyntaxTree.java index 3d55bde38..59023adfd 100644 --- a/common/src/main/java/dev/cel/common/CelAbstractSyntaxTree.java +++ b/common/src/main/java/dev/cel/common/CelAbstractSyntaxTree.java @@ -15,6 +15,7 @@ package dev.cel.common; import dev.cel.expr.Type; +import com.google.auto.value.AutoValue; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.errorprone.annotations.Immutable; @@ -36,16 +37,17 @@ *

Note: Use {@link CelProtoAbstractSyntaxTree} if you need access to the protobuf equivalent * ASTs, such as ParsedExpr and CheckedExpr from syntax.proto or checked.proto. */ +@AutoValue @Immutable -public final class CelAbstractSyntaxTree { +public abstract class CelAbstractSyntaxTree { - private final CelSource celSource; + abstract CelSource celSource(); - private final CelExpr celExpr; + abstract CelExpr celExpr(); - private final ImmutableMap references; + abstract ImmutableMap references(); - private final ImmutableMap types; + abstract ImmutableMap types(); /** * Constructs a new instance of CelAbstractSyntaxTree that represent a parsed expression. @@ -54,7 +56,8 @@ public final class CelAbstractSyntaxTree { * validating or optimizing an AST. */ public static CelAbstractSyntaxTree newParsedAst(CelExpr celExpr, CelSource celSource) { - return new CelAbstractSyntaxTree(celExpr, celSource); + return new AutoValue_CelAbstractSyntaxTree( + celSource, celExpr, ImmutableMap.of(), ImmutableMap.of()); } /** @@ -69,32 +72,18 @@ public static CelAbstractSyntaxTree newCheckedAst( CelSource celSource, Map references, Map types) { - return new CelAbstractSyntaxTree(celExpr, celSource, references, types); - } - - private CelAbstractSyntaxTree(CelExpr celExpr, CelSource celSource) { - this(celExpr, celSource, ImmutableMap.of(), ImmutableMap.of()); - } - - private CelAbstractSyntaxTree( - CelExpr celExpr, - CelSource celSource, - Map references, - Map types) { - this.celExpr = celExpr; - this.celSource = celSource; - this.references = ImmutableMap.copyOf(references); - this.types = ImmutableMap.copyOf(types); + return new AutoValue_CelAbstractSyntaxTree( + celSource, celExpr, ImmutableMap.copyOf(references), ImmutableMap.copyOf(types)); } /** Returns the underlying {@link CelExpr} representation of the abstract syntax tree. */ public CelExpr getExpr() { - return celExpr; + return celExpr(); } /** Tests whether the underlying abstract syntax tree has been type checked or not. */ public boolean isChecked() { - return !types.isEmpty(); + return !types().isEmpty(); } /** @@ -117,23 +106,23 @@ public Type getProtoResultType() { * Returns the {@link CelSource} that was used during construction of the abstract syntax tree. */ public CelSource getSource() { - return celSource; + return celSource(); } public Optional getType(long exprId) { - return Optional.ofNullable(types.get(exprId)); + return Optional.ofNullable(types().get(exprId)); } public ImmutableMap getTypeMap() { - return types; + return types(); } public Optional getReference(long exprId) { - return Optional.ofNullable(references.get(exprId)); + return Optional.ofNullable(references().get(exprId)); } public ImmutableMap getReferenceMap() { - return references; + return references(); } public CelReference getReferenceOrThrow(long exprId) { @@ -142,12 +131,12 @@ public CelReference getReferenceOrThrow(long exprId) { } Optional findEnumValue(long exprId) { - CelReference ref = references.get(exprId); + CelReference ref = references().get(exprId); return ref != null ? ref.value() : Optional.empty(); } Optional> findOverloadIDs(long exprId) { - CelReference ref = references.get(exprId); + CelReference ref = references().get(exprId); return ref != null && !ref.value().isPresent() ? Optional.of(ref.overloadIds()) : Optional.empty(); diff --git a/common/src/main/java/dev/cel/common/CelSource.java b/common/src/main/java/dev/cel/common/CelSource.java index 1c8d4dbe8..2678a0a2c 100644 --- a/common/src/main/java/dev/cel/common/CelSource.java +++ b/common/src/main/java/dev/cel/common/CelSource.java @@ -36,37 +36,34 @@ /** Represents the source content of an expression and related metadata. */ @Immutable -public final class CelSource implements Source { - - private final CelCodePointArray codePoints; - private final String description; - private final ImmutableList lineOffsets; - private final ImmutableMap positions; - private final ImmutableMap macroCalls; - private final ImmutableSet extensions; - - private CelSource(Builder builder) { - this.codePoints = checkNotNull(builder.codePoints); - this.description = checkNotNull(builder.description); - this.positions = checkNotNull(ImmutableMap.copyOf(builder.positions)); - this.lineOffsets = checkNotNull(ImmutableList.copyOf(builder.lineOffsets)); - this.macroCalls = checkNotNull(ImmutableMap.copyOf(builder.macroCalls)); - this.extensions = checkNotNull(builder.extensions.build()); - } +@AutoValue +public abstract class CelSource implements Source { + + abstract CelCodePointArray codePoints(); + + abstract String description(); + + abstract ImmutableList lineOffsets(); + + abstract ImmutableMap positions(); + + abstract ImmutableMap macroCalls(); + + abstract ImmutableSet extensions(); @Override public CelCodePointArray getContent() { - return codePoints; + return codePoints(); } @Override public String getDescription() { - return description; + return description(); } @Override public ImmutableMap getPositionsMap() { - return positions; + return positions(); } /** @@ -76,15 +73,15 @@ public ImmutableMap getPositionsMap() { *

NOTE: The indices point to the index just after the '\n' not the index of '\n' itself. */ public ImmutableList getLineOffsets() { - return lineOffsets; + return lineOffsets(); } public ImmutableMap getMacroCalls() { - return macroCalls; + return macroCalls(); } public ImmutableSet getExtensions() { - return extensions; + return extensions(); } /** See {@link #getLocationOffset(int, int)}. */ @@ -101,19 +98,19 @@ public Optional getLocationOffset(CelSourceLocation location) { * @param column the column number starting from 0 */ public Optional getLocationOffset(int line, int column) { - return getLocationOffsetImpl(lineOffsets, line, column); + return getLocationOffsetImpl(lineOffsets(), line, column); } /** * Get the line and column in the source expression text for the given code point {@code offset}. */ public Optional getOffsetLocation(int offset) { - return CelSourceHelper.getOffsetLocation(codePoints, offset); + return CelSourceHelper.getOffsetLocation(codePoints(), offset); } @Override public Optional getSnippet(int line) { - return CelSourceHelper.getSnippet(codePoints, line); + return CelSourceHelper.getSnippet(codePoints(), line); } /** @@ -136,11 +133,11 @@ private static Optional getLocationOffsetImpl( } public Builder toBuilder() { - return new Builder(codePoints, lineOffsets) - .setDescription(description) - .addPositionsMap(positions) - .addAllExtensions(extensions) - .addAllMacroCalls(macroCalls); + return new Builder(codePoints(), lineOffsets()) + .setDescription(description()) + .addPositionsMap(positions()) + .addAllExtensions(extensions()) + .addAllMacroCalls(macroCalls()); } public static Builder newBuilder() { @@ -236,12 +233,6 @@ public Builder addAllMacroCalls(Map macroCalls) { return this; } - @CanIgnoreReturnValue - public Builder clearMacroCall(long exprId) { - this.macroCalls.remove(exprId); - return this; - } - public ImmutableSet getExtensions() { return extensions.build(); } @@ -308,7 +299,13 @@ public boolean containsMacroCalls(long exprId) { @CheckReturnValue public CelSource build() { - return new CelSource(this); + return new AutoValue_CelSource( + codePoints, + description, + ImmutableList.copyOf(lineOffsets), + ImmutableMap.copyOf(positions), + ImmutableMap.copyOf(macroCalls), + extensions.build()); } } @@ -369,7 +366,7 @@ public enum Component { /** Type checker. Checks that references in an AST are defined and types agree. */ COMPONENT_TYPE_CHECKER, /** Runtime. Evaluates a parsed and optionally checked CEL AST against a context. */ - COMPONENT_RUNTIME; + COMPONENT_RUNTIME } @CheckReturnValue diff --git a/common/src/main/java/dev/cel/common/internal/BasicCodePointArray.java b/common/src/main/java/dev/cel/common/internal/BasicCodePointArray.java index 251f09d61..a240df763 100644 --- a/common/src/main/java/dev/cel/common/internal/BasicCodePointArray.java +++ b/common/src/main/java/dev/cel/common/internal/BasicCodePointArray.java @@ -18,6 +18,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkPositionIndexes; +import com.google.auto.value.AutoValue; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableList; import com.google.errorprone.annotations.Immutable; @@ -32,50 +33,40 @@ @Immutable @VisibleForTesting @Internal -public final class BasicCodePointArray extends CelCodePointArray { +@AutoValue +@AutoValue.CopyAnnotations +@SuppressWarnings("Immutable") // char[] is not exposed externally, thus cannot be mutated. +public abstract class BasicCodePointArray extends CelCodePointArray { - @SuppressWarnings("Immutable") - private final char[] codePoints; + @SuppressWarnings("AutoValueImmutableFields") + abstract char[] codePoints(); - private final int offset; - private final int size; - private final ImmutableList lineOffsets; + abstract int offset(); - BasicCodePointArray(char[] codePoints, int size, ImmutableList lineOffsets) { - this(codePoints, 0, lineOffsets, size); + static BasicCodePointArray create( + char[] codePoints, int size, ImmutableList lineOffsets) { + return create(codePoints, 0, lineOffsets, size); } - BasicCodePointArray(char[] codePoints, int offset, ImmutableList lineOffsets, int size) { - this.codePoints = checkNotNull(codePoints); - this.offset = offset; - this.size = size; - this.lineOffsets = lineOffsets; + static BasicCodePointArray create( + char[] codePoints, int offset, ImmutableList lineOffsets, int size) { + return new AutoValue_BasicCodePointArray(size, checkNotNull(lineOffsets), codePoints, offset); } @Override public BasicCodePointArray slice(int i, int j) { checkPositionIndexes(i, j, size()); - return new BasicCodePointArray(codePoints, offset + i, lineOffsets, j - i); + return create(codePoints(), offset() + i, lineOffsets(), j - i); } @Override public int get(int index) { checkElementIndex(index, size()); - return codePoints[offset + index] & 0xffff; + return codePoints()[offset() + index] & 0xffff; } @Override - public int size() { - return size; - } - - @Override - public ImmutableList lineOffsets() { - return lineOffsets; - } - - @Override - public String toString() { - return new String(codePoints, offset, size); + public final String toString() { + return new String(codePoints(), offset(), size()); } } diff --git a/common/src/main/java/dev/cel/common/internal/CelCodePointArray.java b/common/src/main/java/dev/cel/common/internal/CelCodePointArray.java index 94d94b5dc..1f3124c93 100644 --- a/common/src/main/java/dev/cel/common/internal/CelCodePointArray.java +++ b/common/src/main/java/dev/cel/common/internal/CelCodePointArray.java @@ -101,11 +101,12 @@ public static CelCodePointArray fromString(String text) { intArray[intIndex++] = codePoint; } - return new SupplementalCodePointArray( + return SupplementalCodePointArray.create( intArray, intIndex, lineOffsetContext.buildLineOffsets()); } - return new BasicCodePointArray(charArray, charIndex, lineOffsetContext.buildLineOffsets()); + return BasicCodePointArray.create( + charArray, charIndex, lineOffsetContext.buildLineOffsets()); } int[] intArray = new int[text.length()]; int intIndex = 0; @@ -120,11 +121,11 @@ public static CelCodePointArray fromString(String text) { intArray[intIndex++] = codePoint; } - return new SupplementalCodePointArray( + return SupplementalCodePointArray.create( intArray, intIndex, lineOffsetContext.buildLineOffsets()); } - return new Latin1CodePointArray(byteArray, byteIndex, lineOffsetContext.buildLineOffsets()); + return Latin1CodePointArray.create(byteArray, byteIndex, lineOffsetContext.buildLineOffsets()); } private static class LineOffsetContext { diff --git a/common/src/main/java/dev/cel/common/internal/Latin1CodePointArray.java b/common/src/main/java/dev/cel/common/internal/Latin1CodePointArray.java index a06448aba..9e54c3a6c 100644 --- a/common/src/main/java/dev/cel/common/internal/Latin1CodePointArray.java +++ b/common/src/main/java/dev/cel/common/internal/Latin1CodePointArray.java @@ -19,6 +19,7 @@ import static com.google.common.base.Preconditions.checkPositionIndexes; import static java.nio.charset.StandardCharsets.ISO_8859_1; +import com.google.auto.value.AutoValue; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableList; import com.google.errorprone.annotations.Immutable; @@ -32,51 +33,40 @@ @Immutable @VisibleForTesting @Internal -public final class Latin1CodePointArray extends CelCodePointArray { +@AutoValue +@AutoValue.CopyAnnotations +@SuppressWarnings("Immutable") // byte[] is not exposed externally, thus cannot be mutated. +public abstract class Latin1CodePointArray extends CelCodePointArray { - @SuppressWarnings("Immutable") - private final byte[] codePoints; + @SuppressWarnings("AutoValueImmutableFields") + abstract byte[] codePoints(); - private final int offset; - private final int size; - private final ImmutableList lineOffsets; + abstract int offset(); - Latin1CodePointArray(byte[] codePoints, int size, ImmutableList lineOffsets) { - this(codePoints, 0, lineOffsets, size); + static Latin1CodePointArray create( + byte[] codePoints, int size, ImmutableList lineOffsets) { + return create(codePoints, 0, lineOffsets, size); } - Latin1CodePointArray( + static Latin1CodePointArray create( byte[] codePoints, int offset, ImmutableList lineOffsets, int size) { - this.codePoints = checkNotNull(codePoints); - this.offset = offset; - this.size = size; - this.lineOffsets = lineOffsets; + return new AutoValue_Latin1CodePointArray(size, checkNotNull(lineOffsets), codePoints, offset); } @Override public Latin1CodePointArray slice(int i, int j) { checkPositionIndexes(i, j, size()); - return new Latin1CodePointArray(codePoints, offset + i, lineOffsets, j - i); + return create(codePoints(), offset() + i, lineOffsets(), j - i); } @Override public int get(int index) { checkElementIndex(index, size()); - return Byte.toUnsignedInt(codePoints[offset + index]); + return Byte.toUnsignedInt(codePoints()[offset() + index]); } @Override - public int size() { - return size; - } - - @Override - public ImmutableList lineOffsets() { - return lineOffsets; - } - - @Override - public String toString() { - return new String(codePoints, offset, size, ISO_8859_1); + public final String toString() { + return new String(codePoints(), offset(), size(), ISO_8859_1); } } diff --git a/common/src/main/java/dev/cel/common/internal/SupplementalCodePointArray.java b/common/src/main/java/dev/cel/common/internal/SupplementalCodePointArray.java index 30f2fce27..dc3cb10a4 100644 --- a/common/src/main/java/dev/cel/common/internal/SupplementalCodePointArray.java +++ b/common/src/main/java/dev/cel/common/internal/SupplementalCodePointArray.java @@ -18,6 +18,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkPositionIndexes; +import com.google.auto.value.AutoValue; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableList; import com.google.errorprone.annotations.Immutable; @@ -32,51 +33,41 @@ @Immutable @VisibleForTesting @Internal -public final class SupplementalCodePointArray extends CelCodePointArray { +@AutoValue +@AutoValue.CopyAnnotations +@SuppressWarnings("Immutable") // int[] is not exposed externally, thus cannot be mutated. +public abstract class SupplementalCodePointArray extends CelCodePointArray { - @SuppressWarnings("Immutable") - private final int[] codePoints; + @SuppressWarnings("AutoValueImmutableFields") + abstract int[] codePoints(); - private final int offset; - private final int size; - private final ImmutableList lineOffsets; + abstract int offset(); - SupplementalCodePointArray(int[] codePoints, int size, ImmutableList lineOffsets) { - this(codePoints, 0, lineOffsets, size); + static SupplementalCodePointArray create( + int[] codePoints, int size, ImmutableList lineOffsets) { + return create(codePoints, 0, lineOffsets, size); } - SupplementalCodePointArray( + static SupplementalCodePointArray create( int[] codePoints, int offset, ImmutableList lineOffsets, int size) { - this.codePoints = checkNotNull(codePoints); - this.offset = offset; - this.size = size; - this.lineOffsets = lineOffsets; + return new AutoValue_SupplementalCodePointArray( + size, checkNotNull(lineOffsets), codePoints, offset); } @Override public SupplementalCodePointArray slice(int i, int j) { checkPositionIndexes(i, j, size()); - return new SupplementalCodePointArray(codePoints, offset + i, lineOffsets, j - i); + return create(codePoints(), offset() + i, lineOffsets(), j - i); } @Override public int get(int index) { checkElementIndex(index, size()); - return codePoints[offset + index]; + return codePoints()[offset() + index]; } @Override - public int size() { - return size; - } - - @Override - public ImmutableList lineOffsets() { - return lineOffsets; - } - - @Override - public String toString() { - return new String(codePoints, offset, size); + public final String toString() { + return new String(codePoints(), offset(), size()); } } diff --git a/common/src/test/java/dev/cel/common/BUILD.bazel b/common/src/test/java/dev/cel/common/BUILD.bazel index 0f201e480..b277d5c4d 100644 --- a/common/src/test/java/dev/cel/common/BUILD.bazel +++ b/common/src/test/java/dev/cel/common/BUILD.bazel @@ -24,11 +24,15 @@ java_library( "//common/types", "//common/types:cel_types", "//common/types:cel_v1alpha1_types", + "//compiler", + "//compiler:compiler_builder", + "//parser:macro", "@@protobuf~//java/core", "@cel_spec//proto/cel/expr:expr_java_proto", "@com_google_googleapis//google/api/expr/v1alpha1:expr_java_proto", "@com_google_googleapis//google/rpc/context:attribute_context_java_proto", "@maven//:com_google_guava_guava", + "@maven//:com_google_guava_guava_testlib", "@maven//:com_google_testparameterinjector_test_parameter_injector", "@maven//:com_google_truth_extensions_truth_proto_extension", "@maven//:junit_junit", diff --git a/common/src/test/java/dev/cel/common/CelAbstractSyntaxTreeTest.java b/common/src/test/java/dev/cel/common/CelAbstractSyntaxTreeTest.java index 48e28894a..2cdf81380 100644 --- a/common/src/test/java/dev/cel/common/CelAbstractSyntaxTreeTest.java +++ b/common/src/test/java/dev/cel/common/CelAbstractSyntaxTreeTest.java @@ -26,10 +26,14 @@ import dev.cel.expr.SourceInfo; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import com.google.common.testing.EqualsTester; import dev.cel.common.ast.CelConstant; import dev.cel.common.ast.CelExpr; import dev.cel.common.types.CelTypes; import dev.cel.common.types.SimpleType; +import dev.cel.compiler.CelCompiler; +import dev.cel.compiler.CelCompilerFactory; +import dev.cel.parser.CelStandardMacro; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -146,6 +150,30 @@ public void getSource_hasDescriptionEqualToSourceLocation() { assertThat(PARSED_AST.getSource().getDescription()).isEqualTo("test/location.cel"); } + @Test + public void equalityTest() throws Exception { + CelCompiler celCompiler = + CelCompilerFactory.standardCelCompilerBuilder() + .setStandardMacros(CelStandardMacro.STANDARD_MACROS) + .setOptions(CelOptions.current().populateMacroCalls(true).build()) + .build(); + new EqualsTester() + .addEqualityGroup( + CelAbstractSyntaxTree.newParsedAst( + CelExpr.newBuilder().build(), CelSource.newBuilder().build())) + .addEqualityGroup( + celCompiler.compile("'foo'").getAst(), celCompiler.compile("'foo'").getAst()) // ASCII + .addEqualityGroup( + celCompiler.compile("'가나다'").getAst(), celCompiler.compile("'가나다'").getAst()) // BMP + .addEqualityGroup( + celCompiler.compile("'😦😁😑'").getAst(), + celCompiler.compile("'😦😁😑'").getAst()) // SMP + .addEqualityGroup( + celCompiler.compile("[1,2,3].exists(x, x > 0)").getAst(), + celCompiler.compile("[1,2,3].exists(x, x > 0)").getAst()) + .testEquals(); + } + @Test public void parsedExpression_createAst() { CelExpr celExpr = CelExpr.newBuilder().setId(1).setConstant(CelConstant.ofValue(2)).build(); From 2f6f308205c14fbda9607bb26a21b01a5cb96a80 Mon Sep 17 00:00:00 2001 From: Tristan Swadell Date: Sat, 5 Oct 2024 17:30:22 -0700 Subject: [PATCH 206/486] Ensure empty YAML inputs yield checked exceptions PiperOrigin-RevId: 682755056 --- policy/src/main/java/dev/cel/policy/BUILD.bazel | 1 - .../java/dev/cel/policy/CelPolicyYamlConfigParser.java | 8 +++++++- .../main/java/dev/cel/policy/CelPolicyYamlParser.java | 9 ++++++++- policy/src/main/java/dev/cel/policy/YamlHelper.java | 6 +++--- 4 files changed, 18 insertions(+), 6 deletions(-) diff --git a/policy/src/main/java/dev/cel/policy/BUILD.bazel b/policy/src/main/java/dev/cel/policy/BUILD.bazel index 546853bb8..bc96866b2 100644 --- a/policy/src/main/java/dev/cel/policy/BUILD.bazel +++ b/policy/src/main/java/dev/cel/policy/BUILD.bazel @@ -117,7 +117,6 @@ java_library( ":value_string", ":yaml_helper", "//common:compiler_common", - "//common:source_location", "//common/internal", "@maven//:com_google_guava_guava", "@maven//:org_yaml_snakeyaml", diff --git a/policy/src/main/java/dev/cel/policy/CelPolicyYamlConfigParser.java b/policy/src/main/java/dev/cel/policy/CelPolicyYamlConfigParser.java index 6d84c8fcb..204125b71 100644 --- a/policy/src/main/java/dev/cel/policy/CelPolicyYamlConfigParser.java +++ b/policy/src/main/java/dev/cel/policy/CelPolicyYamlConfigParser.java @@ -338,7 +338,13 @@ private CelPolicyConfig parseYaml(String source, String description) throws CelPolicyValidationException { Node node; try { - node = parseYamlSource(source); + Node yamlNode = + parseYamlSource(source) + .orElseThrow( + () -> + new CelPolicyValidationException( + String.format("YAML document is malformed: %s", source))); + node = yamlNode; } catch (RuntimeException e) { throw new CelPolicyValidationException("YAML document is malformed: " + e.getMessage(), e); } diff --git a/policy/src/main/java/dev/cel/policy/CelPolicyYamlParser.java b/policy/src/main/java/dev/cel/policy/CelPolicyYamlParser.java index 318f44fbc..841dadf08 100644 --- a/policy/src/main/java/dev/cel/policy/CelPolicyYamlParser.java +++ b/policy/src/main/java/dev/cel/policy/CelPolicyYamlParser.java @@ -66,8 +66,15 @@ private static class ParserImpl implements PolicyParserContext { private CelPolicy parseYaml() throws CelPolicyValidationException { Node node; + String policySourceString = policySource.getContent().toString(); try { - node = YamlHelper.parseYamlSource(policySource.getContent().toString()); + Node yamlNode = + YamlHelper.parseYamlSource(policySourceString) + .orElseThrow( + () -> + new CelPolicyValidationException( + String.format("YAML document is malformed: %s", policySourceString))); + node = yamlNode; } catch (RuntimeException e) { throw new CelPolicyValidationException("YAML document is malformed: " + e.getMessage(), e); } diff --git a/policy/src/main/java/dev/cel/policy/YamlHelper.java b/policy/src/main/java/dev/cel/policy/YamlHelper.java index c289c73f6..2642cac44 100644 --- a/policy/src/main/java/dev/cel/policy/YamlHelper.java +++ b/policy/src/main/java/dev/cel/policy/YamlHelper.java @@ -20,6 +20,7 @@ import com.google.common.base.Joiner; import java.io.StringReader; import java.util.List; +import java.util.Optional; import org.yaml.snakeyaml.LoaderOptions; import org.yaml.snakeyaml.Yaml; import org.yaml.snakeyaml.constructor.SafeConstructor; @@ -68,10 +69,9 @@ public static boolean assertYamlType( return false; } - static Node parseYamlSource(String policyContent) { + static Optional parseYamlSource(String policyContent) { Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions())); - - return yaml.compose(new StringReader(policyContent)); + return Optional.ofNullable(yaml.compose(new StringReader(policyContent))); } static boolean assertRequiredFields( From 0da0145ee8cbd074d4b62a01dc9070137e1bfc5d Mon Sep 17 00:00:00 2001 From: Tristan Swadell Date: Sun, 6 Oct 2024 00:01:55 -0700 Subject: [PATCH 207/486] Additional test case and error message refinement PiperOrigin-RevId: 682818292 --- .../main/java/dev/cel/policy/CelPolicyYamlConfigParser.java | 2 +- policy/src/main/java/dev/cel/policy/CelPolicyYamlParser.java | 3 ++- .../java/dev/cel/policy/CelPolicyYamlConfigParserTest.java | 5 +++++ .../test/java/dev/cel/policy/CelPolicyYamlParserTest.java | 5 +++++ 4 files changed, 13 insertions(+), 2 deletions(-) diff --git a/policy/src/main/java/dev/cel/policy/CelPolicyYamlConfigParser.java b/policy/src/main/java/dev/cel/policy/CelPolicyYamlConfigParser.java index 204125b71..b37952fb9 100644 --- a/policy/src/main/java/dev/cel/policy/CelPolicyYamlConfigParser.java +++ b/policy/src/main/java/dev/cel/policy/CelPolicyYamlConfigParser.java @@ -343,7 +343,7 @@ private CelPolicyConfig parseYaml(String source, String description) .orElseThrow( () -> new CelPolicyValidationException( - String.format("YAML document is malformed: %s", source))); + String.format("YAML document empty or malformed: %s", source))); node = yamlNode; } catch (RuntimeException e) { throw new CelPolicyValidationException("YAML document is malformed: " + e.getMessage(), e); diff --git a/policy/src/main/java/dev/cel/policy/CelPolicyYamlParser.java b/policy/src/main/java/dev/cel/policy/CelPolicyYamlParser.java index 841dadf08..5e527e73f 100644 --- a/policy/src/main/java/dev/cel/policy/CelPolicyYamlParser.java +++ b/policy/src/main/java/dev/cel/policy/CelPolicyYamlParser.java @@ -73,7 +73,8 @@ private CelPolicy parseYaml() throws CelPolicyValidationException { .orElseThrow( () -> new CelPolicyValidationException( - String.format("YAML document is malformed: %s", policySourceString))); + String.format( + "YAML document empty or malformed: %s", policySourceString))); node = yamlNode; } catch (RuntimeException e) { throw new CelPolicyValidationException("YAML document is malformed: " + e.getMessage(), e); diff --git a/policy/src/test/java/dev/cel/policy/CelPolicyYamlConfigParserTest.java b/policy/src/test/java/dev/cel/policy/CelPolicyYamlConfigParserTest.java index 630bfc76e..f4c0f2f1c 100644 --- a/policy/src/test/java/dev/cel/policy/CelPolicyYamlConfigParserTest.java +++ b/policy/src/test/java/dev/cel/policy/CelPolicyYamlConfigParserTest.java @@ -43,6 +43,11 @@ public final class CelPolicyYamlConfigParserTest { private static final CelPolicyConfigParser POLICY_CONFIG_PARSER = CelPolicyParserFactory.newYamlConfigParser(); + @Test + public void config_setEmpty() throws Exception { + assertThrows(CelPolicyValidationException.class, () -> POLICY_CONFIG_PARSER.parse("")); + } + @Test public void config_setBasicProperties() throws Exception { String yamlConfig = "name: hello\n" + "description: empty\n" + "container: pb.pkg\n"; diff --git a/policy/src/test/java/dev/cel/policy/CelPolicyYamlParserTest.java b/policy/src/test/java/dev/cel/policy/CelPolicyYamlParserTest.java index c648d3ac3..a62b7255e 100644 --- a/policy/src/test/java/dev/cel/policy/CelPolicyYamlParserTest.java +++ b/policy/src/test/java/dev/cel/policy/CelPolicyYamlParserTest.java @@ -43,6 +43,11 @@ public void parseYamlPolicy_success(@TestParameter TestYamlPolicy yamlPolicy) th assertThat(policy.policySource().getDescription()).isEqualTo(description); } + @Test + public void parser_setEmpty() throws Exception { + assertThrows(CelPolicyValidationException.class, () -> POLICY_PARSER.parse("", "")); + } + @Test public void parseYamlPolicy_withExplanation() throws Exception { String policySource = From 23354f4807fb827c2357b235fa3480873b5996d8 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Thu, 10 Oct 2024 10:21:28 -0700 Subject: [PATCH 208/486] Fix CEL-Java to be fully protobuf v4 compatible Fixes https://github.com/google/cel-java/issues/462 PiperOrigin-RevId: 684490250 --- .bazelrc | 3 +++ WORKSPACE | 26 +++++++++---------- .../src/main/java/dev/cel/bundle/BUILD.bazel | 2 +- .../src/test/java/dev/cel/bundle/BUILD.bazel | 2 +- .../src/main/java/dev/cel/checker/BUILD.bazel | 10 +++---- .../src/test/java/dev/cel/checker/BUILD.bazel | 2 +- codelab/src/main/codelab/BUILD.bazel | 2 +- .../src/main/codelab/solutions/BUILD.bazel | 2 +- codelab/src/test/codelab/BUILD.bazel | 6 ++--- .../src/test/codelab/solutions/BUILD.bazel | 6 ++--- .../src/main/java/dev/cel/common/BUILD.bazel | 4 +-- .../main/java/dev/cel/common/ast/BUILD.bazel | 4 +-- .../java/dev/cel/common/internal/BUILD.bazel | 18 ++++++------- .../java/dev/cel/common/types/BUILD.bazel | 6 ++--- .../java/dev/cel/common/values/BUILD.bazel | 4 +-- .../src/test/java/dev/cel/common/BUILD.bazel | 2 +- .../test/java/dev/cel/common/ast/BUILD.bazel | 2 +- .../java/dev/cel/common/internal/BUILD.bazel | 2 +- .../java/dev/cel/common/values/BUILD.bazel | 2 +- .../main/java/dev/cel/compiler/BUILD.bazel | 4 +-- .../test/java/dev/cel/conformance/BUILD.bazel | 2 +- .../main/java/dev/cel/extensions/BUILD.bazel | 4 +-- .../test/java/dev/cel/extensions/BUILD.bazel | 2 +- .../src/main/java/dev/cel/parser/BUILD.bazel | 2 +- .../src/test/java/dev/cel/parser/BUILD.bazel | 2 +- .../src/main/java/dev/cel/runtime/BUILD.bazel | 8 +++--- .../src/test/java/dev/cel/runtime/BUILD.bazel | 2 +- .../src/main/java/dev/cel/testing/BUILD.bazel | 4 +-- .../dev/cel/validator/validators/BUILD.bazel | 4 +-- .../dev/cel/validator/validators/BUILD.bazel | 2 +- 30 files changed, 72 insertions(+), 69 deletions(-) create mode 100644 .bazelrc diff --git a/.bazelrc b/.bazelrc new file mode 100644 index 000000000..0e8299f1d --- /dev/null +++ b/.bazelrc @@ -0,0 +1,3 @@ +build --cxxopt=-std=c++14 +build --host_cxxopt=-std=c++14 +common --noenable_bzlmod diff --git a/WORKSPACE b/WORKSPACE index 4dc16ce61..97ecd141a 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -73,20 +73,20 @@ maven_install( "com.google.auto.value:auto-value:1.11.0", "com.google.auto.value:auto-value-annotations:1.11.0", "com.google.code.findbugs:annotations:3.0.1", - "com.google.errorprone:error_prone_annotations:2.30.0", - "com.google.guava:guava:33.3.0-jre", - "com.google.guava:guava-testlib:33.3.0-jre", - "com.google.protobuf:protobuf-java:4.28.0", - "com.google.protobuf:protobuf-java-util:4.28.0", + "com.google.errorprone:error_prone_annotations:2.33.0", + "com.google.guava:guava:33.3.1-jre", + "com.google.guava:guava-testlib:33.3.1-jre", + "com.google.protobuf:protobuf-java:4.28.2", + "com.google.protobuf:protobuf-java-util:4.28.2", "com.google.re2j:re2j:1.7", - "com.google.testparameterinjector:test-parameter-injector:1.15", - "com.google.truth.extensions:truth-java8-extension:1.4.2", - "com.google.truth.extensions:truth-proto-extension:1.4.2", - "com.google.truth:truth:1.4.2", + "com.google.testparameterinjector:test-parameter-injector:1.18", + "com.google.truth.extensions:truth-java8-extension:1.4.4", + "com.google.truth.extensions:truth-proto-extension:1.4.4", + "com.google.truth:truth:1.4.4", "org.antlr:antlr4-runtime:" + ANTLR4_VERSION, "org.jspecify:jspecify:1.0.0", "org.threeten:threeten-extra:1.8.0", - "org.yaml:snakeyaml:2.2", + "org.yaml:snakeyaml:2.3", ], repositories = [ "https://maven.google.com", @@ -96,9 +96,9 @@ maven_install( http_archive( name = "com_google_protobuf", - sha256 = "13e7749c30bc24af6ee93e092422f9dc08491c7097efa69461f88eb5f61805ce", - strip_prefix = "protobuf-28.0", - urls = ["https://github.com/protocolbuffers/protobuf/archive/v28.0.tar.gz"], + sha256 = "b2340aa47faf7ef10a0328190319d3f3bee1b24f426d4ce8f4253b6f27ce16db", + strip_prefix = "protobuf-28.2", + urls = ["https://github.com/protocolbuffers/protobuf/archive/v28.2.tar.gz"], ) # Required by com_google_protobuf diff --git a/bundle/src/main/java/dev/cel/bundle/BUILD.bazel b/bundle/src/main/java/dev/cel/bundle/BUILD.bazel index 5ef5123c1..b6f170ee4 100644 --- a/bundle/src/main/java/dev/cel/bundle/BUILD.bazel +++ b/bundle/src/main/java/dev/cel/bundle/BUILD.bazel @@ -39,10 +39,10 @@ java_library( "//parser:macro", "//parser:parser_builder", "//runtime", - "@@protobuf~//java/core", "@cel_spec//proto/cel/expr:expr_java_proto", "@maven//:com_google_code_findbugs_annotations", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", ], ) diff --git a/bundle/src/test/java/dev/cel/bundle/BUILD.bazel b/bundle/src/test/java/dev/cel/bundle/BUILD.bazel index 8b191c25a..be643cce7 100644 --- a/bundle/src/test/java/dev/cel/bundle/BUILD.bazel +++ b/bundle/src/test/java/dev/cel/bundle/BUILD.bazel @@ -33,7 +33,6 @@ java_library( "//parser:macro", "//runtime", "//runtime:unknown_attributes", - "@@protobuf~//java/core", "@cel_spec//proto/cel/expr:expr_java_proto", "@cel_spec//proto/test/v1/proto2:test_all_types_java_proto", "@cel_spec//proto/test/v1/proto3:test_all_types_java_proto", @@ -41,6 +40,7 @@ java_library( "@com_google_googleapis//google/type:type_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_guava_guava_testlib", + "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_protobuf_protobuf_java_util", "@maven//:com_google_testparameterinjector_test_parameter_injector", "@maven//:com_google_truth_extensions_truth_proto_extension", diff --git a/checker/src/main/java/dev/cel/checker/BUILD.bazel b/checker/src/main/java/dev/cel/checker/BUILD.bazel index 3d209db4e..05671f426 100644 --- a/checker/src/main/java/dev/cel/checker/BUILD.bazel +++ b/checker/src/main/java/dev/cel/checker/BUILD.bazel @@ -52,10 +52,10 @@ java_library( "//common/types", "//common/types:cel_types", "//common/types:type_providers", - "@@protobuf~//java/core", "@cel_spec//proto/cel/expr:expr_java_proto", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", "@maven//:org_jspecify_jspecify", ], ) @@ -84,10 +84,10 @@ java_library( "//common/types:cel_types", "//common/types:message_type_provider", "//common/types:type_providers", - "@@protobuf~//java/core", "@cel_spec//proto/cel/expr:expr_java_proto", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", ], ) @@ -103,9 +103,9 @@ java_library( "//common:compiler_common", "//common:options", "//common/types:type_providers", - "@@protobuf~//java/core", "@cel_spec//proto/cel/expr:expr_java_proto", "@maven//:com_google_errorprone_error_prone_annotations", + "@maven//:com_google_protobuf_protobuf_java", ], ) @@ -116,9 +116,9 @@ java_library( ], deps = [ "//:auto_value", - "@@protobuf~//java/core", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", ], ) @@ -184,10 +184,10 @@ java_library( "//common/types:type_providers", "//parser:macro", "//parser:operator", - "@@protobuf~//java/core", "@cel_spec//proto/cel/expr:expr_java_proto", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", "@maven//:org_jspecify_jspecify", ], ) diff --git a/checker/src/test/java/dev/cel/checker/BUILD.bazel b/checker/src/test/java/dev/cel/checker/BUILD.bazel index 096207cc5..e3e410429 100644 --- a/checker/src/test/java/dev/cel/checker/BUILD.bazel +++ b/checker/src/test/java/dev/cel/checker/BUILD.bazel @@ -11,7 +11,7 @@ java_library( srcs = glob(["*Test.java"]), resources = ["//checker/src/test/resources:baselines"], deps = [ - "@@protobuf~//java/core", + "@maven//:com_google_protobuf_protobuf_java", # "//java/com/google/testing/testsize:annotations", "//:auto_value", "//checker", diff --git a/codelab/src/main/codelab/BUILD.bazel b/codelab/src/main/codelab/BUILD.bazel index 2b3eb0247..adeb3b5dd 100644 --- a/codelab/src/main/codelab/BUILD.bazel +++ b/codelab/src/main/codelab/BUILD.bazel @@ -35,9 +35,9 @@ java_library( "//validator/validators:homogeneous_literal", # unuseddeps: keep "//validator/validators:regex", # unuseddeps: keep "//validator/validators:timestamp", # unuseddeps: keep - "@@protobuf~//java/core", # unuseddeps: keep "@com_google_googleapis//google/rpc/context:attribute_context_java_proto", # unuseddeps: keep "@maven//:com_google_guava_guava", # unuseddeps: keep + "@maven//:com_google_protobuf_protobuf_java", # unuseddeps: keep "@maven//:com_google_protobuf_protobuf_java_util", # unuseddeps: keep ], ) diff --git a/codelab/src/main/codelab/solutions/BUILD.bazel b/codelab/src/main/codelab/solutions/BUILD.bazel index 2060e3e8c..458fbe0b4 100644 --- a/codelab/src/main/codelab/solutions/BUILD.bazel +++ b/codelab/src/main/codelab/solutions/BUILD.bazel @@ -35,9 +35,9 @@ java_library( "//validator/validators:homogeneous_literal", "//validator/validators:regex", "//validator/validators:timestamp", - "@@protobuf~//java/core", "@com_google_googleapis//google/rpc/context:attribute_context_java_proto", "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_protobuf_protobuf_java_util", ], ) diff --git a/codelab/src/test/codelab/BUILD.bazel b/codelab/src/test/codelab/BUILD.bazel index 1b39618d0..0cfccfcaa 100644 --- a/codelab/src/test/codelab/BUILD.bazel +++ b/codelab/src/test/codelab/BUILD.bazel @@ -29,9 +29,9 @@ java_test( "//codelab", "//common", "//common/types", - "@@protobuf~//java/core", "@com_google_googleapis//google/rpc/context:attribute_context_java_proto", "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_testparameterinjector_test_parameter_injector", "@maven//:junit_junit", ], @@ -60,9 +60,9 @@ java_test( "//:java_truth", "//codelab", "//common", - "@@protobuf~//java/core", "@com_google_googleapis//google/rpc/context:attribute_context_java_proto", "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_testparameterinjector_test_parameter_injector", "@maven//:junit_junit", ], @@ -93,9 +93,9 @@ java_test( "//:java_truth", "//codelab", "//common", - "@@protobuf~//java/core", "@com_google_googleapis//google/rpc/context:attribute_context_java_proto", "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_protobuf_protobuf_java_util", "@maven//:com_google_testparameterinjector_test_parameter_injector", "@maven//:junit_junit", diff --git a/codelab/src/test/codelab/solutions/BUILD.bazel b/codelab/src/test/codelab/solutions/BUILD.bazel index 6438f8ee2..09e89dc51 100644 --- a/codelab/src/test/codelab/solutions/BUILD.bazel +++ b/codelab/src/test/codelab/solutions/BUILD.bazel @@ -27,9 +27,9 @@ java_test( "//codelab:solutions", "//common", "//common/types", - "@@protobuf~//java/core", "@com_google_googleapis//google/rpc/context:attribute_context_java_proto", "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_testparameterinjector_test_parameter_injector", "@maven//:junit_junit", ], @@ -56,9 +56,9 @@ java_test( "//:java_truth", "//codelab:solutions", "//common", - "@@protobuf~//java/core", "@com_google_googleapis//google/rpc/context:attribute_context_java_proto", "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_testparameterinjector_test_parameter_injector", "@maven//:junit_junit", ], @@ -87,9 +87,9 @@ java_test( "//:java_truth", "//codelab:solutions", "//common", - "@@protobuf~//java/core", "@com_google_googleapis//google/rpc/context:attribute_context_java_proto", "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_protobuf_protobuf_java_util", "@maven//:com_google_testparameterinjector_test_parameter_injector", "@maven//:junit_junit", diff --git a/common/src/main/java/dev/cel/common/BUILD.bazel b/common/src/main/java/dev/cel/common/BUILD.bazel index e254ffbdd..9e4fa12fd 100644 --- a/common/src/main/java/dev/cel/common/BUILD.bazel +++ b/common/src/main/java/dev/cel/common/BUILD.bazel @@ -60,10 +60,10 @@ java_library( "//common/types", "//common/types:cel_types", "//common/types:type_providers", - "@@protobuf~//java/core", "@cel_spec//proto/cel/expr:expr_java_proto", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", ], ) @@ -193,9 +193,9 @@ java_library( tags = [ ], deps = [ - "@@protobuf~//java/core", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_protobuf_protobuf_java_util", ], ) diff --git a/common/src/main/java/dev/cel/common/ast/BUILD.bazel b/common/src/main/java/dev/cel/common/ast/BUILD.bazel index 8cc9be997..a5736cff9 100644 --- a/common/src/main/java/dev/cel/common/ast/BUILD.bazel +++ b/common/src/main/java/dev/cel/common/ast/BUILD.bazel @@ -48,9 +48,9 @@ java_library( deps = [ "//:auto_value", "//common/annotations", - "@@protobuf~//java/core", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", "@maven//:org_jspecify_jspecify", ], ) @@ -98,8 +98,8 @@ java_library( deps = [ ":ast", "//common/annotations", - "@@protobuf~//java/core", "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", ], ) diff --git a/common/src/main/java/dev/cel/common/internal/BUILD.bazel b/common/src/main/java/dev/cel/common/internal/BUILD.bazel index a86c9aa79..6b83b441a 100644 --- a/common/src/main/java/dev/cel/common/internal/BUILD.bazel +++ b/common/src/main/java/dev/cel/common/internal/BUILD.bazel @@ -42,9 +42,9 @@ java_library( "//:auto_value", "//common/annotations", "//common/ast", - "@@protobuf~//java/core", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", "@maven//:org_antlr_antlr4_runtime", ], ) @@ -105,8 +105,8 @@ java_library( ], deps = [ "//common/annotations", - "@@protobuf~//java/core", "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", ], ) @@ -126,11 +126,11 @@ java_library( "//common:proto_json_adapter", "//common:runtime_exception", "//common/annotations", - "@@protobuf~//java/core", "@cel_spec//proto/cel/expr:expr_java_proto", "@maven//:com_google_code_findbugs_annotations", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", "@maven//:org_jspecify_jspecify", ], ) @@ -144,9 +144,9 @@ java_library( ":dynamic_proto", "//:auto_value", "//common/annotations", - "@@protobuf~//java/core", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", "@maven//:org_jspecify_jspecify", ], ) @@ -160,9 +160,9 @@ java_library( ], deps = [ "//:auto_value", - "@@protobuf~//java/core", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", ], ) @@ -184,8 +184,8 @@ java_library( ], deps = [ "//common/annotations", - "@@protobuf~//java/core", "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", ], ) @@ -199,7 +199,7 @@ java_library( ":default_instance_message_factory", ":proto_message_factory", "//common/annotations", - "@@protobuf~//java/core", + "@maven//:com_google_protobuf_protobuf_java", ], ) @@ -210,9 +210,9 @@ java_library( ], deps = [ ":cel_descriptor_pools", - "@@protobuf~//java/core", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", ], ) @@ -225,9 +225,9 @@ java_library( ":well_known_proto", "//common", "//common/annotations", - "@@protobuf~//java/core", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", ], ) diff --git a/common/src/main/java/dev/cel/common/types/BUILD.bazel b/common/src/main/java/dev/cel/common/types/BUILD.bazel index a1f1a68d4..4f4029419 100644 --- a/common/src/main/java/dev/cel/common/types/BUILD.bazel +++ b/common/src/main/java/dev/cel/common/types/BUILD.bazel @@ -75,9 +75,9 @@ java_library( ":type_providers", ":types", "//common/annotations", - "@@protobuf~//java/core", "@cel_spec//proto/cel/expr:expr_java_proto", "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", ], ) @@ -90,9 +90,9 @@ java_library( ":type_providers", ":types", "//common/annotations", - "@@protobuf~//java/core", "@com_google_googleapis//google/api/expr/v1alpha1:expr_java_proto", "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", ], ) @@ -134,8 +134,8 @@ java_library( "//:auto_value", "//common", "//common/internal:file_descriptor_converter", - "@@protobuf~//java/core", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", ], ) diff --git a/common/src/main/java/dev/cel/common/values/BUILD.bazel b/common/src/main/java/dev/cel/common/values/BUILD.bazel index 8f1aa06c2..c9e233108 100644 --- a/common/src/main/java/dev/cel/common/values/BUILD.bazel +++ b/common/src/main/java/dev/cel/common/values/BUILD.bazel @@ -116,9 +116,9 @@ java_library( "//common/types:cel_types", "//common/types:type_providers", "//common/values:cel_byte_string", - "@@protobuf~//java/core", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_protobuf_protobuf_java_util", "@maven//:org_jspecify_jspecify", ], @@ -139,7 +139,7 @@ java_library( "//common/annotations", "//common/internal:dynamic_proto", "//common/internal:proto_message_factory", - "@@protobuf~//java/core", "@maven//:com_google_errorprone_error_prone_annotations", + "@maven//:com_google_protobuf_protobuf_java", ], ) diff --git a/common/src/test/java/dev/cel/common/BUILD.bazel b/common/src/test/java/dev/cel/common/BUILD.bazel index b277d5c4d..bac8affe1 100644 --- a/common/src/test/java/dev/cel/common/BUILD.bazel +++ b/common/src/test/java/dev/cel/common/BUILD.bazel @@ -27,12 +27,12 @@ java_library( "//compiler", "//compiler:compiler_builder", "//parser:macro", - "@@protobuf~//java/core", "@cel_spec//proto/cel/expr:expr_java_proto", "@com_google_googleapis//google/api/expr/v1alpha1:expr_java_proto", "@com_google_googleapis//google/rpc/context:attribute_context_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_guava_guava_testlib", + "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_testparameterinjector_test_parameter_injector", "@maven//:com_google_truth_extensions_truth_proto_extension", "@maven//:junit_junit", diff --git a/common/src/test/java/dev/cel/common/ast/BUILD.bazel b/common/src/test/java/dev/cel/common/ast/BUILD.bazel index 5cfc4eb63..848920037 100644 --- a/common/src/test/java/dev/cel/common/ast/BUILD.bazel +++ b/common/src/test/java/dev/cel/common/ast/BUILD.bazel @@ -29,12 +29,12 @@ java_library( "//extensions:optional_library", "//parser:macro", "//parser:operator", - "@@protobuf~//java/core", "@cel_spec//proto/cel/expr:expr_java_proto", "@cel_spec//proto/test/v1/proto3:test_all_types_java_proto", "@com_google_googleapis//google/api/expr/v1alpha1:expr_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_guava_guava_testlib", + "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_testparameterinjector_test_parameter_injector", "@maven//:junit_junit", ], diff --git a/common/src/test/java/dev/cel/common/internal/BUILD.bazel b/common/src/test/java/dev/cel/common/internal/BUILD.bazel index 9a033b00a..d29f67a50 100644 --- a/common/src/test/java/dev/cel/common/internal/BUILD.bazel +++ b/common/src/test/java/dev/cel/common/internal/BUILD.bazel @@ -31,11 +31,11 @@ java_library( "//common/src/test/resources:service_conflicting_name_java_proto", "//common/src/test/resources:single_file_java_proto", "//common/testing", - "@@protobuf~//java/core", "@cel_spec//proto/test/v1/proto2:test_all_types_java_proto", "@cel_spec//proto/test/v1/proto3:test_all_types_java_proto", "@com_google_googleapis//google/type:type_java_proto", "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_testparameterinjector_test_parameter_injector", "@maven//:junit_junit", ], diff --git a/common/src/test/java/dev/cel/common/values/BUILD.bazel b/common/src/test/java/dev/cel/common/values/BUILD.bazel index 00800a01c..48e90e120 100644 --- a/common/src/test/java/dev/cel/common/values/BUILD.bazel +++ b/common/src/test/java/dev/cel/common/values/BUILD.bazel @@ -25,10 +25,10 @@ java_library( "//common/values:cel_value_provider", "//common/values:proto_message_value", "//common/values:proto_message_value_provider", - "@@protobuf~//java/core", "@cel_spec//proto/test/v1/proto2:test_all_types_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_guava_guava_testlib", + "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_protobuf_protobuf_java_util", "@maven//:com_google_testparameterinjector_test_parameter_injector", "@maven//:junit_junit", diff --git a/compiler/src/main/java/dev/cel/compiler/BUILD.bazel b/compiler/src/main/java/dev/cel/compiler/BUILD.bazel index 63a9cd4e6..22d403b6c 100644 --- a/compiler/src/main/java/dev/cel/compiler/BUILD.bazel +++ b/compiler/src/main/java/dev/cel/compiler/BUILD.bazel @@ -44,10 +44,10 @@ java_library( "//parser", "//parser:macro", "//parser:parser_builder", - "@@protobuf~//java/core", "@cel_spec//proto/cel/expr:expr_java_proto", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", ], ) @@ -66,8 +66,8 @@ java_library( "//common/types:type_providers", "//parser:macro", "//parser:parser_builder", - "@@protobuf~//java/core", "@cel_spec//proto/cel/expr:expr_java_proto", "@maven//:com_google_errorprone_error_prone_annotations", + "@maven//:com_google_protobuf_protobuf_java", ], ) diff --git a/conformance/src/test/java/dev/cel/conformance/BUILD.bazel b/conformance/src/test/java/dev/cel/conformance/BUILD.bazel index f3014aca5..57a83b955 100644 --- a/conformance/src/test/java/dev/cel/conformance/BUILD.bazel +++ b/conformance/src/test/java/dev/cel/conformance/BUILD.bazel @@ -30,13 +30,13 @@ java_library( "//parser:macro", "//parser:parser_builder", "//runtime", - "@@protobuf~//java/core", "@cel_spec//proto/cel/expr:expr_java_proto", "@cel_spec//proto/test/v1:simple_java_proto", "@cel_spec//proto/test/v1/proto2:test_all_types_java_proto", "@cel_spec//proto/test/v1/proto3:test_all_types_java_proto", "@com_google_googleapis//google/api/expr/v1alpha1:expr_java_proto", "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_truth_extensions_truth_proto_extension", "@maven//:junit_junit", ], diff --git a/extensions/src/main/java/dev/cel/extensions/BUILD.bazel b/extensions/src/main/java/dev/cel/extensions/BUILD.bazel index a3256ecca..e14421c9b 100644 --- a/extensions/src/main/java/dev/cel/extensions/BUILD.bazel +++ b/extensions/src/main/java/dev/cel/extensions/BUILD.bazel @@ -104,9 +104,9 @@ java_library( "//common/types", "//compiler:compiler_builder", "//runtime", - "@@protobuf~//java/core", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", ], ) @@ -127,8 +127,8 @@ java_library( "//parser:operator", "//parser:parser_builder", "//runtime", - "@@protobuf~//java/core", "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", ], ) diff --git a/extensions/src/test/java/dev/cel/extensions/BUILD.bazel b/extensions/src/test/java/dev/cel/extensions/BUILD.bazel index 4ed844381..c2d435993 100644 --- a/extensions/src/test/java/dev/cel/extensions/BUILD.bazel +++ b/extensions/src/test/java/dev/cel/extensions/BUILD.bazel @@ -25,11 +25,11 @@ java_library( "//parser:macro", "//runtime", "//runtime:interpreter_util", - "@@protobuf~//java/core", "@cel_spec//proto/cel/expr:expr_java_proto", "@cel_spec//proto/test/v1/proto2:test_all_types_java_proto", "@cel_spec//proto/test/v1/proto3:test_all_types_java_proto", "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_protobuf_protobuf_java_util", "@maven//:com_google_testparameterinjector_test_parameter_injector", "@maven//:junit_junit", diff --git a/parser/src/main/java/dev/cel/parser/BUILD.bazel b/parser/src/main/java/dev/cel/parser/BUILD.bazel index d86b48668..46f68b0bd 100644 --- a/parser/src/main/java/dev/cel/parser/BUILD.bazel +++ b/parser/src/main/java/dev/cel/parser/BUILD.bazel @@ -127,6 +127,6 @@ java_library( "//common", "//common/ast", "//common/ast:cel_expr_visitor", - "@@protobuf~//java/core", + "@maven//:com_google_protobuf_protobuf_java", ], ) diff --git a/parser/src/test/java/dev/cel/parser/BUILD.bazel b/parser/src/test/java/dev/cel/parser/BUILD.bazel index 8697baad6..7972576ff 100644 --- a/parser/src/test/java/dev/cel/parser/BUILD.bazel +++ b/parser/src/test/java/dev/cel/parser/BUILD.bazel @@ -28,11 +28,11 @@ java_library( "//parser:unparser", "//testing:adorner", "//testing:baseline_test_case", - "@@protobuf~//java/core", "@cel_spec//proto/cel/expr:expr_java_proto", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", "@maven//:com_google_guava_guava_testlib", + "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_testparameterinjector_test_parameter_injector", "@maven//:junit_junit", ], diff --git a/runtime/src/main/java/dev/cel/runtime/BUILD.bazel b/runtime/src/main/java/dev/cel/runtime/BUILD.bazel index 6a8c1cea0..e74420b74 100644 --- a/runtime/src/main/java/dev/cel/runtime/BUILD.bazel +++ b/runtime/src/main/java/dev/cel/runtime/BUILD.bazel @@ -57,10 +57,10 @@ java_library( "//common/internal:safe_string_formatter", "//common/types", "//common/types:type_providers", - "@@protobuf~//java/core", "@cel_spec//proto/cel/expr:expr_java_proto", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_protobuf_protobuf_java_util", "@maven//:com_google_re2j_re2j", "@maven//:org_jspecify_jspecify", @@ -94,11 +94,11 @@ java_library( "//common/internal:proto_message_factory", "//common/types:cel_types", "//common/types:type_providers", - "@@protobuf~//java/core", "@cel_spec//proto/cel/expr:expr_java_proto", "@maven//:com_google_code_findbugs_annotations", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", "@maven//:org_jspecify_jspecify", ], ) @@ -121,9 +121,9 @@ java_library( "//common/internal:converter", "//common/internal:dynamic_proto", "//common/internal:proto_equality", - "@@protobuf~//java/core", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_re2j_re2j", "@maven//:org_threeten_threeten_extra", ], @@ -165,10 +165,10 @@ java_library( "//common/values:cel_value_provider", "//common/values:proto_message_value_provider", "//runtime:interpreter", - "@@protobuf~//java/core", "@maven//:com_google_code_findbugs_annotations", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", "@maven//:org_jspecify_jspecify", ], ) diff --git a/runtime/src/test/java/dev/cel/runtime/BUILD.bazel b/runtime/src/test/java/dev/cel/runtime/BUILD.bazel index 6a80864c2..6210df4ec 100644 --- a/runtime/src/test/java/dev/cel/runtime/BUILD.bazel +++ b/runtime/src/test/java/dev/cel/runtime/BUILD.bazel @@ -41,12 +41,12 @@ java_library( "//runtime:runtime_helper", "//runtime:unknown_attributes", "//runtime:unknown_options", - "@@protobuf~//java/core", "@cel_spec//proto/test/v1/proto2:test_all_types_java_proto", "@cel_spec//proto/test/v1/proto3:test_all_types_java_proto", "@com_google_googleapis//google/api/expr/v1alpha1:expr_java_proto", "@com_google_googleapis//google/rpc/context:attribute_context_java_proto", "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_protobuf_protobuf_java_util", "@maven//:com_google_testparameterinjector_test_parameter_injector", "@maven//:com_google_truth_extensions_truth_proto_extension", diff --git a/testing/src/main/java/dev/cel/testing/BUILD.bazel b/testing/src/main/java/dev/cel/testing/BUILD.bazel index bbe1ab489..be0b8ac69 100644 --- a/testing/src/main/java/dev/cel/testing/BUILD.bazel +++ b/testing/src/main/java/dev/cel/testing/BUILD.bazel @@ -77,9 +77,9 @@ java_library( "//compiler", "//compiler:compiler_builder", "//parser:macro", - "@@protobuf~//java/core", "@cel_spec//proto/cel/expr:expr_java_proto", "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", ], ) @@ -107,10 +107,10 @@ java_library( "//extensions:optional_library", "//runtime", "//runtime:runtime_helper", - "@@protobuf~//java/core", "@cel_spec//proto/cel/expr:expr_java_proto", "@cel_spec//proto/test/v1/proto3:test_all_types_java_proto", "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_protobuf_protobuf_java_util", "@maven//:junit_junit", ], diff --git a/validator/src/main/java/dev/cel/validator/validators/BUILD.bazel b/validator/src/main/java/dev/cel/validator/validators/BUILD.bazel index d166cfa76..37868fa3a 100644 --- a/validator/src/main/java/dev/cel/validator/validators/BUILD.bazel +++ b/validator/src/main/java/dev/cel/validator/validators/BUILD.bazel @@ -17,7 +17,7 @@ java_library( ], deps = [ ":literal_validator", - "@@protobuf~//java/core", + "@maven//:com_google_protobuf_protobuf_java", ], ) @@ -30,7 +30,7 @@ java_library( ], deps = [ ":literal_validator", - "@@protobuf~//java/core", + "@maven//:com_google_protobuf_protobuf_java", ], ) diff --git a/validator/src/test/java/dev/cel/validator/validators/BUILD.bazel b/validator/src/test/java/dev/cel/validator/validators/BUILD.bazel index 76f4de78a..5c0ab0e8a 100644 --- a/validator/src/test/java/dev/cel/validator/validators/BUILD.bazel +++ b/validator/src/test/java/dev/cel/validator/validators/BUILD.bazel @@ -24,9 +24,9 @@ java_library( "//validator/validators:homogeneous_literal", "//validator/validators:regex", "//validator/validators:timestamp", - "@@protobuf~//java/core", "@cel_spec//proto/cel/expr:expr_java_proto", "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_protobuf_protobuf_java_util", "@maven//:com_google_testparameterinjector_test_parameter_injector", "@maven//:junit_junit", From e560d8892be6b5aeebfbcce14e3a88ebb6dd397b Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Thu, 10 Oct 2024 10:53:43 -0700 Subject: [PATCH 209/486] Release 0.8.0 PiperOrigin-RevId: 684501939 --- README.md | 4 ++-- publish/cel_version.bzl | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 7d673e4db..01e0a1450 100644 --- a/README.md +++ b/README.md @@ -55,14 +55,14 @@ CEL-Java is available in Maven Central Repository. [Download the JARs here][8] o dev.cel cel - 0.7.1 + 0.8.0 ``` **Gradle** ```gradle -implementation 'dev.cel:cel:0.7.1' +implementation 'dev.cel:cel:0.8.0' ``` Then run this example: diff --git a/publish/cel_version.bzl b/publish/cel_version.bzl index c232b03b8..b92d340ca 100644 --- a/publish/cel_version.bzl +++ b/publish/cel_version.bzl @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. """Maven artifact version for CEL.""" -CEL_VERSION = "0.7.1" +CEL_VERSION = "0.8.0" From c31bc896ddb8a29e8a8d47291a46c977dbdd6af0 Mon Sep 17 00:00:00 2001 From: CEL Dev Team Date: Thu, 10 Oct 2024 15:39:57 -0700 Subject: [PATCH 210/486] Add description field to CelPolicy.Variable. PiperOrigin-RevId: 684602440 --- .../src/main/java/dev/cel/policy/CelPolicy.java | 6 ++++++ .../java/dev/cel/policy/CelPolicyYamlParser.java | 3 +++ .../dev/cel/policy/CelPolicyYamlParserTest.java | 16 ++++++++++++++++ 3 files changed, 25 insertions(+) diff --git a/policy/src/main/java/dev/cel/policy/CelPolicy.java b/policy/src/main/java/dev/cel/policy/CelPolicy.java index 33940c692..21bf53b7d 100644 --- a/policy/src/main/java/dev/cel/policy/CelPolicy.java +++ b/policy/src/main/java/dev/cel/policy/CelPolicy.java @@ -231,6 +231,8 @@ public abstract static class Variable { public abstract ValueString expression(); + public abstract Optional description(); + /** Builder for {@link Variable}. */ @AutoValue.Builder public abstract static class Builder implements RequiredFieldsChecker { @@ -239,10 +241,14 @@ public abstract static class Builder implements RequiredFieldsChecker { abstract Optional expression(); + abstract Optional description(); + public abstract Builder setName(ValueString name); public abstract Builder setExpression(ValueString expression); + public abstract Builder setDescription(ValueString description); + @Override public ImmutableList requiredFields() { return ImmutableList.of( diff --git a/policy/src/main/java/dev/cel/policy/CelPolicyYamlParser.java b/policy/src/main/java/dev/cel/policy/CelPolicyYamlParser.java index 5e527e73f..3eb8cdbf0 100644 --- a/policy/src/main/java/dev/cel/policy/CelPolicyYamlParser.java +++ b/policy/src/main/java/dev/cel/policy/CelPolicyYamlParser.java @@ -287,6 +287,9 @@ public CelPolicy.Variable parseVariable( case "expression": builder.setExpression(ctx.newValueString(valueNode)); break; + case "description": + builder.setDescription(ctx.newValueString(valueNode)); + break; default: tagVisitor.visitVariableTag(ctx, keyId, keyName, valueNode, policyBuilder, builder); break; diff --git a/policy/src/test/java/dev/cel/policy/CelPolicyYamlParserTest.java b/policy/src/test/java/dev/cel/policy/CelPolicyYamlParserTest.java index a62b7255e..90f6da0eb 100644 --- a/policy/src/test/java/dev/cel/policy/CelPolicyYamlParserTest.java +++ b/policy/src/test/java/dev/cel/policy/CelPolicyYamlParserTest.java @@ -48,6 +48,22 @@ public void parser_setEmpty() throws Exception { assertThrows(CelPolicyValidationException.class, () -> POLICY_PARSER.parse("", "")); } + @Test + public void parseYamlPolicy_withDescription() throws Exception { + String policySource = + "rule:\n" + + " variables:\n" + + " - name: 'variable_with_description'\n" + + " description: 'this is a description of the variable'\n" + + " expression: 'true'"; + + CelPolicy policy = POLICY_PARSER.parse(policySource); + + assertThat(policy.rule().variables()).hasSize(1); + assertThat(Iterables.getOnlyElement(policy.rule().variables()).description()) + .hasValue(ValueString.of(10, "this is a description of the variable")); + } + @Test public void parseYamlPolicy_withExplanation() throws Exception { String policySource = From abf857f1ffe05c8fb2e6b82e6c7a76c33df7afaf Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Fri, 11 Oct 2024 14:48:14 -0700 Subject: [PATCH 211/486] Move evaluateExpr utility methods to validator and optimizer PiperOrigin-RevId: 684961932 --- common/ast/BUILD.bazel | 5 -- .../main/java/dev/cel/common/ast/BUILD.bazel | 16 ----- .../java/dev/cel/common/ast/CelExprUtil.java | 71 ------------------- .../dev/cel/optimizer/optimizers/BUILD.bazel | 1 - .../optimizers/ConstantFoldingOptimizer.java | 15 +++- .../dev/cel/validator/validators/BUILD.bazel | 5 +- .../validators/LiteralValidator.java | 25 ++++++- 7 files changed, 40 insertions(+), 98 deletions(-) delete mode 100644 common/src/main/java/dev/cel/common/ast/CelExprUtil.java diff --git a/common/ast/BUILD.bazel b/common/ast/BUILD.bazel index 0a27ae0bc..c4e2455d5 100644 --- a/common/ast/BUILD.bazel +++ b/common/ast/BUILD.bazel @@ -30,11 +30,6 @@ java_library( exports = ["//common/src/main/java/dev/cel/common/ast:expr_factory"], ) -java_library( - name = "expr_util", - exports = ["//common/src/main/java/dev/cel/common/ast:expr_util"], -) - java_library( name = "mutable_expr", exports = ["//common/src/main/java/dev/cel/common/ast:mutable_expr"], diff --git a/common/src/main/java/dev/cel/common/ast/BUILD.bazel b/common/src/main/java/dev/cel/common/ast/BUILD.bazel index a5736cff9..a30f144e6 100644 --- a/common/src/main/java/dev/cel/common/ast/BUILD.bazel +++ b/common/src/main/java/dev/cel/common/ast/BUILD.bazel @@ -103,22 +103,6 @@ java_library( ], ) -java_library( - name = "expr_util", - srcs = ["CelExprUtil.java"], - tags = [ - ], - deps = [ - ":ast", - "//bundle:cel", - "//common", - "//common:compiler_common", - "//runtime", - "@maven//:com_google_errorprone_error_prone_annotations", - "@maven//:com_google_guava_guava", - ], -) - java_library( name = "mutable_expr", srcs = MUTABLE_EXPR_SOURCES, diff --git a/common/src/main/java/dev/cel/common/ast/CelExprUtil.java b/common/src/main/java/dev/cel/common/ast/CelExprUtil.java deleted file mode 100644 index 20217128e..000000000 --- a/common/src/main/java/dev/cel/common/ast/CelExprUtil.java +++ /dev/null @@ -1,71 +0,0 @@ -// 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.common.ast; - -import com.google.errorprone.annotations.CanIgnoreReturnValue; -import dev.cel.bundle.Cel; -import dev.cel.common.CelAbstractSyntaxTree; -import dev.cel.common.CelSource; -import dev.cel.common.CelValidationException; -import dev.cel.runtime.CelEvaluationException; - -/** Utility class for working with CelExpr. */ -public final class CelExprUtil { - - /** - * Type-checks and evaluates a CelExpr. This method should be used in the context of validating or - * optimizing an AST. - * - * @return Evaluated result. - * @throws CelValidationException if CelExpr fails to type-check. - * @throws CelEvaluationException if CelExpr fails to evaluate. - */ - @CanIgnoreReturnValue - public static Object evaluateExpr(Cel cel, CelExpr expr) - throws CelValidationException, CelEvaluationException { - CelAbstractSyntaxTree ast = - CelAbstractSyntaxTree.newParsedAst(expr, CelSource.newBuilder().build()); - ast = cel.check(ast).getAst(); - - return cel.createProgram(ast).eval(); - } - - /** - * Type-checks and evaluates a CelExpr. The evaluated result is then checked to see if it's the - * expected result type. - * - *

This method should be used in the context of validating or optimizing an AST. - * - * @return Evaluated result. - * @throws CelValidationException if CelExpr fails to type-check. - * @throws CelEvaluationException if CelExpr fails to evaluate. - * @throws IllegalStateException if the evaluated result is not of type {@code - * expectedResultType}. - */ - @CanIgnoreReturnValue - public static Object evaluateExpr(Cel cel, CelExpr expr, Class expectedResultType) - throws CelValidationException, CelEvaluationException { - Object result = evaluateExpr(cel, expr); - if (!expectedResultType.isInstance(result)) { - throw new IllegalStateException( - String.format( - "Expected %s type but got %s instead", - expectedResultType.getName(), result.getClass().getName())); - } - return result; - } - - private CelExprUtil() {} -} diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel b/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel index 396925ef7..fe1341a6c 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel @@ -23,7 +23,6 @@ java_library( "//common:compiler_common", "//common:mutable_ast", "//common/ast", - "//common/ast:expr_util", "//common/ast:mutable_expr", "//common/navigation:mutable_navigation", "//extensions:optional_library", diff --git a/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java b/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java index 7cf1ce1c3..dd5a3c211 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizer.java @@ -24,10 +24,11 @@ import dev.cel.bundle.Cel; import dev.cel.common.CelAbstractSyntaxTree; import dev.cel.common.CelMutableAst; +import dev.cel.common.CelSource; import dev.cel.common.CelValidationException; import dev.cel.common.ast.CelConstant; +import dev.cel.common.ast.CelExpr; import dev.cel.common.ast.CelExpr.ExprKind.Kind; -import dev.cel.common.ast.CelExprUtil; import dev.cel.common.ast.CelMutableExpr; import dev.cel.common.ast.CelMutableExpr.CelMutableCall; import dev.cel.common.ast.CelMutableExpr.CelMutableList; @@ -248,7 +249,7 @@ private Optional maybeFold( throws CelOptimizationException { Object result; try { - result = CelExprUtil.evaluateExpr(cel, CelMutableExprConverter.fromMutableExpr(node.expr())); + result = evaluateExpr(cel, CelMutableExprConverter.fromMutableExpr(node.expr())); } catch (CelValidationException | CelEvaluationException e) { throw new CelOptimizationException( "Constant folding failure. Failed to evaluate subtree due to: " + e.getMessage(), e); @@ -591,6 +592,16 @@ private CelMutableAst pruneOptionalStructElements(CelMutableAst ast, CelMutableE return ast; } + @CanIgnoreReturnValue + private static Object evaluateExpr(Cel cel, CelExpr expr) + throws CelValidationException, CelEvaluationException { + CelAbstractSyntaxTree ast = + CelAbstractSyntaxTree.newParsedAst(expr, CelSource.newBuilder().build()); + ast = cel.check(ast).getAst(); + + return cel.createProgram(ast).eval(); + } + /** Options to configure how Constant Folding behave. */ @AutoValue public abstract static class ConstantFoldingOptions { diff --git a/validator/src/main/java/dev/cel/validator/validators/BUILD.bazel b/validator/src/main/java/dev/cel/validator/validators/BUILD.bazel index 37868fa3a..7986fd014 100644 --- a/validator/src/main/java/dev/cel/validator/validators/BUILD.bazel +++ b/validator/src/main/java/dev/cel/validator/validators/BUILD.bazel @@ -94,10 +94,13 @@ java_library( visibility = ["//visibility:private"], deps = [ "//bundle:cel", + "//common", + "//common:compiler_common", "//common/ast", "//common/ast:expr_factory", - "//common/ast:expr_util", "//common/navigation", + "//runtime", "//validator:ast_validator", + "@maven//:com_google_errorprone_error_prone_annotations", ], ) diff --git a/validator/src/main/java/dev/cel/validator/validators/LiteralValidator.java b/validator/src/main/java/dev/cel/validator/validators/LiteralValidator.java index 0848870cc..2f23dab4c 100644 --- a/validator/src/main/java/dev/cel/validator/validators/LiteralValidator.java +++ b/validator/src/main/java/dev/cel/validator/validators/LiteralValidator.java @@ -14,13 +14,17 @@ package dev.cel.validator.validators; +import com.google.errorprone.annotations.CanIgnoreReturnValue; import dev.cel.bundle.Cel; +import dev.cel.common.CelAbstractSyntaxTree; +import dev.cel.common.CelSource; +import dev.cel.common.CelValidationException; import dev.cel.common.ast.CelExpr; import dev.cel.common.ast.CelExpr.ExprKind.Kind; import dev.cel.common.ast.CelExprFactory; -import dev.cel.common.ast.CelExprUtil; import dev.cel.common.navigation.CelNavigableAst; import dev.cel.common.navigation.CelNavigableExpr; +import dev.cel.runtime.CelEvaluationException; import dev.cel.validator.CelAstValidator; /** @@ -57,7 +61,7 @@ public void validate(CelNavigableAst navigableAst, Cel cel, IssuesFactory issues CelExpr callExpr = exprFactory.newGlobalCall(functionName, exprFactory.newConstant(expr.constant())); try { - CelExprUtil.evaluateExpr(cel, callExpr, expectedResultType); + evaluateExpr(cel, callExpr, expectedResultType); } catch (Exception e) { issuesFactory.addError( expr.id(), @@ -66,4 +70,21 @@ public void validate(CelNavigableAst navigableAst, Cel cel, IssuesFactory issues } }); } + + @CanIgnoreReturnValue + private static Object evaluateExpr(Cel cel, CelExpr expr, Class expectedResultType) + throws CelValidationException, CelEvaluationException { + CelAbstractSyntaxTree ast = + CelAbstractSyntaxTree.newParsedAst(expr, CelSource.newBuilder().build()); + ast = cel.check(ast).getAst(); + Object result = cel.createProgram(ast).eval(); + + if (!expectedResultType.isInstance(result)) { + throw new IllegalStateException( + String.format( + "Expected %s type but got %s instead", + expectedResultType.getName(), result.getClass().getName())); + } + return result; + } } From 1021e70ec2a64be1a17f8c01ae098334634e2103 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Sun, 13 Oct 2024 23:11:52 -0700 Subject: [PATCH 212/486] Cleanup of unused methods and build targets PiperOrigin-RevId: 685583668 --- runtime/BUILD.bazel | 12 ------- .../dev/cel/runtime/DefaultDispatcher.java | 33 ------------------- 2 files changed, 45 deletions(-) diff --git a/runtime/BUILD.bazel b/runtime/BUILD.bazel index 8c0c72a6a..3635c0961 100644 --- a/runtime/BUILD.bazel +++ b/runtime/BUILD.bazel @@ -10,12 +10,6 @@ java_library( exports = ["//runtime/src/main/java/dev/cel/runtime"], ) -java_library( - name = "base", - visibility = ["//visibility:public"], - exports = ["//runtime/src/main/java/dev/cel/runtime:base"], -) - java_library( name = "interpreter", visibility = ["//visibility:public"], @@ -47,9 +41,3 @@ java_library( name = "evaluation_listener", exports = ["//runtime/src/main/java/dev/cel/runtime:evaluation_listener"], ) - -java_library( - name = "runtime_type_provider_legacy", - visibility = ["//visibility:public"], - exports = ["//runtime/src/main/java/dev/cel/runtime:runtime_type_provider_legacy"], -) diff --git a/runtime/src/main/java/dev/cel/runtime/DefaultDispatcher.java b/runtime/src/main/java/dev/cel/runtime/DefaultDispatcher.java index cfc16bee7..bc20a8a0b 100644 --- a/runtime/src/main/java/dev/cel/runtime/DefaultDispatcher.java +++ b/runtime/src/main/java/dev/cel/runtime/DefaultDispatcher.java @@ -17,16 +17,13 @@ import com.google.common.base.Joiner; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; import com.google.errorprone.annotations.Immutable; import javax.annotation.concurrent.ThreadSafe; import com.google.errorprone.annotations.concurrent.GuardedBy; import com.google.protobuf.MessageLite; import dev.cel.common.CelErrorCode; import dev.cel.common.CelOptions; -import dev.cel.common.ExprFeatures; import dev.cel.common.annotations.Internal; -import dev.cel.common.internal.DefaultMessageFactory; import dev.cel.common.internal.DynamicProto; import java.util.ArrayList; import java.util.HashMap; @@ -43,36 +40,6 @@ @ThreadSafe @Internal public final class DefaultDispatcher implements Dispatcher, Registrar { - /** - * Creates a new dispatcher with all standard functions. - * - * @deprecated Migrate to fluent APIs. See {@link CelRuntimeFactory}. - */ - @Deprecated - public static DefaultDispatcher create() { - return create(CelOptions.LEGACY); - } - - /** - * Creates a new dispatcher with all standard functions. - * - * @deprecated Migrate to fluent APIs. See {@link CelRuntimeFactory}. - */ - @Deprecated - public static DefaultDispatcher create(ImmutableSet features) { - return create(CelOptions.fromExprFeatures(features)); - } - - /** - * Creates a new dispatcher with all standard functions. - * - * @deprecated Migrate to fluent APIs. See {@link CelRuntimeFactory}. - */ - @Deprecated - public static DefaultDispatcher create(CelOptions celOptions) { - DynamicProto dynamicProto = DynamicProto.create(DefaultMessageFactory.INSTANCE); - return create(celOptions, dynamicProto, true); - } public static DefaultDispatcher create( CelOptions celOptions, DynamicProto dynamicProto, boolean enableStandardEnvironment) { From 6dc2f16866f8d20c284ae87997903b21041e1e2a Mon Sep 17 00:00:00 2001 From: Jonathan Tatum Date: Tue, 15 Oct 2024 12:18:59 -0700 Subject: [PATCH 213/486] Update baseline tests for java checker: - use unique overload_ids - fix file with typo PiperOrigin-RevId: 686195856 --- .../java/dev/cel/checker/ExprCheckerTest.java | 18 +++++++++--------- .../abstractTypeParameterized.baseline | 14 +++++++------- .../abstractTypeParameterizedError.baseline | 6 +++--- ...ractTypeParameterizedInListLiteral.baseline | 8 ++++---- .../resources/jsonStructTypeError.baseline | 2 +- 5 files changed, 24 insertions(+), 24 deletions(-) diff --git a/checker/src/test/java/dev/cel/checker/ExprCheckerTest.java b/checker/src/test/java/dev/cel/checker/ExprCheckerTest.java index c232441fc..29ad5146d 100644 --- a/checker/src/test/java/dev/cel/checker/ExprCheckerTest.java +++ b/checker/src/test/java/dev/cel/checker/ExprCheckerTest.java @@ -805,13 +805,13 @@ public void abstractTypeParameterized() throws Exception { "vector", // Declare the function 'vector' to create the abstract type. globalOverload( - "vector", + "vector_type", ImmutableList.of(CelTypes.create(typeParam)), ImmutableList.of("T"), CelTypes.create(abstractType)), // Declare a function to create a new value of abstract type based on a list. globalOverload( - "vector", + "vector_list", ImmutableList.of(createList(typeParam)), ImmutableList.of("T"), abstractType)); @@ -820,7 +820,7 @@ public void abstractTypeParameterized() throws Exception { declareFunction( "at", memberOverload( - "at", + "vector_at_int", ImmutableList.of(abstractType, CelTypes.INT64), ImmutableList.of("T"), typeParam)); @@ -843,13 +843,13 @@ public void abstractTypeParameterizedInListLiteral() throws Exception { "vector", // Declare the function 'vector' to create the abstract type. globalOverload( - "vector", + "vector_type", ImmutableList.of(CelTypes.create(typeParam)), ImmutableList.of("T"), CelTypes.create(abstractType)), // Declare a function to create a new value of abstract type based on a list. globalOverload( - "vector", + "vector_list", ImmutableList.of(createList(typeParam)), ImmutableList.of("T"), abstractType)); @@ -870,23 +870,23 @@ public void abstractTypeParameterizedError() throws Exception { "vector", // Declare the function 'vector' to create the abstract type. globalOverload( - "vector", + "vector_type", ImmutableList.of(CelTypes.create(typeParam)), ImmutableList.of("T"), CelTypes.create(abstractType)), // Declare a function to create a new value of abstract type based on a list. globalOverload( - "vector", + "vector_list", ImmutableList.of(createList(typeParam)), ImmutableList.of("T"), abstractType)); declareFunction( "add", globalOverload( - "add", + "add_vector_type", ImmutableList.of(CelTypes.create(abstractType), CelTypes.create(abstractType)), ImmutableList.of("T"), - abstractType)); + CelTypes.create(abstractType))); source = "add(vector([1, 2]), vector([2u, -1])) == vector([1, 2, 2u, -1])"; runTest(); } diff --git a/checker/src/test/resources/abstractTypeParameterized.baseline b/checker/src/test/resources/abstractTypeParameterized.baseline index 948f61ec9..28cc0000a 100644 --- a/checker/src/test/resources/abstractTypeParameterized.baseline +++ b/checker/src/test/resources/abstractTypeParameterized.baseline @@ -1,10 +1,10 @@ Source: type(vector([1])) == vector(dyn) && vector([1]).at(0) == 1 declare vector { - function vector (type(T)) -> type(vector(T)) - function vector (list(T)) -> vector(T) + function vector_type (type(T)) -> type(vector(T)) + function vector_list (list(T)) -> vector(T) } declare at { - function at vector(T).(int) -> T + function vector_at_int vector(T).(int) -> T } =====> _&&_( @@ -14,20 +14,20 @@ _&&_( [ 1~int ]~list(int) - )~vector(int)^vector + )~vector(int)^vector_list )~type(vector(int))^type, vector( dyn~type(dyn)^dyn - )~type(vector(dyn))^vector + )~type(vector(dyn))^vector_type )~bool^equals, _==_( vector( [ 1~int ]~list(int) - )~vector(int)^vector.at( + )~vector(int)^vector_list.at( 0~int - )~int^at, + )~int^vector_at_int, 1~int )~bool^equals )~bool^logical_and diff --git a/checker/src/test/resources/abstractTypeParameterizedError.baseline b/checker/src/test/resources/abstractTypeParameterizedError.baseline index 140202ab1..8ef50993e 100644 --- a/checker/src/test/resources/abstractTypeParameterizedError.baseline +++ b/checker/src/test/resources/abstractTypeParameterizedError.baseline @@ -1,10 +1,10 @@ Source: add(vector([1, 2]), vector([2u, -1])) == vector([1, 2, 2u, -1]) declare vector { - function vector (type(T)) -> type(vector(T)) - function vector (list(T)) -> vector(T) + function vector_type (type(T)) -> type(vector(T)) + function vector_list (list(T)) -> vector(T) } declare add { - function add (type(vector(T)), type(vector(T))) -> vector(T) + function add_vector_type (type(vector(T)), type(vector(T))) -> type(vector(T)) } =====> ERROR: test_location:1:4: found no matching overload for 'add' applied to '(vector(int), vector(dyn))' (candidates: (type(vector(%T4)), type(vector(%T4)))) diff --git a/checker/src/test/resources/abstractTypeParameterizedInListLiteral.baseline b/checker/src/test/resources/abstractTypeParameterizedInListLiteral.baseline index e07a05598..3425e0325 100644 --- a/checker/src/test/resources/abstractTypeParameterizedInListLiteral.baseline +++ b/checker/src/test/resources/abstractTypeParameterizedInListLiteral.baseline @@ -1,7 +1,7 @@ Source: size([vector([1, 2]), vector([2u, -1])]) == 2 declare vector { - function vector (type(T)) -> type(vector(T)) - function vector (list(T)) -> vector(T) + function vector_type (type(T)) -> type(vector(T)) + function vector_list (list(T)) -> vector(T) } =====> _==_( @@ -12,13 +12,13 @@ _==_( 1~int, 2~int ]~list(int) - )~vector(int)^vector, + )~vector(int)^vector_list, vector( [ 2u~uint, -1~int ]~list(dyn) - )~vector(dyn)^vector + )~vector(dyn)^vector_list ]~list(vector(dyn)) )~int^size_list, 2~int diff --git a/checker/src/test/resources/jsonStructTypeError.baseline b/checker/src/test/resources/jsonStructTypeError.baseline index 83d6bd717..f13507a0d 100644 --- a/checker/src/test/resources/jsonStructTypeError.baseline +++ b/checker/src/test/resources/jsonStructTypeError.baseline @@ -1,4 +1,4 @@ -ource: x["iss"] != TestAllTypes{single_int32: 1} +Source: x["iss"] != TestAllTypes{single_int32: 1} declare x { value google.protobuf.Struct } From 027241155158a519404419002ed221eb96ff1727 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Wed, 16 Oct 2024 01:41:26 -0700 Subject: [PATCH 214/486] Add expr ID set as a field to CelUnknownSet. This serves as a native-type representation for unknown values, intended to replace ExprValue from eval.proto. PiperOrigin-RevId: 686415221 --- .../test/java/dev/cel/bundle/CelImplTest.java | 34 ++++++++++ .../main/java/dev/cel/common/CelOptions.java | 13 ++++ .../src/main/java/dev/cel/runtime/BUILD.bazel | 2 + .../dev/cel/runtime/CallArgumentChecker.java | 25 ++++++-- .../java/dev/cel/runtime/CelUnknownSet.java | 31 ++++++++- .../dev/cel/runtime/DefaultInterpreter.java | 16 +++-- .../java/dev/cel/runtime/InterpreterUtil.java | 64 +++++++++++++------ .../cel/runtime/RuntimeUnknownResolver.java | 35 +++++++--- 8 files changed, 174 insertions(+), 46 deletions(-) diff --git a/bundle/src/test/java/dev/cel/bundle/CelImplTest.java b/bundle/src/test/java/dev/cel/bundle/CelImplTest.java index db8f311e9..38d1c2218 100644 --- a/bundle/src/test/java/dev/cel/bundle/CelImplTest.java +++ b/bundle/src/test/java/dev/cel/bundle/CelImplTest.java @@ -1926,6 +1926,40 @@ public void program_functionParamWithWellKnownType() throws Exception { assertThat(result).isTrue(); } + @Test + public void program_nativeTypeUnknownsEnabled_asIdentifiers() throws Exception { + Cel cel = + CelFactory.standardCelBuilder() + .addVar("x", SimpleType.BOOL) + .addVar("y", SimpleType.BOOL) + .setOptions(CelOptions.current().adaptUnknownValueSetToNativeType(true).build()) + .build(); + CelAbstractSyntaxTree ast = cel.compile("x || y").getAst(); + + CelUnknownSet result = (CelUnknownSet) cel.createProgram(ast).eval(); + + assertThat(result.unknownExprIds()).containsExactly(1L, 3L); + assertThat(result.attributes()).isEmpty(); + } + + @Test + public void program_nativeTypeUnknownsEnabled_asCallArguments() throws Exception { + Cel cel = + CelFactory.standardCelBuilder() + .addVar("x", SimpleType.BOOL) + .addFunctionDeclarations( + newFunctionDeclaration( + "foo", newGlobalOverload("foo_bool", SimpleType.BOOL, SimpleType.BOOL))) + .setOptions(CelOptions.current().adaptUnknownValueSetToNativeType(true).build()) + .build(); + CelAbstractSyntaxTree ast = cel.compile("foo(x)").getAst(); + + CelUnknownSet result = (CelUnknownSet) cel.createProgram(ast).eval(); + + assertThat(result.unknownExprIds()).containsExactly(2L); + assertThat(result.attributes()).isEmpty(); + } + @Test public void toBuilder_isImmutable() { CelBuilder celBuilder = CelFactory.standardCelBuilder(); diff --git a/common/src/main/java/dev/cel/common/CelOptions.java b/common/src/main/java/dev/cel/common/CelOptions.java index 2568099fb..7f7cd7328 100644 --- a/common/src/main/java/dev/cel/common/CelOptions.java +++ b/common/src/main/java/dev/cel/common/CelOptions.java @@ -109,6 +109,8 @@ public enum ProtoUnsetFieldOptions { public abstract ProtoUnsetFieldOptions fromProtoUnsetFieldOption(); + public abstract boolean adaptUnknownValueSetToNativeType(); + public abstract Builder toBuilder(); public ImmutableSet toExprFeatures() { @@ -200,6 +202,7 @@ public static Builder newBuilder() { .enableCelValue(false) .comprehensionMaxIterations(-1) .unwrapWellKnownTypesOnFunctionDispatch(true) + .adaptUnknownValueSetToNativeType(false) .fromProtoUnsetFieldOption(ProtoUnsetFieldOptions.BIND_DEFAULT); } @@ -504,6 +507,16 @@ public abstract static class Builder { */ public abstract Builder fromProtoUnsetFieldOption(ProtoUnsetFieldOptions value); + /** + * If enabled, when the result of an evaluation is a set of unknown values, a native-type + * equivalent {@code CelUnknownSet} is returned as a result. Otherwise, ExprValue from {@code + * eval.proto} is returned instead. + * + *

This is a temporary flag. It will be removed once the consumers have migrated to the + * native-type representation. + */ + public abstract Builder adaptUnknownValueSetToNativeType(boolean value); + public abstract CelOptions build(); } } diff --git a/runtime/src/main/java/dev/cel/runtime/BUILD.bazel b/runtime/src/main/java/dev/cel/runtime/BUILD.bazel index e74420b74..095f69565 100644 --- a/runtime/src/main/java/dev/cel/runtime/BUILD.bazel +++ b/runtime/src/main/java/dev/cel/runtime/BUILD.bazel @@ -19,6 +19,7 @@ BASE_SOURCES = [ "TypeResolver.java", ] +# keep sorted INTERPRETER_SOURCES = [ "Activation.java", "CallArgumentChecker.java", @@ -249,6 +250,7 @@ java_library( ], deps = [ ":base", + ":unknown_attributes", "//common/annotations", "@cel_spec//proto/cel/expr:expr_java_proto", "@maven//:com_google_errorprone_error_prone_annotations", diff --git a/runtime/src/main/java/dev/cel/runtime/CallArgumentChecker.java b/runtime/src/main/java/dev/cel/runtime/CallArgumentChecker.java index a3bd6e4b7..74894a213 100644 --- a/runtime/src/main/java/dev/cel/runtime/CallArgumentChecker.java +++ b/runtime/src/main/java/dev/cel/runtime/CallArgumentChecker.java @@ -32,13 +32,13 @@ @Internal class CallArgumentChecker { private final ArrayList exprIds; - private Optional unknowns; private final RuntimeUnknownResolver resolver; private final boolean acceptPartial; + private Optional unknowns; private CallArgumentChecker(RuntimeUnknownResolver resolver, boolean acceptPartial) { - exprIds = new ArrayList<>(); - unknowns = Optional.empty(); + this.exprIds = new ArrayList<>(); + this.unknowns = Optional.empty(); this.resolver = resolver; this.acceptPartial = acceptPartial; } @@ -76,8 +76,13 @@ void checkArg(DefaultInterpreter.IntermediateResult arg) { // support for ExprValue unknowns. if (InterpreterUtil.isUnknown(arg.value())) { - ExprValue exprValue = (ExprValue) arg.value(); - exprIds.addAll(exprValue.getUnknown().getExprsList()); + if (InterpreterUtil.isExprValueUnknown(arg.value())) { + ExprValue exprValue = (ExprValue) arg.value(); + exprIds.addAll(exprValue.getUnknown().getExprsList()); + } else if (resolver.getAdaptUnknownValueSetOption()) { + CelUnknownSet unknownSet = (CelUnknownSet) arg.value(); + exprIds.addAll(unknownSet.unknownExprIds()); + } } } @@ -98,8 +103,14 @@ Optional maybeUnknowns() { } if (!exprIds.isEmpty()) { - return Optional.of( - ExprValue.newBuilder().setUnknown(UnknownSet.newBuilder().addAllExprs(exprIds)).build()); + if (resolver.getAdaptUnknownValueSetOption()) { + return Optional.of(CelUnknownSet.create(exprIds)); + } else { + return Optional.of( + ExprValue.newBuilder() + .setUnknown(UnknownSet.newBuilder().addAllExprs(exprIds)) + .build()); + } } return Optional.empty(); diff --git a/runtime/src/main/java/dev/cel/runtime/CelUnknownSet.java b/runtime/src/main/java/dev/cel/runtime/CelUnknownSet.java index 8cde13361..e53d8be94 100644 --- a/runtime/src/main/java/dev/cel/runtime/CelUnknownSet.java +++ b/runtime/src/main/java/dev/cel/runtime/CelUnknownSet.java @@ -28,21 +28,46 @@ */ @AutoValue public abstract class CelUnknownSet { + + /** + * Set of attributes with a series of selection or index operations marked unknown. This set is + * always empty if enableUnknownTracking is disabled in {@code CelOptions}. + */ public abstract ImmutableSet attributes(); - public static CelUnknownSet create(ImmutableSet attributes) { - return new AutoValue_CelUnknownSet(attributes); - } + /** Set of subexpression IDs that were decided to be unknown and in the critical path. */ + public abstract ImmutableSet unknownExprIds(); public static CelUnknownSet create(CelAttribute attribute) { return create(ImmutableSet.of(attribute)); } + public static CelUnknownSet create(ImmutableSet attributes) { + return create(attributes, ImmutableSet.of()); + } + + static CelUnknownSet create(Long... unknownExprIds) { + return create(ImmutableSet.copyOf(unknownExprIds)); + } + + static CelUnknownSet create(Iterable unknownExprIds) { + return create(ImmutableSet.of(), ImmutableSet.copyOf(unknownExprIds)); + } + + private static CelUnknownSet create( + ImmutableSet attributes, ImmutableSet unknownExprIds) { + return new AutoValue_CelUnknownSet(attributes, unknownExprIds); + } + public static CelUnknownSet union(CelUnknownSet lhs, CelUnknownSet rhs) { return create( ImmutableSet.builder() .addAll(lhs.attributes()) .addAll(rhs.attributes()) + .build(), + ImmutableSet.builder() + .addAll(lhs.unknownExprIds()) + .addAll(rhs.unknownExprIds()) .build()); } diff --git a/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java b/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java index babec5dda..dc633e1a9 100644 --- a/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java +++ b/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java @@ -108,10 +108,6 @@ static IntermediateResult create(Object value) { } } - public DefaultInterpreter(RuntimeTypeProvider typeProvider, Dispatcher dispatcher) { - this(typeProvider, dispatcher, CelOptions.LEGACY); - } - /** * Creates a new interpreter * @@ -167,7 +163,10 @@ public Object eval(GlobalResolver resolver) throws InterpreterException { @Override public Object eval(GlobalResolver resolver, CelEvaluationListener listener) throws InterpreterException { - return evalTrackingUnknowns(RuntimeUnknownResolver.fromResolver(resolver), listener); + return evalTrackingUnknowns( + RuntimeUnknownResolver.fromResolver( + resolver, celOptions.adaptUnknownValueSetToNativeType()), + listener); } @Override @@ -333,7 +332,9 @@ private IntermediateResult evalFieldSelect( Object fieldValue = typeProvider.selectField(operand, field); return IntermediateResult.create( - attribute, InterpreterUtil.valueOrUnknown(fieldValue, expr.id())); + attribute, + InterpreterUtil.valueOrUnknown( + fieldValue, expr.id(), celOptions.adaptUnknownValueSetToNativeType())); } private IntermediateResult evalCall(ExecutionFrame frame, CelExpr expr, CelCall callExpr) @@ -486,7 +487,8 @@ private IntermediateResult mergeBooleanUnknowns(IntermediateResult lhs, Intermed // Otherwise fallback to normal impl return IntermediateResult.create( - InterpreterUtil.shortcircuitUnknownOrThrowable(lhs.value(), rhs.value())); + InterpreterUtil.shortcircuitUnknownOrThrowable( + lhs.value(), rhs.value(), celOptions.adaptUnknownValueSetToNativeType())); } private enum ShortCircuitableOperators { diff --git a/runtime/src/main/java/dev/cel/runtime/InterpreterUtil.java b/runtime/src/main/java/dev/cel/runtime/InterpreterUtil.java index 7f2808c0e..7c6a90468 100644 --- a/runtime/src/main/java/dev/cel/runtime/InterpreterUtil.java +++ b/runtime/src/main/java/dev/cel/runtime/InterpreterUtil.java @@ -17,9 +17,7 @@ import dev.cel.expr.ExprValue; import dev.cel.expr.UnknownSet; import dev.cel.common.annotations.Internal; -import java.util.Arrays; import java.util.LinkedHashSet; -import java.util.List; import java.util.Set; import org.jspecify.annotations.Nullable; @@ -56,8 +54,19 @@ public static Object strict(Object valueOrThrowable) throws InterpreterException * @return boolean value if object is unknown. */ public static boolean isUnknown(Object obj) { - return obj instanceof ExprValue - && ((ExprValue) obj).getKindCase() == ExprValue.KindCase.UNKNOWN; + if (isExprValueUnknown(obj)) { + return true; + } + return obj instanceof CelUnknownSet; + } + + /** TODO: Remove once clients have been migrated. */ + static boolean isExprValueUnknown(Object obj) { + if (obj instanceof ExprValue) { + return ((ExprValue) obj).getKindCase() == ExprValue.KindCase.UNKNOWN; + } + + return false; } /** @@ -67,7 +76,7 @@ public static boolean isUnknown(Object obj) { * @return A new ExprValue object which has all unknown expr ids from input objects, without * duplication. */ - public static ExprValue combineUnknownExprValue(Object... objs) { + static ExprValue combineUnknownProtoExprValue(Object... objs) { UnknownSet.Builder unknownsetBuilder = UnknownSet.newBuilder(); Set ids = new LinkedHashSet<>(); for (Object object : objs) { @@ -79,21 +88,25 @@ public static ExprValue combineUnknownExprValue(Object... objs) { return ExprValue.newBuilder().setUnknown(unknownsetBuilder).build(); } - /** Create a {@code ExprValue} for one or more {@code ids} representing an unknown set. */ - public static ExprValue createUnknownExprValue(Long... ids) { - return createUnknownExprValue(Arrays.asList(ids)); + static CelUnknownSet combineUnknownExprValue(Object... objs) { + Set ids = new LinkedHashSet<>(); + for (Object object : objs) { + if (isUnknown(object)) { + ids.addAll(((CelUnknownSet) object).unknownExprIds()); + } + } + + return CelUnknownSet.create(ids); } /** * Create an ExprValue object has UnknownSet, from a list of unknown expr ids * - * @param ids List of unknown expr ids + * @param id unknown expr id * @return A new ExprValue object which has all unknown expr ids from input list */ - public static ExprValue createUnknownExprValue(List ids) { - ExprValue.Builder exprValueBuilder = ExprValue.newBuilder(); - exprValueBuilder.setUnknown(UnknownSet.newBuilder().addAllExprs(ids)); - return exprValueBuilder.build(); + private static ExprValue createUnknownExprValue(long id) { + return ExprValue.newBuilder().setUnknown(UnknownSet.newBuilder().addExprs(id)).build(); } /** @@ -104,11 +117,14 @@ public static ExprValue createUnknownExprValue(List ids) { * from any boolean arguments alone. This allows us to consolidate the error/unknown handling for * both of these operators. */ - public static Object shortcircuitUnknownOrThrowable(Object left, Object right) + public static Object shortcircuitUnknownOrThrowable( + Object left, Object right, boolean adaptUnknownValueSetToNativeType) throws InterpreterException { // unknown unknown ==> unknown combined if (InterpreterUtil.isUnknown(left) && InterpreterUtil.isUnknown(right)) { - return InterpreterUtil.combineUnknownExprValue(left, right); + return adaptUnknownValueSetToNativeType + ? InterpreterUtil.combineUnknownExprValue(left, right) + : InterpreterUtil.combineUnknownProtoExprValue(left, right); } // unknown ==> unknown // unknown t|f ==> unknown @@ -132,18 +148,24 @@ public static Object shortcircuitUnknownOrThrowable(Object left, Object right) "Left or/and right object is neither bool, unknown nor error, unexpected behavior."); } - public static Object valueOrUnknown(@Nullable Object valueOrThrowable, Long id) { + public static Object valueOrUnknown( + @Nullable Object valueOrThrowable, Long id, boolean adaptUnknownValueSet) { // Handle the unknown value case. if (isUnknown(valueOrThrowable)) { - ExprValue value = (ExprValue) valueOrThrowable; - if (value.getUnknown().getExprsCount() != 0) { - return valueOrThrowable; + if (adaptUnknownValueSet) { + return CelUnknownSet.create(id); + } else { + // TODO: Remove once clients have been migrated. + ExprValue value = (ExprValue) valueOrThrowable; + if (value.getUnknown().getExprsCount() != 0) { + return valueOrThrowable; + } + return createUnknownExprValue(id); } - return createUnknownExprValue(id); } // Handle the null value case. if (valueOrThrowable == null) { - return createUnknownExprValue(id); + return adaptUnknownValueSet ? CelUnknownSet.create(id) : createUnknownExprValue(id); } return valueOrThrowable; } diff --git a/runtime/src/main/java/dev/cel/runtime/RuntimeUnknownResolver.java b/runtime/src/main/java/dev/cel/runtime/RuntimeUnknownResolver.java index 1c1be9b94..9a08dea10 100644 --- a/runtime/src/main/java/dev/cel/runtime/RuntimeUnknownResolver.java +++ b/runtime/src/main/java/dev/cel/runtime/RuntimeUnknownResolver.java @@ -40,20 +40,29 @@ public class RuntimeUnknownResolver { private final boolean attributeTrackingEnabled; + /** TODO: Remove after callers have been migrated */ + private final boolean adaptUnknownValueSet; + private RuntimeUnknownResolver( GlobalResolver resolver, CelAttributeResolver attributeResolver, - boolean attributeTrackingEnabled) { + boolean attributeTrackingEnabled, + boolean adaptUnknownValueSet) { this.resolver = resolver; this.attributeResolver = attributeResolver; this.attributeTrackingEnabled = attributeTrackingEnabled; + this.adaptUnknownValueSet = adaptUnknownValueSet; } - public static RuntimeUnknownResolver fromResolver(GlobalResolver resolver) { + public static RuntimeUnknownResolver fromResolver( + GlobalResolver resolver, boolean adaptUnknownValueSet) { // This prevents calculating the attribute trail if it will never be used for // efficiency, but doesn't change observable behavior. return new RuntimeUnknownResolver( - resolver, DEFAULT_RESOLVER, /* attributeTrackingEnabled= */ false) {}; + resolver, + DEFAULT_RESOLVER, + /* attributeTrackingEnabled= */ false, + /* adaptUnknownValueSet= */ adaptUnknownValueSet); } public static Builder builder() { @@ -83,7 +92,7 @@ public Builder setAttributeResolver(CelAttributeResolver resolver) { } public RuntimeUnknownResolver build() { - return new RuntimeUnknownResolver(resolver, attributeResolver, true); + return new RuntimeUnknownResolver(resolver, attributeResolver, true, false); } } @@ -111,7 +120,7 @@ DefaultInterpreter.IntermediateResult resolveSimpleName(String name, Long exprId Object result = resolver.resolve(name); return DefaultInterpreter.IntermediateResult.create( - attr, InterpreterUtil.valueOrUnknown(result, exprId)); + attr, InterpreterUtil.valueOrUnknown(result, exprId, adaptUnknownValueSet)); } void cacheLazilyEvaluatedResult(String name, DefaultInterpreter.IntermediateResult result) { @@ -127,7 +136,12 @@ Optional resolveAttribute(CelAttribute attr) { } ScopedResolver withScope(Map vars) { - return new ScopedResolver(this, vars); + return new ScopedResolver(this, vars, adaptUnknownValueSet); + } + + /** TODO: Remove after callers have been migrated */ + boolean getAdaptUnknownValueSetOption() { + return adaptUnknownValueSet; } static final class ScopedResolver extends RuntimeUnknownResolver { @@ -137,8 +151,13 @@ static final class ScopedResolver extends RuntimeUnknownResolver { private ScopedResolver( RuntimeUnknownResolver parent, - Map shadowedVars) { - super(parent.resolver, parent.attributeResolver, parent.attributeTrackingEnabled); + Map shadowedVars, + boolean adaptUnknownValueSet) { + super( + parent.resolver, + parent.attributeResolver, + parent.attributeTrackingEnabled, + adaptUnknownValueSet); this.parent = parent; this.shadowedVars = shadowedVars; this.lazyEvalResultCache = new HashMap<>(); From 7e6578c965733e09a8c8838397d35a31ada4816e Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Wed, 16 Oct 2024 09:50:10 -0700 Subject: [PATCH 215/486] Correctly suppress AutoValueMutable warnings PiperOrigin-RevId: 686542214 --- .../main/java/dev/cel/common/internal/BasicCodePointArray.java | 2 +- .../main/java/dev/cel/common/internal/Latin1CodePointArray.java | 2 +- .../dev/cel/common/internal/SupplementalCodePointArray.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/common/src/main/java/dev/cel/common/internal/BasicCodePointArray.java b/common/src/main/java/dev/cel/common/internal/BasicCodePointArray.java index a240df763..9f1bb5cb6 100644 --- a/common/src/main/java/dev/cel/common/internal/BasicCodePointArray.java +++ b/common/src/main/java/dev/cel/common/internal/BasicCodePointArray.java @@ -38,7 +38,7 @@ @SuppressWarnings("Immutable") // char[] is not exposed externally, thus cannot be mutated. public abstract class BasicCodePointArray extends CelCodePointArray { - @SuppressWarnings("AutoValueImmutableFields") + @SuppressWarnings("mutable") abstract char[] codePoints(); abstract int offset(); diff --git a/common/src/main/java/dev/cel/common/internal/Latin1CodePointArray.java b/common/src/main/java/dev/cel/common/internal/Latin1CodePointArray.java index 9e54c3a6c..d9536cbb4 100644 --- a/common/src/main/java/dev/cel/common/internal/Latin1CodePointArray.java +++ b/common/src/main/java/dev/cel/common/internal/Latin1CodePointArray.java @@ -38,7 +38,7 @@ @SuppressWarnings("Immutable") // byte[] is not exposed externally, thus cannot be mutated. public abstract class Latin1CodePointArray extends CelCodePointArray { - @SuppressWarnings("AutoValueImmutableFields") + @SuppressWarnings("mutable") abstract byte[] codePoints(); abstract int offset(); diff --git a/common/src/main/java/dev/cel/common/internal/SupplementalCodePointArray.java b/common/src/main/java/dev/cel/common/internal/SupplementalCodePointArray.java index dc3cb10a4..80e6c93d3 100644 --- a/common/src/main/java/dev/cel/common/internal/SupplementalCodePointArray.java +++ b/common/src/main/java/dev/cel/common/internal/SupplementalCodePointArray.java @@ -38,7 +38,7 @@ @SuppressWarnings("Immutable") // int[] is not exposed externally, thus cannot be mutated. public abstract class SupplementalCodePointArray extends CelCodePointArray { - @SuppressWarnings("AutoValueImmutableFields") + @SuppressWarnings("mutable") abstract int[] codePoints(); abstract int offset(); From ea78c86d69cbe1b467f90cdb3208b9ac1cfee705 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Wed, 16 Oct 2024 11:44:33 -0700 Subject: [PATCH 216/486] Enforce strictness of type function This ensures that: - type(unknown) -> unknown - type(error) -> error PiperOrigin-RevId: 686585884 --- .../java/dev/cel/runtime/CelUnknownSet.java | 2 +- .../dev/cel/runtime/DefaultInterpreter.java | 14 +++++++--- .../test/resources/unknownResultSet.baseline | 27 +++++++++++++++++++ .../dev/cel/testing/BaseInterpreterTest.java | 8 ++++++ 4 files changed, 46 insertions(+), 5 deletions(-) diff --git a/runtime/src/main/java/dev/cel/runtime/CelUnknownSet.java b/runtime/src/main/java/dev/cel/runtime/CelUnknownSet.java index e53d8be94..d05be8133 100644 --- a/runtime/src/main/java/dev/cel/runtime/CelUnknownSet.java +++ b/runtime/src/main/java/dev/cel/runtime/CelUnknownSet.java @@ -46,7 +46,7 @@ public static CelUnknownSet create(ImmutableSet attributes) { return create(attributes, ImmutableSet.of()); } - static CelUnknownSet create(Long... unknownExprIds) { + public static CelUnknownSet create(Long... unknownExprIds) { return create(ImmutableSet.copyOf(unknownExprIds)); } diff --git a/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java b/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java index dc633e1a9..a0dd1f242 100644 --- a/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java +++ b/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java @@ -222,10 +222,14 @@ private IntermediateResult evalInternal(ExecutionFrame frame, CelExpr expr) } } - private boolean isUnknownValue(Object value) { + private static boolean isUnknownValue(Object value) { return value instanceof CelUnknownSet || InterpreterUtil.isUnknown(value); } + private static boolean isUnknownOrError(Object value) { + return isUnknownValue(value) || value instanceof Exception; + } + private Object evalConstant( ExecutionFrame unusedFrame, CelExpr unusedExpr, CelConstant constExpr) { switch (constExpr.getKind()) { @@ -593,6 +597,10 @@ private IntermediateResult evalType(ExecutionFrame frame, CelCall callExpr) throws InterpreterException { CelExpr typeExprArg = callExpr.args().get(0); IntermediateResult argResult = evalInternal(frame, typeExprArg); + // Type is a strict function. Early return if the argument is an error or an unknown. + if (isUnknownOrError(argResult.value())) { + return argResult; + } CelType checkedType = ast.getType(typeExprArg.id()) @@ -682,9 +690,7 @@ private IntermediateResult evalBoolean(ExecutionFrame frame, CelExpr expr, boole throws InterpreterException { IntermediateResult value = strict ? evalInternal(frame, expr) : evalNonstrictly(frame, expr); - if (!(value.value() instanceof Boolean) - && !isUnknownValue(value.value()) - && !(value.value() instanceof Exception)) { + if (!(value.value() instanceof Boolean) && !isUnknownOrError(value.value())) { throw new InterpreterException.Builder("expected boolean value, found: %s", value.value()) .setErrorCode(CelErrorCode.INVALID_ARGUMENT) .setLocation(metadata, expr.id()) diff --git a/runtime/src/test/resources/unknownResultSet.baseline b/runtime/src/test/resources/unknownResultSet.baseline index 2b2c61f62..7cc661627 100644 --- a/runtime/src/test/resources/unknownResultSet.baseline +++ b/runtime/src/test/resources/unknownResultSet.baseline @@ -515,3 +515,30 @@ result: unknown { exprs: 3 exprs: 6 } + + +Source: type(x.single_int32) +declare x { + value google.api.expr.test.v1.proto3.TestAllTypes +} +declare f { + function f int.(int) -> bool +} +=====> +bindings: {} +result: unknown { + exprs: 2 +} + + +Source: type(1 / 0 > 2) +declare x { + value google.api.expr.test.v1.proto3.TestAllTypes +} +declare f { + function f int.(int) -> bool +} +=====> +bindings: {} +error: evaluation error: / by zero +error_code: DIVIDE_BY_ZERO diff --git a/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java b/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java index 68f343a19..17c3bb809 100644 --- a/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java +++ b/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java @@ -1298,6 +1298,14 @@ public void unknownResultSet() { // message with multiple unknowns => unknownSet source = "TestAllTypes{single_int32: x.single_int32, single_int64: x.single_int64}"; runTest(); + + // type(unknown) -> unknown + source = "type(x.single_int32)"; + runTest(); + + // type(error) -> error + source = "type(1 / 0 > 2)"; + runTest(); } @Test From 9b9d0d1559787fc7e2f63f609813904b3c857873 Mon Sep 17 00:00:00 2001 From: Justin King Date: Thu, 17 Oct 2024 12:13:53 -0700 Subject: [PATCH 217/486] Use an immutable copy of `DefaultDispatcher` to avoid synchronization PiperOrigin-RevId: 687000721 --- .../src/main/java/dev/cel/runtime/CelRuntimeLegacyImpl.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/runtime/src/main/java/dev/cel/runtime/CelRuntimeLegacyImpl.java b/runtime/src/main/java/dev/cel/runtime/CelRuntimeLegacyImpl.java index f5f96e5ca..81beec7cc 100644 --- a/runtime/src/main/java/dev/cel/runtime/CelRuntimeLegacyImpl.java +++ b/runtime/src/main/java/dev/cel/runtime/CelRuntimeLegacyImpl.java @@ -266,7 +266,9 @@ public CelRuntimeLegacyImpl build() { } return new CelRuntimeLegacyImpl( - new DefaultInterpreter(runtimeTypeProvider, dispatcher, options), options, this); + new DefaultInterpreter(runtimeTypeProvider, dispatcher.immutableCopy(), options), + options, + this); } private static CelDescriptorPool newDescriptorPool( From ec4fa39bc7c6136dc29fdbb1f688a5759e05fa61 Mon Sep 17 00:00:00 2001 From: Jonathan Tatum Date: Fri, 18 Oct 2024 11:11:56 -0700 Subject: [PATCH 218/486] Rollback: Enforce strictness of type function This ensures that: - type(unknown) -> unknown - type(error) -> error PiperOrigin-RevId: 687363881 --- .../java/dev/cel/runtime/CelUnknownSet.java | 2 +- .../dev/cel/runtime/DefaultInterpreter.java | 14 +++------- .../test/resources/unknownResultSet.baseline | 27 ------------------- .../dev/cel/testing/BaseInterpreterTest.java | 8 ------ 4 files changed, 5 insertions(+), 46 deletions(-) diff --git a/runtime/src/main/java/dev/cel/runtime/CelUnknownSet.java b/runtime/src/main/java/dev/cel/runtime/CelUnknownSet.java index d05be8133..e53d8be94 100644 --- a/runtime/src/main/java/dev/cel/runtime/CelUnknownSet.java +++ b/runtime/src/main/java/dev/cel/runtime/CelUnknownSet.java @@ -46,7 +46,7 @@ public static CelUnknownSet create(ImmutableSet attributes) { return create(attributes, ImmutableSet.of()); } - public static CelUnknownSet create(Long... unknownExprIds) { + static CelUnknownSet create(Long... unknownExprIds) { return create(ImmutableSet.copyOf(unknownExprIds)); } diff --git a/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java b/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java index a0dd1f242..dc633e1a9 100644 --- a/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java +++ b/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java @@ -222,14 +222,10 @@ private IntermediateResult evalInternal(ExecutionFrame frame, CelExpr expr) } } - private static boolean isUnknownValue(Object value) { + private boolean isUnknownValue(Object value) { return value instanceof CelUnknownSet || InterpreterUtil.isUnknown(value); } - private static boolean isUnknownOrError(Object value) { - return isUnknownValue(value) || value instanceof Exception; - } - private Object evalConstant( ExecutionFrame unusedFrame, CelExpr unusedExpr, CelConstant constExpr) { switch (constExpr.getKind()) { @@ -597,10 +593,6 @@ private IntermediateResult evalType(ExecutionFrame frame, CelCall callExpr) throws InterpreterException { CelExpr typeExprArg = callExpr.args().get(0); IntermediateResult argResult = evalInternal(frame, typeExprArg); - // Type is a strict function. Early return if the argument is an error or an unknown. - if (isUnknownOrError(argResult.value())) { - return argResult; - } CelType checkedType = ast.getType(typeExprArg.id()) @@ -690,7 +682,9 @@ private IntermediateResult evalBoolean(ExecutionFrame frame, CelExpr expr, boole throws InterpreterException { IntermediateResult value = strict ? evalInternal(frame, expr) : evalNonstrictly(frame, expr); - if (!(value.value() instanceof Boolean) && !isUnknownOrError(value.value())) { + if (!(value.value() instanceof Boolean) + && !isUnknownValue(value.value()) + && !(value.value() instanceof Exception)) { throw new InterpreterException.Builder("expected boolean value, found: %s", value.value()) .setErrorCode(CelErrorCode.INVALID_ARGUMENT) .setLocation(metadata, expr.id()) diff --git a/runtime/src/test/resources/unknownResultSet.baseline b/runtime/src/test/resources/unknownResultSet.baseline index 7cc661627..2b2c61f62 100644 --- a/runtime/src/test/resources/unknownResultSet.baseline +++ b/runtime/src/test/resources/unknownResultSet.baseline @@ -515,30 +515,3 @@ result: unknown { exprs: 3 exprs: 6 } - - -Source: type(x.single_int32) -declare x { - value google.api.expr.test.v1.proto3.TestAllTypes -} -declare f { - function f int.(int) -> bool -} -=====> -bindings: {} -result: unknown { - exprs: 2 -} - - -Source: type(1 / 0 > 2) -declare x { - value google.api.expr.test.v1.proto3.TestAllTypes -} -declare f { - function f int.(int) -> bool -} -=====> -bindings: {} -error: evaluation error: / by zero -error_code: DIVIDE_BY_ZERO diff --git a/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java b/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java index 17c3bb809..68f343a19 100644 --- a/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java +++ b/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java @@ -1298,14 +1298,6 @@ public void unknownResultSet() { // message with multiple unknowns => unknownSet source = "TestAllTypes{single_int32: x.single_int32, single_int64: x.single_int64}"; runTest(); - - // type(unknown) -> unknown - source = "type(x.single_int32)"; - runTest(); - - // type(error) -> error - source = "type(1 / 0 > 2)"; - runTest(); } @Test From 0a9ae34b243a9f9eb18ef65ad7ca271261fdc883 Mon Sep 17 00:00:00 2001 From: Jonathan Tatum Date: Fri, 18 Oct 2024 15:56:20 -0700 Subject: [PATCH 219/486] Update visibility for CelUnknownSet::create PiperOrigin-RevId: 687449942 --- runtime/src/main/java/dev/cel/runtime/CelUnknownSet.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/src/main/java/dev/cel/runtime/CelUnknownSet.java b/runtime/src/main/java/dev/cel/runtime/CelUnknownSet.java index e53d8be94..d05be8133 100644 --- a/runtime/src/main/java/dev/cel/runtime/CelUnknownSet.java +++ b/runtime/src/main/java/dev/cel/runtime/CelUnknownSet.java @@ -46,7 +46,7 @@ public static CelUnknownSet create(ImmutableSet attributes) { return create(attributes, ImmutableSet.of()); } - static CelUnknownSet create(Long... unknownExprIds) { + public static CelUnknownSet create(Long... unknownExprIds) { return create(ImmutableSet.copyOf(unknownExprIds)); } From a32d6e35a85516582bc0192c0ed1da99b87f3d2b Mon Sep 17 00:00:00 2001 From: Ori Dagan Date: Sun, 20 Oct 2024 11:45:42 +0300 Subject: [PATCH 220/486] fixed parsing a macro that has an arg call expression which is receiver style --- parser/src/main/java/dev/cel/parser/Parser.java | 1 + .../java/dev/cel/parser/CelUnparserImplTest.java | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/parser/src/main/java/dev/cel/parser/Parser.java b/parser/src/main/java/dev/cel/parser/Parser.java index 3ec9350ed..61caff017 100644 --- a/parser/src/main/java/dev/cel/parser/Parser.java +++ b/parser/src/main/java/dev/cel/parser/Parser.java @@ -613,6 +613,7 @@ private CelExpr buildMacroCallArgs(CelExpr expr) { // means that the depth check on the AST during parsing will catch recursion overflows // before we get to here. expr.call().args().forEach(arg -> callExpr.addArgs(buildMacroCallArgs(arg))); + expr.call().target().ifPresent(target -> callExpr.setTarget(buildMacroCallArgs(target))); return resultExpr.setCall(callExpr.build()).build(); } return expr; diff --git a/parser/src/test/java/dev/cel/parser/CelUnparserImplTest.java b/parser/src/test/java/dev/cel/parser/CelUnparserImplTest.java index be95fcaef..7f6029cad 100644 --- a/parser/src/test/java/dev/cel/parser/CelUnparserImplTest.java +++ b/parser/src/test/java/dev/cel/parser/CelUnparserImplTest.java @@ -273,4 +273,16 @@ public void unparse_comprehensionWithoutMacroCallTracking_throwsException() thro "Comprehension unparsing requires macro calls to be populated. Ensure the option is" + " enabled."); } + + @Test + public void unparse_macroWithReceiverStyleArg() throws Exception { + CelParser parser = + CelParserImpl.newBuilder() + .setOptions(CelOptions.newBuilder().populateMacroCalls(true).build()) + .setStandardMacros(CelStandardMacro.STANDARD_MACROS) + .build(); + CelAbstractSyntaxTree ast = parser.parse("[\"a\"].all(x, x.trim().lowerAscii().contains(\"b\"))").getAst(); + + assertThat(unparser.unparse(ast)).isEqualTo("[\"a\"].all(x, x.trim().lowerAscii().contains(\"b\"))"); + } } From 167957b59f417697958ab05fd667f58831eb17a5 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Tue, 22 Oct 2024 18:49:21 -0700 Subject: [PATCH 221/486] Rollback: Enforce strictness of type function This ensures that: - type(unknown) -> unknown - type(error) -> error PiperOrigin-RevId: 688765902 --- .../dev/cel/runtime/DefaultInterpreter.java | 14 +++++++--- .../test/resources/unknownResultSet.baseline | 27 +++++++++++++++++++ .../dev/cel/testing/BaseInterpreterTest.java | 8 ++++++ 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java b/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java index dc633e1a9..a0dd1f242 100644 --- a/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java +++ b/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java @@ -222,10 +222,14 @@ private IntermediateResult evalInternal(ExecutionFrame frame, CelExpr expr) } } - private boolean isUnknownValue(Object value) { + private static boolean isUnknownValue(Object value) { return value instanceof CelUnknownSet || InterpreterUtil.isUnknown(value); } + private static boolean isUnknownOrError(Object value) { + return isUnknownValue(value) || value instanceof Exception; + } + private Object evalConstant( ExecutionFrame unusedFrame, CelExpr unusedExpr, CelConstant constExpr) { switch (constExpr.getKind()) { @@ -593,6 +597,10 @@ private IntermediateResult evalType(ExecutionFrame frame, CelCall callExpr) throws InterpreterException { CelExpr typeExprArg = callExpr.args().get(0); IntermediateResult argResult = evalInternal(frame, typeExprArg); + // Type is a strict function. Early return if the argument is an error or an unknown. + if (isUnknownOrError(argResult.value())) { + return argResult; + } CelType checkedType = ast.getType(typeExprArg.id()) @@ -682,9 +690,7 @@ private IntermediateResult evalBoolean(ExecutionFrame frame, CelExpr expr, boole throws InterpreterException { IntermediateResult value = strict ? evalInternal(frame, expr) : evalNonstrictly(frame, expr); - if (!(value.value() instanceof Boolean) - && !isUnknownValue(value.value()) - && !(value.value() instanceof Exception)) { + if (!(value.value() instanceof Boolean) && !isUnknownOrError(value.value())) { throw new InterpreterException.Builder("expected boolean value, found: %s", value.value()) .setErrorCode(CelErrorCode.INVALID_ARGUMENT) .setLocation(metadata, expr.id()) diff --git a/runtime/src/test/resources/unknownResultSet.baseline b/runtime/src/test/resources/unknownResultSet.baseline index 2b2c61f62..7cc661627 100644 --- a/runtime/src/test/resources/unknownResultSet.baseline +++ b/runtime/src/test/resources/unknownResultSet.baseline @@ -515,3 +515,30 @@ result: unknown { exprs: 3 exprs: 6 } + + +Source: type(x.single_int32) +declare x { + value google.api.expr.test.v1.proto3.TestAllTypes +} +declare f { + function f int.(int) -> bool +} +=====> +bindings: {} +result: unknown { + exprs: 2 +} + + +Source: type(1 / 0 > 2) +declare x { + value google.api.expr.test.v1.proto3.TestAllTypes +} +declare f { + function f int.(int) -> bool +} +=====> +bindings: {} +error: evaluation error: / by zero +error_code: DIVIDE_BY_ZERO diff --git a/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java b/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java index 68f343a19..17c3bb809 100644 --- a/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java +++ b/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java @@ -1298,6 +1298,14 @@ public void unknownResultSet() { // message with multiple unknowns => unknownSet source = "TestAllTypes{single_int32: x.single_int32, single_int64: x.single_int64}"; runTest(); + + // type(unknown) -> unknown + source = "type(x.single_int32)"; + runTest(); + + // type(error) -> error + source = "type(1 / 0 > 2)"; + runTest(); } @Test From fccefae7c57bd5895dcbc374c1e70c78a0be8750 Mon Sep 17 00:00:00 2001 From: Sergii Tkachenko Date: Thu, 24 Oct 2024 14:03:14 -0700 Subject: [PATCH 222/486] Fix feature_request.md config blocks It appears that the second config block was left on accident. --- .github/ISSUE_TEMPLATE/feature_request.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 67062e439..59a173b91 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -6,12 +6,6 @@ labels: '' --- ---- -name: Feature request -about: Suggest an idea for this project - ---- - **Feature request checklist** - [ ] There are no issues that match the desired change From 45641a8790acb6ace9044b57695c1a202ecf99e9 Mon Sep 17 00:00:00 2001 From: Tristan Swadell Date: Thu, 24 Oct 2024 15:42:17 -0700 Subject: [PATCH 223/486] Sync with GitHub PiperOrigin-RevId: 689541392 --- .../test/java/dev/cel/conformance/BUILD.bazel | 4 +-- .../dev/cel/conformance/ConformanceTest.java | 27 +++++++------------ 2 files changed, 11 insertions(+), 20 deletions(-) diff --git a/conformance/src/test/java/dev/cel/conformance/BUILD.bazel b/conformance/src/test/java/dev/cel/conformance/BUILD.bazel index 57a83b955..e32d18382 100644 --- a/conformance/src/test/java/dev/cel/conformance/BUILD.bazel +++ b/conformance/src/test/java/dev/cel/conformance/BUILD.bazel @@ -30,10 +30,10 @@ java_library( "//parser:macro", "//parser:parser_builder", "//runtime", + "//third_party/cel/spec/proto/cel/expr/conformance/proto2:test_all_types_java_proto", + "//third_party/cel/spec/proto/cel/expr/conformance/proto3:test_all_types_java_proto", "@cel_spec//proto/cel/expr:expr_java_proto", "@cel_spec//proto/test/v1:simple_java_proto", - "@cel_spec//proto/test/v1/proto2:test_all_types_java_proto", - "@cel_spec//proto/test/v1/proto3:test_all_types_java_proto", "@com_google_googleapis//google/api/expr/v1alpha1:expr_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", diff --git a/conformance/src/test/java/dev/cel/conformance/ConformanceTest.java b/conformance/src/test/java/dev/cel/conformance/ConformanceTest.java index 32c10bf4d..f1d3c1e75 100644 --- a/conformance/src/test/java/dev/cel/conformance/ConformanceTest.java +++ b/conformance/src/test/java/dev/cel/conformance/ConformanceTest.java @@ -19,7 +19,6 @@ import dev.cel.expr.Decl; import com.google.api.expr.test.v1.SimpleProto.SimpleTest; -import com.google.api.expr.test.v1.proto2.TestAllTypesExtensions; import com.google.api.expr.v1alpha1.ExprValue; import com.google.api.expr.v1alpha1.ListValue; import com.google.api.expr.v1alpha1.MapValue; @@ -69,8 +68,7 @@ public final class ConformanceTest extends Statement { private static ExtensionRegistry newDefaultExtensionRegistry() { ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance(); - com.google.api.expr.test.v1.proto2.TestAllTypesExtensions.registerAllExtensions( - extensionRegistry); + dev.cel.expr.conformance.proto2.TestAllTypesExtensions.registerAllExtensions(extensionRegistry); return extensionRegistry; } @@ -79,12 +77,9 @@ private static TypeRegistry newDefaultTypeRegistry() { CelDescriptors allDescriptors = CelDescriptorUtil.getAllDescriptorsFromFileDescriptor( ImmutableList.of( - com.google.api.expr.test.v1.proto2.TestAllTypesProto.TestAllTypes.getDescriptor() - .getFile(), - com.google.api.expr.test.v1.proto3.TestAllTypesProto.TestAllTypes.getDescriptor() - .getFile(), - com.google.api.expr.test.v1.proto2.TestAllTypesExtensions.getDescriptor() - .getFile())); + dev.cel.expr.conformance.proto2.TestAllTypes.getDescriptor().getFile(), + dev.cel.expr.conformance.proto3.TestAllTypes.getDescriptor().getFile(), + dev.cel.expr.conformance.proto2.TestAllTypesExtensions.getDescriptor().getFile())); return TypeRegistry.newBuilder().add(allDescriptors.messageTypeDescriptors()).build(); } @@ -140,7 +135,7 @@ private static CelChecker getChecker(SimpleTest test) throws Exception { .setOptions(OPTIONS) .setContainer(test.getContainer()) .addDeclarations(decls.build()) - .addFileTypes(TestAllTypesExtensions.getDescriptor()) + .addFileTypes(dev.cel.expr.conformance.proto2.TestAllTypesExtensions.getDescriptor()) .addLibraries( CelExtensions.bindings(), CelExtensions.encoders(), @@ -148,10 +143,8 @@ private static CelChecker getChecker(SimpleTest test) throws Exception { CelExtensions.sets(), CelExtensions.strings(), CelOptionalLibrary.INSTANCE) - .addMessageTypes( - com.google.api.expr.test.v1.proto2.TestAllTypesProto.TestAllTypes.getDescriptor()) - .addMessageTypes( - com.google.api.expr.test.v1.proto3.TestAllTypesProto.TestAllTypes.getDescriptor()) + .addMessageTypes(dev.cel.expr.conformance.proto2.TestAllTypes.getDescriptor()) + .addMessageTypes(dev.cel.expr.conformance.proto3.TestAllTypes.getDescriptor()) .build(); } @@ -164,10 +157,8 @@ private static CelChecker getChecker(SimpleTest test) throws Exception { CelExtensions.sets(), CelExtensions.strings(), CelOptionalLibrary.INSTANCE) - .addMessageTypes( - com.google.api.expr.test.v1.proto2.TestAllTypesProto.TestAllTypes.getDescriptor()) - .addMessageTypes( - com.google.api.expr.test.v1.proto3.TestAllTypesProto.TestAllTypes.getDescriptor()) + .addMessageTypes(dev.cel.expr.conformance.proto2.TestAllTypes.getDescriptor()) + .addMessageTypes(dev.cel.expr.conformance.proto3.TestAllTypes.getDescriptor()) .build(); private static ImmutableMap getBindings(SimpleTest test) throws Exception { From f96dd0b6d550b3f11e1eada917155f6ca78a9713 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Fri, 25 Oct 2024 06:01:21 -0700 Subject: [PATCH 224/486] Internal Changes PiperOrigin-RevId: 689760093 --- checker/src/test/java/dev/cel/checker/BUILD.bazel | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/checker/src/test/java/dev/cel/checker/BUILD.bazel b/checker/src/test/java/dev/cel/checker/BUILD.bazel index e3e410429..4bb8544d5 100644 --- a/checker/src/test/java/dev/cel/checker/BUILD.bazel +++ b/checker/src/test/java/dev/cel/checker/BUILD.bazel @@ -11,7 +11,6 @@ java_library( srcs = glob(["*Test.java"]), resources = ["//checker/src/test/resources:baselines"], deps = [ - "@maven//:com_google_protobuf_protobuf_java", # "//java/com/google/testing/testsize:annotations", "//:auto_value", "//checker", @@ -50,6 +49,7 @@ java_library( "@cel_spec//proto/test/v1/proto3:test_all_types_java_proto", "@com_google_googleapis//google/rpc/context:attribute_context_java_proto", "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", ], ) From 3cb263a4f0a501bc39bb9fab1ae89ecde61c3086 Mon Sep 17 00:00:00 2001 From: Tristan Swadell Date: Mon, 11 Nov 2024 16:25:22 -0800 Subject: [PATCH 225/486] Remove the legacy createInterpretable(CheckedExpr) PiperOrigin-RevId: 695519680 --- runtime/src/main/java/dev/cel/runtime/BUILD.bazel | 2 -- .../main/java/dev/cel/runtime/DefaultInterpreter.java | 8 -------- .../src/main/java/dev/cel/runtime/Interpreter.java | 11 ----------- 3 files changed, 21 deletions(-) diff --git a/runtime/src/main/java/dev/cel/runtime/BUILD.bazel b/runtime/src/main/java/dev/cel/runtime/BUILD.bazel index 095f69565..c3fe0074c 100644 --- a/runtime/src/main/java/dev/cel/runtime/BUILD.bazel +++ b/runtime/src/main/java/dev/cel/runtime/BUILD.bazel @@ -45,7 +45,6 @@ java_library( ], deps = [ ":runtime_helper", - "//:auto_value", "//common", "//common:error_codes", "//common:options", @@ -85,7 +84,6 @@ java_library( "//common:error_codes", "//common:features", "//common:options", - "//common:proto_ast", "//common:runtime_exception", "//common/annotations", "//common/ast", diff --git a/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java b/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java index a0dd1f242..36f07c4b5 100644 --- a/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java +++ b/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java @@ -14,7 +14,6 @@ package dev.cel.runtime; -import dev.cel.expr.CheckedExpr; import dev.cel.expr.Value; import com.google.auto.value.AutoValue; import com.google.common.base.Preconditions; @@ -24,7 +23,6 @@ import dev.cel.common.CelAbstractSyntaxTree; import dev.cel.common.CelErrorCode; import dev.cel.common.CelOptions; -import dev.cel.common.CelProtoAbstractSyntaxTree; import dev.cel.common.annotations.Internal; import dev.cel.common.ast.CelConstant; import dev.cel.common.ast.CelExpr; @@ -122,12 +120,6 @@ public DefaultInterpreter( this.celOptions = celOptions; } - @Override - @Deprecated - public Interpretable createInterpretable(CheckedExpr checkedExpr) { - return createInterpretable(CelProtoAbstractSyntaxTree.fromCheckedExpr(checkedExpr).getAst()); - } - @Override public Interpretable createInterpretable(CelAbstractSyntaxTree ast) { return new DefaultInterpretable(typeProvider, dispatcher, ast, celOptions); diff --git a/runtime/src/main/java/dev/cel/runtime/Interpreter.java b/runtime/src/main/java/dev/cel/runtime/Interpreter.java index c6fe08077..5c316da1a 100644 --- a/runtime/src/main/java/dev/cel/runtime/Interpreter.java +++ b/runtime/src/main/java/dev/cel/runtime/Interpreter.java @@ -14,7 +14,6 @@ package dev.cel.runtime; -import dev.cel.expr.CheckedExpr; import javax.annotation.concurrent.ThreadSafe; import dev.cel.common.CelAbstractSyntaxTree; import dev.cel.common.annotations.Internal; @@ -28,16 +27,6 @@ @Internal public interface Interpreter { - /** - * Creates an interpretable for the given expression. - * - *

This method may run pre-processing and partial evaluation of the expression it gets passed. - * - * @deprecated Use {@link #createInterpretable(CelAbstractSyntaxTree)} instead. - */ - @Deprecated - Interpretable createInterpretable(CheckedExpr checkedExpr) throws InterpreterException; - /** * Creates an interpretable for the given expression. * From 8d2f1009b1e7f826ec6646f3eecf1573f3d4b7ea Mon Sep 17 00:00:00 2001 From: Tristan Swadell Date: Thu, 14 Nov 2024 17:07:35 -0800 Subject: [PATCH 226/486] BUILD dependency bundling PiperOrigin-RevId: 696697160 --- conformance/src/test/java/dev/cel/conformance/BUILD.bazel | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conformance/src/test/java/dev/cel/conformance/BUILD.bazel b/conformance/src/test/java/dev/cel/conformance/BUILD.bazel index e32d18382..78350e1a0 100644 --- a/conformance/src/test/java/dev/cel/conformance/BUILD.bazel +++ b/conformance/src/test/java/dev/cel/conformance/BUILD.bazel @@ -30,9 +30,9 @@ java_library( "//parser:macro", "//parser:parser_builder", "//runtime", - "//third_party/cel/spec/proto/cel/expr/conformance/proto2:test_all_types_java_proto", - "//third_party/cel/spec/proto/cel/expr/conformance/proto3:test_all_types_java_proto", "@cel_spec//proto/cel/expr:expr_java_proto", + "@cel_spec//proto/cel/expr/conformance/proto2:test_all_types_java_proto", + "@cel_spec//proto/cel/expr/conformance/proto3:test_all_types_java_proto", "@cel_spec//proto/test/v1:simple_java_proto", "@com_google_googleapis//google/api/expr/v1alpha1:expr_java_proto", "@maven//:com_google_guava_guava", From 7dce5b4ee33856f1401a86e4c58606dcd4486562 Mon Sep 17 00:00:00 2001 From: Tristan Swadell Date: Fri, 15 Nov 2024 11:46:22 -0800 Subject: [PATCH 227/486] Introduce late-bound functions into CEL-Java PiperOrigin-RevId: 696954942 --- .../dev/cel/extensions/CelExtensionsTest.java | 4 +- .../src/main/java/dev/cel/runtime/BUILD.bazel | 8 + .../cel/runtime/CelEvaluationException.java | 4 + .../dev/cel/runtime/CelFunctionOverload.java | 28 +-- .../dev/cel/runtime/CelFunctionResolver.java | 24 +++ .../cel/runtime/CelLateFunctionBindings.java | 70 +++++++ .../dev/cel/runtime/CelResolvedOverload.java | 56 ++++++ .../main/java/dev/cel/runtime/CelRuntime.java | 55 +++++- .../dev/cel/runtime/DefaultDispatcher.java | 177 ++++++++---------- .../dev/cel/runtime/DefaultInterpreter.java | 85 ++++++++- .../main/java/dev/cel/runtime/Dispatcher.java | 20 +- .../dev/cel/runtime/FunctionOverload.java | 47 +++++ .../dev/cel/runtime/FunctionResolver.java | 45 +++++ .../java/dev/cel/runtime/Interpretable.java | 19 ++ .../dev/cel/runtime/InterpreterException.java | 28 ++- .../main/java/dev/cel/runtime/Registrar.java | 27 +-- .../dev/cel/runtime/ResolvedOverload.java | 64 +++++++ .../runtime/UnknownTrackingInterpretable.java | 15 +- .../src/test/java/dev/cel/runtime/BUILD.bazel | 1 + .../runtime/CelLateFunctionBindingsTest.java | 146 +++++++++++++++ .../cel/runtime/CelResolvedOverloadTest.java | 67 +++++++ .../java/dev/cel/runtime/CelRuntimeTest.java | 2 +- .../cel/runtime/DefaultDispatcherTest.java | 60 ++++++ .../resources/lateBoundFunctions.baseline | 7 + .../src/main/java/dev/cel/testing/BUILD.bazel | 1 + .../dev/cel/testing/BaseInterpreterTest.java | 66 ++++++- 26 files changed, 930 insertions(+), 196 deletions(-) create mode 100644 runtime/src/main/java/dev/cel/runtime/CelFunctionResolver.java create mode 100644 runtime/src/main/java/dev/cel/runtime/CelLateFunctionBindings.java create mode 100644 runtime/src/main/java/dev/cel/runtime/CelResolvedOverload.java create mode 100644 runtime/src/main/java/dev/cel/runtime/FunctionOverload.java create mode 100644 runtime/src/main/java/dev/cel/runtime/FunctionResolver.java create mode 100644 runtime/src/main/java/dev/cel/runtime/ResolvedOverload.java create mode 100644 runtime/src/test/java/dev/cel/runtime/CelLateFunctionBindingsTest.java create mode 100644 runtime/src/test/java/dev/cel/runtime/CelResolvedOverloadTest.java create mode 100644 runtime/src/test/java/dev/cel/runtime/DefaultDispatcherTest.java create mode 100644 runtime/src/test/resources/lateBoundFunctions.baseline diff --git a/extensions/src/test/java/dev/cel/extensions/CelExtensionsTest.java b/extensions/src/test/java/dev/cel/extensions/CelExtensionsTest.java index 26c51b1f4..80fe77f98 100644 --- a/extensions/src/test/java/dev/cel/extensions/CelExtensionsTest.java +++ b/extensions/src/test/java/dev/cel/extensions/CelExtensionsTest.java @@ -89,7 +89,9 @@ public void addStringExtensionsForCompilerOnly_throwsEvaluationException() throw assertThat(exception) .hasMessageThat() - .contains("Unknown overload id 'string_substring_int_int' for function 'substring'"); + .contains( + "No matching overload for function 'substring'. Overload candidates:" + + " string_substring_int_int"); } @Test diff --git a/runtime/src/main/java/dev/cel/runtime/BUILD.bazel b/runtime/src/main/java/dev/cel/runtime/BUILD.bazel index c3fe0074c..dd9abfd28 100644 --- a/runtime/src/main/java/dev/cel/runtime/BUILD.bazel +++ b/runtime/src/main/java/dev/cel/runtime/BUILD.bazel @@ -10,10 +10,13 @@ package( BASE_SOURCES = [ "DefaultMetadata.java", + "FunctionResolver.java", + "FunctionOverload.java", "InterpreterException.java", "MessageProvider.java", "Metadata.java", "Registrar.java", + "ResolvedOverload.java", "StandardFunctions.java", "StandardTypeResolver.java", "TypeResolver.java", @@ -45,6 +48,7 @@ java_library( ], deps = [ ":runtime_helper", + "//:auto_value", "//common", "//common:error_codes", "//common:options", @@ -58,6 +62,7 @@ java_library( "//common/types", "//common/types:type_providers", "@cel_spec//proto/cel/expr:expr_java_proto", + "@maven//:com_google_code_findbugs_annotations", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", @@ -132,6 +137,9 @@ java_library( RUNTIME_SOURCES = [ "CelEvaluationException.java", "CelFunctionOverload.java", + "CelFunctionResolver.java", + "CelLateFunctionBindings.java", + "CelResolvedOverload.java", "CelRuntime.java", "CelRuntimeBuilder.java", "CelRuntimeFactory.java", diff --git a/runtime/src/main/java/dev/cel/runtime/CelEvaluationException.java b/runtime/src/main/java/dev/cel/runtime/CelEvaluationException.java index 313077ecf..a4ca1dd65 100644 --- a/runtime/src/main/java/dev/cel/runtime/CelEvaluationException.java +++ b/runtime/src/main/java/dev/cel/runtime/CelEvaluationException.java @@ -31,6 +31,10 @@ public CelEvaluationException(String message, Throwable cause) { super(message, cause); } + public CelEvaluationException(String message, Throwable cause, CelErrorCode errorCode) { + super(message, cause, errorCode); + } + CelEvaluationException(InterpreterException cause) { super(cause.getMessage(), cause.getCause()); } diff --git a/runtime/src/main/java/dev/cel/runtime/CelFunctionOverload.java b/runtime/src/main/java/dev/cel/runtime/CelFunctionOverload.java index 2ea1cb529..a098f7835 100644 --- a/runtime/src/main/java/dev/cel/runtime/CelFunctionOverload.java +++ b/runtime/src/main/java/dev/cel/runtime/CelFunctionOverload.java @@ -1,4 +1,4 @@ -// Copyright 2022 Google LLC +// Copyright 2024 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -19,28 +19,4 @@ /** Interface describing the general signature of all CEL custom function implementations. */ @Immutable @FunctionalInterface -public interface CelFunctionOverload { - - /** Evaluate a set of arguments throwing a {@code CelEvaluationException} on error. */ - Object apply(Object[] args) throws CelEvaluationException; - - /** - * Helper interface for describing unary functions where the type-parameter is used to improve - * compile-time correctness of function bindings. - */ - @Immutable - @FunctionalInterface - interface Unary { - Object apply(T arg) throws CelEvaluationException; - } - - /** - * Helper interface for describing binary functions where the type parameters are used to improve - * compile-time correctness of function bindings. - */ - @Immutable - @FunctionalInterface - interface Binary { - Object apply(T1 arg1, T2 arg2) throws CelEvaluationException; - } -} +public interface CelFunctionOverload extends FunctionOverload {} diff --git a/runtime/src/main/java/dev/cel/runtime/CelFunctionResolver.java b/runtime/src/main/java/dev/cel/runtime/CelFunctionResolver.java new file mode 100644 index 000000000..7571a8803 --- /dev/null +++ b/runtime/src/main/java/dev/cel/runtime/CelFunctionResolver.java @@ -0,0 +1,24 @@ +// Copyright 202 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.runtime; + +import javax.annotation.concurrent.ThreadSafe; + +/** + * Interface to a resolver for CEL functions based on the function name, overload ids, and + * arguments. + */ +@ThreadSafe +public interface CelFunctionResolver extends FunctionResolver {} diff --git a/runtime/src/main/java/dev/cel/runtime/CelLateFunctionBindings.java b/runtime/src/main/java/dev/cel/runtime/CelLateFunctionBindings.java new file mode 100644 index 000000000..0fea43b0d --- /dev/null +++ b/runtime/src/main/java/dev/cel/runtime/CelLateFunctionBindings.java @@ -0,0 +1,70 @@ +// Copyright 2024 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.runtime; + +import static com.google.common.collect.ImmutableMap.toImmutableMap; + +import com.google.common.collect.ImmutableMap; +import com.google.errorprone.annotations.Immutable; +import dev.cel.common.CelException; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +/** + * Collection of {@link CelFunctionBinding} values which are intended to be created once + * per-evaluation, rather than once per-program setup. + */ +@Immutable +public final class CelLateFunctionBindings implements CelFunctionResolver { + + private final ImmutableMap functions; + + private CelLateFunctionBindings(ImmutableMap functions) { + this.functions = functions; + } + + @Override + public Optional findOverload( + String functionName, List overloadIds, Object[] args) throws CelException { + return DefaultDispatcher.findOverload(functionName, overloadIds, functions, args); + } + + public static CelLateFunctionBindings from(CelRuntime.CelFunctionBinding... functions) { + return from(Arrays.asList(functions)); + } + + public static CelLateFunctionBindings from(List functions) { + return new CelLateFunctionBindings( + functions.stream() + .collect( + toImmutableMap( + CelRuntime.CelFunctionBinding::getOverloadId, + CelLateFunctionBindings::createResolvedOverload))); + } + + private static ResolvedOverload createResolvedOverload(CelRuntime.CelFunctionBinding binding) { + return CelResolvedOverload.of( + binding.getOverloadId(), + binding.getArgTypes(), + (args) -> { + try { + return binding.getDefinition().apply(args); + } catch (CelException e) { + throw InterpreterException.wrapOrThrow(e); + } + }); + } +} diff --git a/runtime/src/main/java/dev/cel/runtime/CelResolvedOverload.java b/runtime/src/main/java/dev/cel/runtime/CelResolvedOverload.java new file mode 100644 index 000000000..e23749f15 --- /dev/null +++ b/runtime/src/main/java/dev/cel/runtime/CelResolvedOverload.java @@ -0,0 +1,56 @@ +// Copyright 2024 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.runtime; + +import com.google.auto.value.AutoValue; +import com.google.common.collect.ImmutableList; +import com.google.errorprone.annotations.Immutable; + +/** + * Representation of a function overload which has been resolved to a specific set of argument types + * and a function definition. + */ +@AutoValue +@Immutable +public abstract class CelResolvedOverload implements ResolvedOverload { + + /** The overload id of the function. */ + @Override + public abstract String getOverloadId(); + + /** The types of the function parameters. */ + @Override + public abstract ImmutableList> getParameterTypes(); + + /** The function definition. */ + @Override + public abstract CelFunctionOverload getDefinition(); + + /** + * Creates a new resolved overload from the given overload id, parameter types, and definition. + */ + public static CelResolvedOverload of( + String overloadId, Class[] parameterTypes, CelFunctionOverload definition) { + return of(overloadId, ImmutableList.copyOf(parameterTypes), definition); + } + + /** + * Creates a new resolved overload from the given overload id, parameter types, and definition. + */ + public static CelResolvedOverload of( + String overloadId, ImmutableList> parameterTypes, CelFunctionOverload definition) { + return new AutoValue_CelResolvedOverload(overloadId, parameterTypes, definition); + } +} diff --git a/runtime/src/main/java/dev/cel/runtime/CelRuntime.java b/runtime/src/main/java/dev/cel/runtime/CelRuntime.java index 2b28d015b..854b064fa 100644 --- a/runtime/src/main/java/dev/cel/runtime/CelRuntime.java +++ b/runtime/src/main/java/dev/cel/runtime/CelRuntime.java @@ -25,6 +25,7 @@ import dev.cel.common.CelAbstractSyntaxTree; import dev.cel.common.CelOptions; import java.util.Map; +import java.util.Optional; /** * The CelRuntime creates executable {@code Program} instances from {@code CelAbstractSyntaxTree} @@ -64,6 +65,18 @@ public Object eval(CelVariableResolver resolver) throws CelEvaluationException { return evalInternal((name) -> resolver.find(name).orElse(null)); } + /** + * Evaluate a compiled program with a custom variable {@code resolver} and late-bound functions + * {@code lateBoundFunctionResolver}. + */ + public Object eval(CelVariableResolver resolver, CelFunctionResolver lateBoundFunctionResolver) + throws CelEvaluationException { + return evalInternal( + (name) -> resolver.find(name).orElse(null), + lateBoundFunctionResolver, + CelEvaluationListener.noOpListener()); + } + /** * Trace evaluates a compiled program without any variables and invokes the listener as * evaluation progresses through the AST. @@ -99,6 +112,20 @@ public Object trace(CelVariableResolver resolver, CelEvaluationListener listener return evalInternal((name) -> resolver.find(name).orElse(null), listener); } + /** + * Trace evaluates a compiled program using a custom variable {@code resolver} and late-bound + * functions {@code lateBoundFunctionResolver}. The listener is invoked as evaluation progresses + * through the AST. + */ + public Object trace( + CelVariableResolver resolver, + CelFunctionResolver lateBoundFunctionResolver, + CelEvaluationListener listener) + throws CelEvaluationException { + return evalInternal( + (name) -> resolver.find(name).orElse(null), lateBoundFunctionResolver, listener); + } + /** * Advance evaluation based on the current unknown context. * @@ -109,23 +136,36 @@ public Object trace(CelVariableResolver resolver, CelEvaluationListener listener * UnknownTracking} is disabled, this is equivalent to eval. */ public Object advanceEvaluation(UnknownContext context) throws CelEvaluationException { - return evalInternal(context, CelEvaluationListener.noOpListener()); + return evalInternal(context, Optional.empty(), CelEvaluationListener.noOpListener()); } private Object evalInternal(GlobalResolver resolver) throws CelEvaluationException { - return evalInternal(resolver, CelEvaluationListener.noOpListener()); + return evalInternal( + UnknownContext.create(resolver), Optional.empty(), CelEvaluationListener.noOpListener()); } private Object evalInternal(GlobalResolver resolver, CelEvaluationListener listener) throws CelEvaluationException { - return evalInternal(UnknownContext.create(resolver), listener); + return evalInternal(UnknownContext.create(resolver), Optional.empty(), listener); + } + + private Object evalInternal( + GlobalResolver resolver, + CelFunctionResolver lateBoundFunctionResolver, + CelEvaluationListener listener) + throws CelEvaluationException { + return evalInternal( + UnknownContext.create(resolver), Optional.of(lateBoundFunctionResolver), listener); } /** * Evaluate an expr node with an UnknownContext (an activation annotated with which attributes * are unknown). */ - private Object evalInternal(UnknownContext context, CelEvaluationListener listener) + private Object evalInternal( + UnknownContext context, + Optional lateBoundFunctionResolver, + CelEvaluationListener listener) throws CelEvaluationException { try { Interpretable impl = getInterpretable(); @@ -141,8 +181,12 @@ private Object evalInternal(UnknownContext context, CelEvaluationListener listen .setResolver(context.variableResolver()) .setAttributeResolver(context.createAttributeResolver()) .build(), + lateBoundFunctionResolver, listener); } else { + if (lateBoundFunctionResolver.isPresent()) { + return impl.eval(context.variableResolver(), lateBoundFunctionResolver.get(), listener); + } return impl.eval(context.variableResolver(), listener); } } catch (InterpreterException e) { @@ -177,8 +221,7 @@ private static CelEvaluationException unwrapOrCreateEvaluationException( * *

While the CEL function has a human-readable {@code camelCase} name, overload ids should use * the following convention where all {@code } names should be ASCII lower-cased. For types - * prefer the unparameterized simple name of time, or unqualified package name of any proto-based - * type: + * prefer the unparameterized simple name of time, or unqualified name of any proto-based type: * *